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

启动设备之前

有的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. golang 写日志到syslog

    应用程序可以通过 UNIX domain sockets, UDP or TCP,向syslog守护进程发送日志.syslog守护进程可以在远端. 这样,就可以不用单独收集应用程序的日志了. gola ...

  2. Nginx禁止IP访问,只允许域名访问

    Nginx禁止IP访问,只允许域名访问 我们在使用nginx的过程中会遇到很多的恶意IP攻击,这个时候就要用到Nginx 禁止IP访问了. 1.直接返回403错误 server { listen de ...

  3. sxstrace启动.bat

    @echo offset dd=%date:~8,2%set mm=%date:~5,2%set yy=%date:~0,4%set Tss=%TIME:~6,2%set Tmm=%TIME:~3,2 ...

  4. TCP/IP学习20180629-数据链路层-ARP、IP

    1.数据链路层:IP.ARP.RARPARP协议用来找到目标主机的Ethernet网卡Mac地址,IP协议用来承载数据ARP协议找到目标,IP协议传输数据2.IP协议ip协议是TCP/IP协议的核心, ...

  5. 会话保持及Form表单

    1,cookie技术视图views里面:def index(request): #获取请求中的cookie num = request.COOKIES.get('num') if num: num = ...

  6. Deployment Descriptor Web.xml

    Deployment Descriptor部署描述符: - 部署描述符是要部署到Web容器或EJB容器的Web应用程序或EJB应用程序的配置文件. - 部署描述符应包含EJB应用程序中所有企业bean ...

  7. tomcat JRE_HOME

    tomcat 不知道什么时候开始需要  JRE_HOME了: D:\java\apache-tomcat-7.0.68\bin>startup.batJAVA_HOME == D:\Progra ...

  8. 【Java】获取二维数组行列长度

    二维数组int array[][] = new int[3][3]; 行长度:array.length 列长度:array[i].length

  9. Balls(扔鸡蛋问题)

    4554 BallsThe classic Two Glass Balls brain-teaser is often posed as:“Given two identical glass sphe ...

  10. 触发full gc的条件

    1.调用System.gc 2.老年代空间不足 3.永生区空间不足 4.CMS GC时出现promotion failed和concurrent mode failure 5.统计得到的Minor G ...