本文将介绍 TUN/TAP 驱动的使用并分析虚拟网卡 TUN/TAP 驱动程式在 Linux 环境下的设计思路。

简介

虚拟网卡Tun/tap驱动是个开源项目,支持很多的类UNIX平台,OpenVPN和Vtun都是基于他实现隧道包封装。本文将介绍tun/tap驱动的使用并分析虚拟网卡tun/tap驱动程式在linux环境下的设计思路。

tun/tap 驱动程式实现了虚拟网卡的功能,tun表示虚拟的是点对点设备,tap表示虚拟的是以太网设备,这两种设备针对网络包实施不同的封装。利用tun/tap 驱动,能够将tcp/ip协议栈处理好的网络分包传给任何一个使用tun/tap驱动的进程,由进程重新处理后再发到物理链路中。开源项目openvpn ( http://openvpn.sourceforge.net)和Vtun( http://vtun.sourceforge.net)都是利用tun/tap驱动实现的隧道封装。

使用tun/tap驱动

在linux 2.4内核版本及以后版本中,tun/tap驱动是作为系统默认预先编译进内核中的。在使用之前,确保已装载了tun/tap模块并建立设备文档:



            #modprobe tun

            #mknod /dev/net/tun c 10 200

            

参数c表示是字符设备, 10和200分别是主设备号和次设备号。

这样,我们就能够在程式中使用该驱动了。

使用tun/tap设备的示例程式(摘自openvpn开源项目 http://openvpn.sourceforge.net,tun.c文档)



            int open_tun (const char *dev, char *actual, int size)

            {

            struct ifreq ifr;

            int fd;

            char *device = "/dev/net/tun";

            if ((fd = open (device, O_RDWR)) < 0) //创建描述符

            msg (M_ERR, "Cannot open TUN/TAP dev %s", device);

            memset (&ifr, 0, sizeof (ifr));

            ifr.ifr_flags = IFF_NO_PI;

            if (!strncmp (dev, "tun", 3)) {

            ifr.ifr_flags |= IFF_TUN;

            }

            else if (!strncmp (dev, "tap", 3)) {

            ifr.ifr_flags |= IFF_TAP;

            }

            else {

            msg (M_FATAL, "I don't recognize device %s as a TUN or TAP device",dev);

            }

            if (strlen (dev) > 3)		/* unit number specified? */

            strncpy (ifr.ifr_name, dev, IFNAMSIZ);

            if (ioctl (fd, TUNSETIFF, (void *) &ifr) < 0) //打开虚拟网卡

            msg (M_ERR, "Cannot ioctl TUNSETIFF %s", dev);

            set_nonblock (fd);

            msg (M_INFO, "TUN/TAP device %s opened", ifr.ifr_name);

            strncpynt (actual, ifr.ifr_name, size);

            return fd;

            }

            

调用上述函数后,就能够在shell命令行下使用ifconfig 命令配置虚拟网卡了,通过生成的字符设备描述符,在程式中使用read和write函数就能够读取或发送给虚拟的网卡数据了。

Tun/tap驱动程式工作原理

做为虚拟网卡驱动,Tun/tap驱动程式的数据接收和发送并不直接和真实网卡打交道,而是通过用户态来转交。在linux下,要实现核心态和用户态数据的交互,有多种方式:能够通用socket创建特别套接字,利用套接字实现数据交互;通过proc文档系统创建文档来进行数据交互;还能够使用设备文档的方式,访问设备文档会调用设备驱动相应的例程,设备驱动本身就是核心态和用户态的一个接口,Tun/tap驱动就是利用设备文档实现用户态和核心态的数据交互。

从结构上来说,Tun/tap驱动并不单纯是实现网卡驱动,同时他还实现了字符设备驱动部分。以字符设备的方式连接用户态和核心态。下面是示意图:



Tun/tap 驱动程式中包含两个部分,一部分是字符设备驱动,更有一部分是网卡驱动部分。利用网卡驱动部分接收来自TCP/IP协议栈的网络分包并发送或反过来将接收到的网络分包传给协议栈处理,而字符驱动部分则将网络分包在内核和用户态之间传送,模拟物理链路的数据接收和发送。Tun/tap驱动很好的实现了两种驱动的结合。

下面是定义的tun/tap设备结构:



            struct tun_struct {

            char 			name[8]; //设备名

            unsigned long 		flags; //区分tun和tap设备

            struct fasync_struct    *fasync; //文档异步通知结构

            wait_queue_head_t 	read_wait; //等待队列

            struct net_device	dev;  //linux 抽象网络设备结构

            struct sk_buff_head 	txq; //网络缓冲区队列

            struct net_device_stats	stats; //网卡状态信息结构

            };

            

struct net_device结构是linux内核提供的统一网络设备结构,定义了系统统一的访问接口。

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!