C(Linux)中的TUNTAP接口:无法使用sendto()捕获TUNTAP上发送的UD
我试图在C中编写一个隧道程序,它将从TUNTAP接口获取UDP数据包并将它们发送到串行接口.
我所做的是从克隆设备/ dev / net / tun分配接口,打开它并给它一个ip地址: int tun_setup(char *dev,int flags) { struct sockaddr_in my_addr; struct ifreq ifr; int fd,err; string clonedev = "/dev/net/tun"; // Open clone device file descriptor if( (fd = open(clonedev.c_str(),O_RDWR)) < 0 ) { perror("Opening /dev/net/tun"); return fd; } // Initialise interface parameters structure memset(&ifr,sizeof(ifr)); // Set up flags ifr.ifr_flags = flags; // Set up interface name if (*dev) { strncpy(ifr.ifr_name,dev,IFNAMSIZ); } // Put interface in TUN mode if( (err = ioctl(fd,TUNSETIFF,(void *)&ifr)) < 0 ) { perror("ioctl(TUNSETIFF)"); close(fd); return err; } strcpy(dev,ifr.ifr_name); // Create a socket if ( (s = socket(AF_INET,SOCK_DGRAM,0)) < 0) { perror("socket"); exit(1); } // Get interface flags if (ioctl(s,SIOCGIFFLAGS,&ifr) < 0) { perror("cannot get interface flags"); exit(1); } // Turn on interface ifr.ifr_flags |= IFF_UP; if (ioctl(s,SIOCSIFFLAGS,&ifr) < 0) { fprintf(stderr,"ifup: failed "); perror(ifr.ifr_name); exit(1); } // Set interface address bzero((char *) &my_addr,sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_addr.s_addr = htonl(inet_network("192.168.2.1")); memcpy(&ifr.ifr_addr,&my_addr,sizeof(struct sockaddr)); if (ioctl(s,SIOCSIFADDR,"Cannot set IP address. "); perror(ifr.ifr_name); exit(1); } // Return interface file descriptor return fd; } 然后我创建一个线程,它将对创建的接口的文件描述符进行poll(),并在事件发生时读取()其他一些东西. void* tun_readThreadProc (void* param) { struct pollfd fds[1]; int nread; unsigned char buffer[BUFFERSIZE]; fds[0].fd = tun_fd; fds[0].events = POLLIN; printf("%s : Entered. tun_fd = %d n",__FUNCTION__,tun_fd); for(;;) { printf("%s : Entered loopn",__FUNCTION__); if((poll(fds,1,-1)) == -1) { perror("poll"); exit(1); } printf("%s : Poll sensed somethingn",__FUNCTION__); if((nread = read(tun_fd,buffer,BUFFERSIZE)) < 0) { perror("read"); close(tun_fd); exit(1); } printf("%s : Read something : %d bytesn",nread); } return 0; } 在程序的另一部分,我将UDP套接字绑定到此TUNTAP接口的IP地址. void socketInit( void ) { int on = 1; struct sockaddr_in my_addr; unsigned short DefaultPort = 47808; // Create a socket if ( (s1 = socket(AF_INET,0)) < 0) { perror("socket"); exit(1); } // Bind to it bzero((char *) &my_addr,sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_addr.s_addr = htonl(inet_network("192.168.2.1")); my_addr.sin_port = htons(DefaultPort); if ( (bind(s,(struct sockaddr *) &my_addr,sizeof(my_addr)) < 0) ) { perror("bind"); } // Allow it to broadcast if (setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char *)&on,sizeof(on)) < 0) { perror("setsockopt"); } } 在另一个函数中,我使用sendto()来发送带有此套接字的数据包.我应该使用poll()read()线程捕获这些数据包,然后在串行端口上发送它们,但poll()从不捕获TUNTAP接口上的事件. 我可以使用ping -I tun0 [some destination](tun0 = TUNTAP接口的名称)来ping通此接口 但是如果我使用ping -I 192.168.2.1 [某个目的地](192.168.2.1 = TUNTAP接口地址),它将通过默认接口(eth0,物理网卡). 我能够通过Wireshark验证这一点. 这很可能是ip路由配置问题…… 如果有人能帮助我,我会很高兴. 解决方法
你是如何设置tun tap接口的IP地址的?使用“ip addr add”命令?你有没有检查/配置了tun tap,即“ip link set<< tun tap interface name>> up”?最后你确定你的UDP套接字sendto代码在满足前面说的两个条件之后运行,即它有正确的ip地址和tun tap接口.
更新 我认为你的概念错了,或者我不太了解你. 1)将默认路由设置为tun tap IP地址.这样,所有数据包都将由用户空间程序获取. 所以现在在用户空间程序中,您将获得具有IP和UDP标头的整个数据包.现在整个数据包将是您要通过串行接口传输的消息.因此,当我们使用UDP或TCP(无论您喜欢哪个)通过串行接口发送它时,我们会再次使用一个UDP和IP标头再封装整个数据包. 2)您还需要添加带有串行接口地址的主机规则.以这种方式,用于串行接口的上述封装分组被发送到串行接口,并且由于默认规则它们不会再次返回到TUN TAP设备. 给路径-n并检查路由是否正确.确保您没有其他不需要的路线.如果是,请删除它们. 注意:您还可以从数据包中仅提取有效负载,并使用RAW套接字创建自定义UDP标头,目标作为串行接口的IP地址,并使用TUN TAP设备进行写入.此数据包将被视为属于串行接口的内核路由实例,并将由于主机规则而转发到此处.如果您要使用此案例,则需要创建自定义IP和UDP标头以及CRC计算. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |