栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

TUN/TAP 学习总结(二) —— Linux TUN demo

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

TUN/TAP 学习总结(二) —— Linux TUN demo

该demo 创建了一个TUN 设备,添加一条静态路由指定TUN设备,demo 程序从TUN读取报文,简单处理ICMP报文,然后送回协议栈,从而使ping命令成功执行。

运行环境

# uname -a
Linux localhost.localdomain 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# cat /etc/redhat-release 
CentOS Linux release 7.4.1708 (Core) 

demo 代码

#include 
#include 
#include 
#include 
#include 

#include 
#include 

#include 
#include 

int tun_open(char *dev, int flags)
{
    struct ifreq ifr;
    int fd, err;

    if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
    {
        printf("open /dev/net/tun error %mn");
        return fd;
    }

    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags |= flags;

//    可以指定tun设备名,页可以让系统自动生成
//    if (strlen(dev) > 0)
//        strncpy(ifr.ifr_name, dev, IFNAMSIZ);

    if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
        close(fd);
        printf("set tun error %mn");
        return err;
    }
    strcpy(dev, ifr.ifr_name);


//  将 tun设备 up
    int ctl_fd;
    struct ifreq netifr={0};
    if ((ctl_fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)
    {
        netifr.ifr_flags |= IFF_UP | IFF_RUNNING;
        strncpy(netifr.ifr_name, ifr.ifr_name, IFNAMSIZ);
        if(ioctl(ctl_fd, SIOCSIFFLAGS, &netifr))
        {
            printf("Failed to set socket flags:%mn");
        }
        else 
        {
            printf("%s upn",ifr.ifr_name);
        }
        close(ctl_fd);
    }
    else
    {
        printf("open socket error %s", ifr.ifr_name);
    }

    return fd;
}


int main(int argc, char *argv[])
{
    int tun, ret;
    char tun_name[IFNAMSIZ];
    unsigned char buf[4096];

     tun_name[0] = '';

//  IFF_TUN: 创建一个tun设备
//  IFF_TAP: 创建一个tap设备
//  IFF_NO_PI: 不包含包信息,默认每个数据包当传到用户空间时,都将包含一个附加的包头来保存包信息
     tun = tun_open(tun_name, IFF_TUN | IFF_NO_PI);
    if (tun < 0) {
        perror("tun_create");
        return 1;
    }
    printf("TUN name is %sn", tun_name);

    char cmd[1024]={0};

//  设置tun 的IP和掩码
    snprintf(cmd,sizeof(cmd),"ifconfig %s 192.168.1.201/24",tun_name);
    printf("%sn",cmd);
    system(cmd);

//  添加一条静态路由,将10.10.10.0/24 网段报文的出口设置为 tun
    snprintf(cmd,sizeof(cmd),"route add -net 10.10.10.0 netmask 255.255.255.0 %s",tun_name);
    printf("%sn",cmd);
    system(cmd);


    while (1)
    {
        unsigned char ip[4];

        ret = read(tun, buf, sizeof(buf));
        if (ret < 0)
        {
            printf("read tun error %mn");
            break;
        }
        // 未做报文解析,认为收到的都是ICMP 包,进行简单回复
        memcpy(ip, &buf[12], 4);
        memcpy(&buf[12], &buf[16], 4);
        memcpy(&buf[16], ip, 4);
         buf[20] = 0;
        *((unsigned short*)&buf[22]) += 8;
        printf("read %d bytesn", ret);
         ret = write(tun, buf, ret);
        printf("write %d bytesn", ret);
    }

    return 0;
}

创tun时flag 必须选择IFF_TUN和IFF_TAP其中的一个,未设置IFF_NO_PI时所附加的包信息头如下:

struct tun_pi {
    unsigned short flags;
    unsigned short proto;
};

demo 运行前

demo 运行后 网络设备中增加了一个tun0,route 中增加了两条

ping 任意10.10.10.0 网段的IP 都可以ping通

wireshark 抓包可以看到,报文没有以太网的mac地址和类型,直接从IP层开始

参考文章
http://blog.chinaunix.net/uid-317451-id-92474.html

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/360640.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号