linux下创建tuntap网络设备
时间:2016-05-12 15:52:29
收藏:0
阅读:2330
目标:在linux下建立bridge虚拟网桥、eth虚拟网卡、tuntap接口设备。通过ping来传递报文,通过tuntap使用户应用程序来收发报文。
环境:测试环境为VMware、Ubuntu14。
1.准备工作。
安装brctl、tunctl:
输入brctl和tunctl指令会出现相应指示,输入相应命令即可。我由于Ubuntu版本较低,在apt-get update时报错,出现同样错误可参考下面链接解决。
http://webres.wang/404-not-found-error-apt-get-update-ubuntu/?utm_source=tuicool&utm_medium=referral
设置IP:
我采用的方法是由主机来ping通VMware的虚拟网卡,需要设置相应的模式。在VMware中设置为HOST-ONLY模式,并在主机中设置vmnet1的IP为192.168.0.2,子网掩码为255.255.255.0。之后我们会在linux中设置bridge的IP为192.168.0.10作为虚拟机的IP地址。
2.编写tuntap代码。
此处创建tap设备,而不是tun设备。通过read和write读写tap,并将得到的报文打印出来。
#include <linux/if_tun.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/if.h> #include <error.h> #include <string.h> //memset #include <arpa/inet.h> //ntohs int tap_create(char *dev, int flags); int main(int argc, char *argv[]) { int tap,ret,i,ret_all=0,time=0,pkts=0; char *tap_name = NULL; unsigned char buf[1024]; if (argc < 2) { printf("Please input tap's name\n"); return -1; } if (argc == 2) { tap_name = argv[1]; } tap = tap_create(tap_name, IFF_TAP | IFF_NO_PI); if (tap < 0) { perror("tap_create"); return 1; } printf("TAP name is %s\n", tap_name); while (1) { ret = read(tap, buf, sizeof(buf)); if (ret < 0) { printf("delay 10 secs\n"); sleep(10); continue; } pkts++; ret_all+=ret; printf("read all %d bytes %d pkts\n", ret_all, pkts); for(i=0;i<ret;i++) { if(i%16==0 && i!=0) printf("\n"); printf("%02x ",buf[i]); } printf("\n"); ret = write(tap, buf, ret); printf("write %d bytes\n", ret); for(i=0;i<ret;i++) { if(i%16==0 && i!=0) printf("\n"); printf("%02x ",buf[i]); } printf("\n"); } return 0; } int tap_create(char *dev, int flags) { struct ifreq ifr; int fd, err; if ((fd = open("/dev/net/tun", O_RDWR|O_NONBLOCK)) < 0) return fd; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags |= flags; if (*dev != '\0') strncpy(ifr.ifr_name, dev, IFNAMSIZ); if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) { close(fd); return err; } strcpy(dev, ifr.ifr_name); return fd; }
3.搭建网络
我们搭建的网络为虚拟网桥br0,连接eth0和tap100。在shell中输入以下代码建立br0和eth0:
brctl addbr br0 brctl addif br0 eth0 ifconfig br0 192.168.0.10 netmask 255.255.255.0 up
然后在另一个shell终端执行我们写的tap.c文件,代码如下:
gcc tap.c -o tao sudo ./tap tap100
程序执行,在第一个shell中再写入代码:
sudo ip link set dev tap100 up //该代码使tap设备UP,我在测试中发现如果不加tap设备会收不到数据 sudo brctl addif br0 tap100
然后在主机中启动cmd,通过代码:
ping 192.168.0.11 -t
4.测试结果
5.另
在后来测试中需要设定tap设备的MAC地址,后来采用了如下代码:
//用例:tap_setMAC("tap100","08:00:11:22:33:44") signed char tap_setMAC(const unsigned char *interface_name, const unsigned char *str_macaddr) { int ret; int sock_fd; struct ifreq ifr; unsigned int mac2bit[6]; if(interface_name == NULL || str_macaddr == NULL) { return -1; } //提取mac格式 sscanf((char *)str_macaddr, "%02X:%02X:%02X:%02X:%02X:%02X", (unsigned int *)&mac2bit[0], (unsigned int *)&mac2bit[1], (unsigned int *)&mac2bit[2], (unsigned int *)&mac2bit[3], (unsigned int *)&mac2bit[4], (unsigned int *)&mac2bit[5]); sock_fd = socket(PF_INET, SOCK_DGRAM, 0); if (sock_fd < 0) { return -2; } sprintf(ifr.ifr_ifrn.ifrn_name, "%s", interface_name); ifr.ifr_ifru.ifru_hwaddr.sa_family = 1; ifr.ifr_ifru.ifru_hwaddr.sa_data[0] = mac2bit[0]; ifr.ifr_ifru.ifru_hwaddr.sa_data[1] = mac2bit[1]; ifr.ifr_ifru.ifru_hwaddr.sa_data[2] = mac2bit[2]; ifr.ifr_ifru.ifru_hwaddr.sa_data[3] = mac2bit[3]; ifr.ifr_ifru.ifru_hwaddr.sa_data[4] = mac2bit[4]; ifr.ifr_ifru.ifru_hwaddr.sa_data[5] = mac2bit[5]; ret = ioctl(sock_fd, SIOCSIFHWADDR, &ifr); if (ret != 0) { return -4; } close( sock_fd ); return 0; }
评论(0)