总览
双网隔离是一种安全高效的隔离网络桌面云切换方案,TC只需搭配一个网络切换器,通过切换器便能够在物理隔离的网络之间快速切换,达到快速访问另一个网络的桌面云资源,并且物理隔离,提供了高安全性。
原理
监控系统网线拔插事件,当网线被拔插时触发切换流程。切换流程为:找到与当前WI配对的另一个WI地址,并检查到该WI地址是否连通,如果连通则加载该WI地址。
1、Windows下网线拔插监控
NotifyAddrChange // IPV4地址变化
NotifyIpInterfaceChange // IPV6地址变化
GetAdaptersAddresses // 获取详细网卡信息
NotifyAddrChange函数主要的功能是用来通知应用程序IPv4地址的变化。注意这个函数仅仅支持IPv4地址的变化,如果需要得到IPv6地址的变化,请使用NotifyIpInterfaceChange。实战经验:通过NotifyAddrChange侦测网络变化
NotifyAddrChange只是简单的告诉我们系统的IP地址发生了变化,但是具体是怎样变化,我们无法从此函数调用中得到。这个时候,我们可以使用GetAdaptersAddresses这一函数来得到当前最新的IP地址来判断。
根据GetAdaptersAddresses
接口获取一个网络的详细数据,其中可以获取到IP_ADAPTER_ADDRESSES_LH结构,当中的IF_OPER_STATUS可以知晓网卡状态,为1时表示接口已启动,为2时表示接口已关闭。
2、Linux下网线拔插监控
网络设备在系统中注册、注销和关闭、打开等事件都可以通知给相应的内核组件或用户空间应用程序,其中内核组件通过netdev_chain通知链获取消息,而用户空间应用程序则通过注册Netlink RTMGRP_LINK多播群组获取事件消息。
使用netlink协议,循环从内核中读取创建网络设备的信息,判断状态,后获取网线拔插消息。
通过Netlink检测网线插拔
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>
#define BUFLEN 20480
int main(int argc, char *argv[])
{
int fd, retval;
char buf[BUFLEN] = {0};
int len = BUFLEN;
struct sockaddr_nl addr;
struct nlmsghdr *nh;
struct ifinfomsg *ifinfo;
struct rtattr *attr;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTNLGRP_LINK; // 多播群组RTNLGRP_LINK
bind(fd, (struct sockaddr*)&addr, sizeof(addr));
while ((retval = read(fd, buf, BUFLEN)) > 0)
{
for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, retval); nh = NLMSG_NEXT(nh, retval))
{
if (nh->nlmsg_type == NLMSG_DONE)
break;
else if (nh->nlmsg_type == NLMSG_ERROR)
return;
else if (nh->nlmsg_type != RTM_NEWLINK)
continue;
ifinfo = NLMSG_DATA(nh);
printf("%u: %s", ifinfo->ifi_index, (ifinfo->ifi_flags & IFF_LOWER_UP) ? "up" : "down" );
attr = (struct rtattr*)(((char*)nh) + NLMSG_SPACE(sizeof(*ifinfo)));
len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len))
{
if (attr->rta_type == IFLA_IFNAME)
{
printf(" %s", (char*)RTA_DATA(attr));
break;
}
}
printf("\n");
}
}
return 0;
}
3、切换流程
检测到网络状态改变后,发送信号给主消息流程,执行切换流程:找到与当前WI配对的另一个WI地址,并检查到该WI地址是否连通,如果连通则加载该WI地址。
4、检测WI地址是否连通
1、发送ICMP报文探测
ICMP:它是TCP/IP协议簇的一个子协议,用于在IP主机路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。
Windows下使用IcmpCreateFile IcmpSendEcho
两个接口
Linux下,从内核中循环发送和读取ICMP数据包,发送时带一个特定盐值数据,接收时验证。
struct protoent *proto = getprotobyname("ICMP");
sock_fd = socket(PF_INET, SOCK_RAW, proto->p_proto);
setsockopt(sock_fd, SOL_IP, IP_TTL, &ttl_val, sizeof(ttl_val); // 生存时间
2、利用QNetworkAccessManager实现非ping的探测
对每一个需要探测的WI地址,新建一个QNetworkAccessManager实例,并加入一些特定盐值,在QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(onAccessibilityFinished(QNetworkReply*)));
回调中检测盐值,实现WI是否可达的探测。
网友评论