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
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!