其实关于这两种设备的编程,基本上属于八股文,大家一般都这么干。

启动设备之前

有的linux 并没有将tun 模块编译到内核之中,所以,我们要做的第一件事情就是检查我们的系统是否支持 TUN/TAP 。具体如何检查和解决,请查看这里http://blog.csdn.net/lishuhuakai/article/details/70305543,这篇文章就不再赘述。

光有tun 模块还不够,我们还要创建上篇文章中所提到的文件,运行命令:

% sudo mknod /dev/net/tun c 10 200 # c表示为字符设备,10和200分别是主设备号和次设备号

这样,你到 /dev/net/ 目录下就可以看到一个名称为 tun 的文件了。当然这里的 tun 可以改成任意的你喜欢的名称。

启动设备

对于TUN设备,我们一般这样来初始化:

int
tun_alloc(char dev[IFNAMSIZ]) // dev数组用于存储设备的名称
{
struct ifreq ifr;
int fd, err; if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { // 打开文件
perror("open");
return -1;
} bzero(&ifr, sizeof(ifr)); /* Flags : IFF_TUN - TUN设备
* IFF_TAP - TAP设备
* IFF_NO_PI - 不需要提供包的信息
*/ ifr.ifr_flags = IFF_TUN | IFF_NO_PI; // tun设备不包含以太网头部,而tap包含,仅此而已 if (*dev) {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
} if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { // 打开设备
perror("ioctl TUNSETIFF");
close(fd);
return err;
}
// 一旦设备开启成功,系统会给设备分配一个名称对于tun设备,一般为tunX,X为从0开始的编号,对于tap设备
// 一般为tapX,X为从0开始的编号
strcpy(dev, ifr.ifr_name); // 拷贝设备的名称至dev中
return fd;
}

如果我们想启动一个TAP 设备的话,很简单,将上面的ifr.ifr_flags = IFF_TUN | IFF_NO_PI;改为ifr.ifr_flags = IFF_TAP | IFF_NO_PI;即可,那么我们就启动了一个 TAP 设备。

设定网络地址

上面的代码打开了文件,并且返回了文件的描述符,但是还不够,对于一张网卡来说,我们还要给其配置网络地址,有时候甚至是路由信息,网卡才能够正常地工作。

一旦虚拟的 TUN/TAP 设备启动成功,我们便可以通过命令来给其设定地址。

我来举个例子,以一个 TAP 设备为例:

% sudo ip link set dev tap0 up  # 启动tap0网卡,虽然网卡已经启动,但是此时使用ipconfig命令并不能看到tap0这个设备,因为我们还没有给其配置ip地址

% sudo ip address add dev tap0 10.0.1.5/24 # 给tap0设置ip地址

% ifconfig  # 此时在ifconfig命令下已经可以看到tap0设备了
tap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.1.5 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::1872:80ff:fe20:46e2 prefixlen 64 scopeid 0x20<link>
ether 1a:72:80:20:46:e2 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 % ip route show # 显示所有的路由信息
default via 192.168.140.2 dev ens33 proto static metric 100
10.0.0.0/24 dev ens39 proto kernel scope link src 10.0.0.130 metric 100
10.0.1.0/24 dev tap0 proto kernel scope link src 10.0.1.5 # 给网卡设定ip后,系统自动添加了路由
192.168.140.0/24 dev ens33 proto kernel scope link src 192.168.140.133 metric 100

通过手动敲命令的方式来配置 tap0 设备,略显麻烦,其实我们可以直接在程序中调用 system 函数:

int
run_cmd(char *cmd, ...)
{
va_list ap;
char buf[CMDBUFLEN];
va_start(ap, cmd);
vsnprintf(buf, CMDBUFLEN, cmd, ap);
va_end(ap);
if (debug) { // DEBUG模式下输出信息
printf("EXEC: %s\n", buf);
}
return system(buf);
}

将上面的命令直接传递给 run_cmd 函数即可.

当然,如果你不喜欢这种方式,我们自然还可以有其他的方法,比如说使用下面的函数:

int
set_stack_attribute(char *dev)
{
struct ifreq ifr;
struct sockaddr_in addr;
int sockfd, err = -1; bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
inet_pton(AF_INET, tapaddr, &addr.sin_addr); bzero(&ifr, sizeof(ifr));
strcpy(ifr.ifr_name, dev);
bcopy(&addr, &ifr.ifr_addr, sizeof(addr));
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return -1;
} // ifconfig tap0 10.0.1.5 #设定ip地址
if ((err = ioctl(sockfd, SIOCSIFADDR, (void *)&ifr)) < 0) {
perror("ioctl SIOSIFADDR");
goto done;
} /* 获得接口的标志 */
if ((err = ioctl(sockfd, SIOCGIFFLAGS, (void *)&ifr)) < 0) {
perror("ioctl SIOCGIFADDR");
goto done;
} /* 设置接口的标志 */
ifr.ifr_flags |= IFF_UP;
// ifup tap0 #启动设备
if ((err = ioctl(sockfd, SIOCSIFFLAGS, (void *)&ifr)) < 0) {
perror("ioctl SIOCSIFFLAGS");
goto done;
} inet_pton(AF_INET, "255.255.255.0", &addr.sin_addr);
bcopy(&addr, &ifr.ifr_netmask, sizeof(addr));
// ifconfig tap0 10.0.1.5/24 #设定子网掩码
if ((err = ioctl(sockfd, SIOCSIFNETMASK, (void *) &ifr)) < 0) {
perror("ioctl SIOCSIFNETMASK");
goto done;
} done:
close(sockfd);
return err;
}

