问题是关于如何正确configuration想要使用Tun / Tap模块的Linux主机。
我的目标:
利用现有的路由软件(下面的APP1和APP2),但拦截并修改它发送和接收的所有消息(由调解员完成)。
我的情景:
无法通过套接字“/var/run/MysqLd/MysqLd.sock”连接到本地MysqL服务器
Unix vs BSD vs TCP vs Internet套接字?
在Windows上的Python 3.6中的原始套接字数据包嗅探器
读取Windows套接字上的SIO_KEEPALIVE_VALS字段(保持空闲和间隔时间)
epoll在断开客户端时循环
Ubuntu 10.04 Machine +---------------------------------------------+ | | |APP1 --- tap1 --- Mediator --- tap2 --- APP2 | | | +---------------------------------------------+
tap1和tap2:分别使用IFF_TAP标志和IP 10.0.0.1/24和10.0.0.2/24设置的tap设备。 创build设备的代码如下所示:
#include <stdlib.h> #include <stdio.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <fcntl.h> #include <linux/if.h> #include <linux/if_tun.h> #include <string.h> #include <errno.h> #include <sys/resource.h> void createTun(char *,char *,short); int main(void) { const short FLAGS = IFF_TAP; char *tunName; char *tunIP; // Create tap1 tunName = "tap1 "; tunIP = "10.0.0.1/24 "; createTun(tunName,tunIP,FLAGS); printf("Created %s with IP %sn",tunName,tunIP); // Create tap2 tunName = "tap2 "; tunIP = "10.0.0.2/24 "; createTun(tunName,tunIP); return 0; } void createTun(char *tunName,char *tunIP,short FLAGS) { char *cmd; char *cloneDev = "/dev/net/tun"; char *cmdIPLinkUpTemplate = "ip link set %s up"; char *cmdIPAddrAddTemplate = "ip addr add %s dev %s"; int cmdIPLinkUpRawLength = strlen(cmdIPLinkUpTemplate) - 2; int cmdIPAddrAddRawLength = strlen(cmdIPAddrAddTemplate) - 4; FILE *fp; int fd,err,owner,group; struct ifreq ifr; owner = geteuid(); group = getegid(); // open the clone device if((fd = open(cloneDev,O_RDWR)) < 0) { perror("OPEN CLONEDEV Failed."); exit(EXIT_FAILURE); } memset(&ifr,sizeof(struct ifreq)); ifr.ifr_flags = FLAGS; strncpy(ifr.ifr_name,strlen(tunName)); // create the device if(ioctl(fd,TUNSETIFF,(void *) &ifr) < 0) { perror("IOCTL SETIFF denied."); close(fd); exit(EXIT_FAILURE); } // set dev owner if(owner != -1) { if(ioctl(fd,TUNSetoWNER,owner) < 0) { perror("IOCTL SetoWNER denied."); close(fd); exit(EXIT_FAILURE); } } // set dev group if(group != -1) { if(ioctl(fd,TUNSETGROUP,group) < 0) { perror("IOCTL SETGROUP denied."); close(fd); exit(EXIT_FAILURE); } } // set dev persistent if(ioctl(fd,TUNSETPERSIST,1) < 0) { perror("IOCTL SETPERSIST denied."); close(fd); exit(EXIT_FAILURE); } // Set dev up cmd = malloc(cmdIPLinkUpRawLength + strlen(tunName) + 1); sprintf(cmd,cmdIPLinkUpTemplate,ifr.ifr_name); fp = popen(cmd,"r"); if(fp == NULL) { perror("POPEN Failed."); close(fd); free(cmd); exit(EXIT_FAILURE); } pclose(fp); free(cmd); // Assign IP cmd = malloc(cmdIPAddrAddRawLength + strlen(tunIP) + strlen(tunName) + 1); sprintf(cmd,cmdIPAddrAddTemplate,tunName); fp = popen(cmd,"r"); if(fp == NULL) { perror("POPEN Failed."); close(fd); free(cmd); exit(EXIT_FAILURE); } pclose(fp); free(cmd); return; }
介体:简单地在tap1和tap2之间中继数据的小型自写代码。 基本结构如下:
#include <unistd.h> #include <stdio.h> #include <sys/socket.h> #include <netinet/ip.h> #include <sys/ioctl.h> #include <sys/resource.h> #include <sys/epoll.h> #include <errno.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <linux/if.h> #include <linux/if_tun.h> int main(int argc,char *argv[]) { const int NOF_FD = 2; const char *TUN1 = "tap1"; const char *TUN2 = "tap2"; const char *CLONEDEV = "/dev/net/tun"; int fd_tun1,fd_tun2,fd_epoll; struct ifreq ifr_tun1,ifr_tun2; struct epoll_event ev; const int MAX_EVENTS = 1; int ready,s,t; const int MAX_BUF = 2000; char buf[MAX_BUF]; struct sockaddr_in to; const short FLAGS = IFF_TAP; // Open tap1 if((fd_tun1 = open(CLONEDEV,O_RDWR)) < 0) { perror("OPEN CLONEDEV for tun1 Failed"); exit(EXIT_FAILURE); } memset(&ifr_tun1,sizeof(struct ifreq)); ifr_tun1.ifr_flags = FLAGS; strcpy(ifr_tun1.ifr_name,TUN1); if(ioctl(fd_tun1,(void *) &ifr_tun1) < 0) { perror("IOCTL SETIFF for tap1 Failed"); close(fd_tun1); exit(EXIT_FAILURE); } // Open tap2 if((fd_tun2 = open(CLONEDEV,O_RDWR)) < 0) { perror("OPEN CLONEDEV for tap2 Failed"); exit(EXIT_FAILURE); } memset(&ifr_tun2,sizeof(struct ifreq)); ifr_tun2.ifr_flags = FLAGS; strcpy(ifr_tun2.ifr_name,TUN2); if(ioctl(fd_tun2,(void *) &ifr_tun2) < 0) { perror("IOCTL SETIFF for tun2 Failed"); close(fd_tun1); close(fd_tun2); exit(EXIT_FAILURE); } // Prepare EPOLL if((fd_epoll = epoll_create(NOF_FD)) < 0) { perror("EPOLL CREATE Failed"); close(fd_tun1); close(fd_tun2); exit(EXIT_FAILURE); } memset(&ev,sizeof(ev)); ev.events = EPOLLIN; ev.data.fd = fd_tun1; if(epoll_ctl(fd_epoll,EPOLL_CTL_ADD,fd_tun1,&ev) < 0) { perror("EPOLL CTL ADD fd_tun1 Failed"); close(fd_tun1); close(fd_tun2); close(fd_epoll); exit(EXIT_FAILURE); } memset(&ev,sizeof(ev)); ev.events = EPOLLIN; ev.data.fd = fd_tun2; if(epoll_ctl(fd_epoll,&ev) < 0) { perror("EPOLL CTL ADD fd_tun2 Failed"); close(fd_tun1); close(fd_tun2); close(fd_epoll); exit(EXIT_FAILURE); } // Do relay while(1) { if((ready = epoll_wait(fd_epoll,&ev,MAX_EVENTS,-1)) < 0) { if(errno == EINTR) continue; else { perror("EPOLL WAIT Failed"); close(fd_tun1); close(fd_tun2); close(fd_epoll); exit(EXIT_FAILURE); } } //printf("EPOLL WAIT SIGNALedn"); if(ev.events & EPOLLIN) { if((s = read(ev.data.fd,buf,MAX_BUF)) < 0) { perror("READ Failed"); close(fd_tun1); close(fd_tun2); close(fd_epoll); exit(EXIT_FAILURE); } printf("Read from %s. Bytes: %dnData:n",(ev.data.fd == fd_tun1 ? "tun1" : "tun2"),s); int k; for(k = 0; k < s; k++) { printf("%c",buf[k]); } printf("n"); t = (ev.data.fd == fd_tun1) ? fd_tun2 : fd_tun1; if((s = write(t,s)) < 0) { perror("WRITE Failed"); close(fd_tun1); close(fd_tun2); close(fd_epoll); exit(EXIT_FAILURE); } printf("Written to %s. Bytes: %dn",(t == fd_tun1 ? "tun1" : "tun2"),s); if(epoll_ctl(fd_epoll,EPOLL_CTL_DEL,ev.data.fd,NULL) < 0) { perror("EPOLL CTL DEL Failed"); close(fd_tun1); close(fd_tun2); close(fd_epoll); exit(EXIT_FAILURE); } if(epoll_ctl(fd_epoll,&ev) < 0) { perror("EPOLL CTL ADD Failed"); close(fd_tun1); close(fd_tun2); close(fd_epoll); exit(EXIT_FAILURE); } } printf("nn"); } }
APP1和APP2:OSPF路由守护进程分别通过tap1和tap2进行通信。 守护进程的一大部分表明,基本上涉及以下系统调用:
socket(PF_INET,SOCK_RAW,0X59 /*IPPROTO_??? */) = 8 // opening a socket for OSPF and tap1 fcntl64(8,F_SETFL,0_RDONLY | 0_NONBLOCK) = 0 setsockopt(8,SOL_IP,IP_TOS,[192],4) = 0 setsockopt(8,SOL_SOCKET,SO_PRIORITY,[7],IP_PKTINFO,[1],IP_MTU_disCOVER,[0],IP_MULTICAST_LOOP,IP_MULTICAST_TTL,IP_MUTLICAST_IF," n 1223 ",12) = 0 setsockopt(8,SO_BINDTODEVICE,"tap1 315375307250352tt8207t10 ",32) = 0 setsockopt(8,IP_ADD_MEMBERSHIP,"340 5n 1223 ",12) = 0 // Then it gets in a cycle like: select(9,[3,7,8],[],NULL,{1,0}) = 0 (Timeout) clock_gettime(CLOCK_MONOTONIC,{120893,360452769}) = 0 time(NULL) clock_gettime(CLOCK_MONOTONIC,360504525}) = 0 select(9,{120894,363022746}) = 0 time(NULL) ...
我的用法:
将wireshark连接到tap1。 (没有看到stream量)。
启动APP1。 (wireshark使用源10.0.0.1(tap1)查看IGMP和OSPF消息)
启动APP2。 (因为Mediator还没有运行,wireshark仍然只能看到带有源10.0.0.1(tap1)的IGMP和OSPF消息)
启动调解员。 (wireshark现在可以看到具有tap1和tap2源的IGMP和OSPF消息)。
我的问题:
即使连接到tap1的wireshark看到来自tap1和tap2的消息,APP2也不会收到APP1发送的消息,APP2也不会收到来自APP1的消息。 在上面显示的strace抽取中,select()调用永远不会返回文件描述符8,这实际上就是连接到tap1的套接字。
我的问题:
为什么APP1没有收到APP2发送的消息,即使这些消息是由APP2发送的,由中介转发,并通过连接到tap1的wireshark看到?
我必须在Linux主机上添加任何types/种类的附加路由吗?
我是否在设置tun / tap设备时犯了错误?
我的介体代码不能正常工作吗?
PACKET_MMAP数据偏移
为什么我的Perl TCP服务器脚本挂着很多的TCP连接?
套接字asynchronous操作是否会同步完成?
我还没有尝试过你的代码(有点奇怪,你可以从用户空间打开TAP设备两次,而不是使用multiqueue标志 ,但我们假设这是正确的),但是在处理TAP设备的方式上有一个概念错误。
TUN / TAP本质上只是一个管道,管道的一端在内核(tapX接口),另一端在某些用户空间应用程序中。 不管这个应用程序写入管道是否到达内核接口,就像传入的流量一样(你可以用wireshark看到它)。 无论内核发送到哪个管道(传出到tapX)都会进入应用程序(您可以在应用程序中读取的数据)。
你的代码当前正在做的是打开同一管道的另一个用户空间部分,而这不是你想要的。 你想在管道的另一端获得交通。 从技术上讲,你现在正在做的事情可以通过一个简单的桥接接口来完成,两个水龙头都被添加为端口。 当然,如果你不想只是桥接,而是以某种方式修改流量,事情会变得复杂一些。
解决这个问题的一种方法是添加另一对TAP接口。 您桥接(如在内核桥梁中)您的tap1和tap3,tap2和tap4,现在您在“mediator”中打开tap3和tap4,在它们之间打开代理帧。 这是非常低效的,但可能是解决您的问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。