上面的函数主要干的事情和上面的命令大致相同。

收发数据

收发数据非常简单,每次读取返回的文件描述符即可接收数据,没有数据到来时,会一直阻塞在哪里,当然,你也可以玩一下非阻塞 IO,然后想要发送数据的话,只需要将数据写入到该文件描述符对应的文件中即可。

 

作者:Yihulee
链接:https://www.jianshu.com/p/ab91f7cd98cd
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

TUN/TAP编程实现的更多相关文章

  1. Linux下的TUN/TAP编程

    linux下实现虚拟网卡我们在使用VMWARE的虚拟化软件时经常会发现它们能都能虚拟出一个网卡,貌似很神奇的技术,其实在Linux下很简单,有两种虚拟设 备,TUN时点对点的设备,tap表示以太网设备 ...

  2. [转]Linux虚拟网络设备之tun/tap

    转, 原文:https://segmentfault.com/a/1190000009249039 -------------------------------------------------- ...

  3. Tun/Tap接口使用指导

    Tun/Tap接口指导 目录 Tun/Tap接口指导 概述 工作机制 创建接口 举例 简单的程序 隧道 拓展 参考 概述 对tun接口的了解需求主要来自于openshift的网络,在openshift ...

  4. Linux中的TUN/TAP设备

    今天才发现这家伙...怎么讲...深以为耻.晚上的任务是加深对它的了解,就这么定了. 1. General questions.1.1 What is the TUN ?  The TUN is Vi ...

  5. Tun/Tap interface tutorial

    Foreword: please note that the code available here is only for demonstration purposes. If you want t ...

  6. linux下TUN/TAP虚拟网卡的使用

    转载:http://wushank.blog.51cto.com/3489095/1306849 tun/tap 驱动程序实现了虚拟网卡的功能,tun表示虚拟的是点对点设备,tap表示虚拟的是以太网设 ...

  7. ubuntu14.04安装tun/tap网络设备

    14.04的系统默认是没有tun设备的,所以需要通过在内核中编译时勾选此设备.接下来分步来介绍如何安装tun设备. 一.更新ubuntu桌面版源: sudo gedit /etc/apt/source ...

  8. tun/tap设备_虚拟网卡

    tun/tap 驱动程序实现了虚拟网卡的功能,tun表示虚拟的是点对点设备,tap表示虚拟的是以太网设备,这两种设备针对网络包实施不同的封装.利用tun/tap 驱动,可以将tcp/ip协议栈处理好的 ...

  9. 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP (转)

    网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP 27 March 2013 TUN 设备 TUN 设备是一种虚拟网络设备,通过此设备,程序可以方便得模拟网络行为.先来看看物理设 ...

随机推荐

  1. Hbase Filter过滤器查询详解

    过滤器查询 引言:过滤器的类型很多,但是可以分为两大类——比较过滤器,专用过滤器 过滤器的作用是在服务端判断数据是否满足条件,然后只将满足条件的数据返回给客户端: hbase过滤器的比较运算符: LE ...

  2. Spring生态研习【一】:定时任务Spring-task

    本系列具体研究一下spring生态中的重要或者常用的功能套件,今天从定时任务开始,主要是spring-task.至于quartz,下次找个时间再总结. 我的验证环境,是SpringCloud体系下,基 ...

  3. 黄聪:分享几个免费IP地址查询接口(API)

    淘宝IP地址库 提供的服务包括:1. 根据用户提供的IP地址,快速查询出该IP地址所在的地理信息和地理相关的信息,包括国家.省.市和运营商.2. 用户可以根据自己所在的位置和使用的IP地址更新我们的服 ...

  4. Metadata in HTML

    [本文内容大部分来自MDN中文版:https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Introduction_to_HTML/The_head_m ...

  5. new 对象时的暗执行顺序

    为什么称为暗执行顺序,因为当我们在new 对象时,其不是简简单单的new一个完事,它要首先检查父类的,静态的,非静态的等代码,就好像我们结婚生孩子一样,要先到祖宗那里,公安局那里,左邻右舍那里,告诉他 ...

  6. VS2017调试出现异常浏览器直接关闭的解决办法

    最近升级完VS2017后,出现了各种不适应. 1.F5调试时总是会打开新的浏览器,过去都是在现有窗口右侧打开新的新的浏览器标签页. 这一点就让很不爽,勉强接受吧,继续调试代码但是还有第二种情况. 2. ...

  7. 学习笔记之Problem Solving with Algorithms and Data Structures using Python

    Problem Solving with Algorithms and Data Structures using Python — Problem Solving with Algorithms a ...

  8. 使用libvirtAPI打快照原理

    参考: https://blog.51cto.com/3646344/2096347 https://blog.51cto.com/3646344/2096351(磁盘外部快照) API接口: htt ...

  9. python 列表复制给另一个列表,改值两个列表均会改变(备忘)

    http://blog.csdn.net/lc_lc2000/article/details/53135839 本意是使A = B,B为一个列表,结果在后续对A的操作中,导致B中的值也改变了,才回忆起 ...

  10. 0初识Linux

    今天三八妇女节,Linux就该这么学,开课第一天.信心满满,激动,期待,要努力了.(博客为预习写的,今天又做了更新.)   Linux第一印象就是黑色背景屏幕,上面还有好多代码,敲的一手好的命令操控着 ...