Linux下tun/tap ping操作代码例子_3

d0f476f6fc8af096801d5bf04a9433c3.png    

       上次对tun/tap做了介绍,本次使用“编程”做进一步的使用理解。

1、创建接口

创建新接口和(重新)附加到持久接口的代码本质上是相同的;不同之处在于前者必须由 root 运行(更准确地说,由具有 CAP_NET_ADMIN 能力的用户运行),而后者如果满足某些条件,可以由普通用户运行。让我们从创建新接口开始。

首先,设备 /dev/net/tun 都必须以读/写方式打开。该设备也称为克隆设备,因为它用作创建任何 tun/tap 虚拟接口的起点。该操作(与任何 open() 调用一样)返回一个文件描述符。但这还不足以开始使用它与接口进行通信。    

创建接口的下一步是进行ioctl() 系统调用,其参数是上一步中的描述符、TUNSETIFF 常量以及指向包含描述虚拟接口的参数(基本上是其名称和所需的操作模式 - tun 或 tap)的数据结构的指针。作为一种变体,虚拟接口的名称可以不指定,在这种情况下,内核将通过尝试分配该类型的“下一个”设备来选择一个名称(例如,如果 tap2 已经存在,内核将尝试分配 tap3,依此类推)。所有这些都必须由 root 完成(或由具有 CAP_NET_ADMIN 功能的用户完成 - 我不会再重复这一点;假设它适用于我说“必须由 root 运行”的所有地方)。

如果 ioctl() 成功,则创建虚拟接口,并且我们拥有的文件描述符现在与其关联,并可用于通信。

创建虚拟接口的基本代码在内核源代码树的 Documentation/networking/tuntap.txt 文件中。稍加修改,我们就可以编写一个创建虚拟接口的简单函数:

#include <linux /if.h>#include <linux /if_tun.h>int tun_alloc(char *dev, int flags) {  struct ifreq ifr;  int fd, err;  char *clonedev = "/dev/net/tun";  /* Arguments taken by the function:   *   * char *dev: the name of an interface (or '\0'). MUST have enough   *   space to hold the interface name if '\0' is passed   * int flags: interface flags (eg, IFF_TUN etc.)   */   /* open the clone device */   if( (fd = open(clonedev, O_RDWR)) < 0 ) {     return fd;   }   /* preparation of the struct ifr, of type "struct ifreq" */   memset(&ifr, 0, sizeof(ifr));   ifr.ifr_flags = flags;   /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */   if (*dev) {     /* if a device name was specified, put it in the structure; otherwise,      * the kernel will try to allocate the "next" device of the      * specified type */     strncpy(ifr.ifr_name, dev, IFNAMSIZ);   }   /* try to create the device */   if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {     close(fd);     return err;   }  /* if the operation was successful, write back the name of the   * interface to the variable "dev", so the caller can know   * it. Note that the caller MUST reserve space in *dev (see calling   * code below) */  strcpy(dev, ifr.ifr_name);  /* this is the special file descriptor that the caller will use to talk   * with the virtual interface */  return fd;}

tun_alloc() 函数有两个参数:

  char *dev 包含接口的名称(例如 tap0、tun2 等)。可以使用任何名称,但最好选择一个能表明接口类型的名称。实际上,通常使用 tunX 或 tapX 等名称。如果 *dev 为 '\0',则内核将尝试创建请求类型的“第一个”可用接口(例如 tap0,但如果已经存在,则为 tap1,依此类推)。

  int flags 包含告诉内核我们想要哪种接口(tun 或 tap)的标志。基本上,它可以采用值 IFF_TUN 来指示 TUN 设备(数据包中没有以太网报头),或者采用 IFF_TAP 来指示 TAP 设备(数据包中有以太网报头)。

此外,另一个标志 IFF_NO_PI 可以与基值进行或运算。IFF_NO_PI 告诉内核不提供数据包信息。 IFF_NO_PI 的目的是告诉内核数据包将是“纯”IP 数据包,没有添加任何字节。否则(如果未设置 IFF_NO_PI),则会在数据包开头添加 4 个额外字节(2 个标志字节和 2 个协议字节)。IFF_NO_PI 不需要在接口创建和重新连接时间之间匹配。另请注意,当使用 Wireshark 捕获接口上的流量时,这 4 个字节永远不会显示。    

2、例子

2.1 程序例子

...  /* tunclient.c */  char tun_name[IFNAMSIZ];    /* Connect to the device */  strcpy(tun_name, "tun77");  tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI);  /* tun interface */  if(tun_fd < 0){    perror("Allocating interface");    exit(1);  }  /* Now read data coming from the kernel */  while(1) {    /* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */    nread = read(tun_fd,buffer,sizeof(buffer));    if(nread < 0) {      perror("Reading from interface");      close(tun_fd);      exit(1);    }    /* Do whatever with the data */    printf("Read %d bytes from device %s\n", nread, tun_name);  }  ...

2.2 为tun设备分配ip

ip addr add 192.168.99.167/24 dev tun77ip link set dev tun77 up

这步之后的效果如下:

59b61cdc788bca5ec03cfc21af8e4108.png

此时ifconfig:

38bef92e3e5978d82bcc801ebbd6bc55.png

2.3 使用 tcpdump监控报文

c61d6dc68a7298197e197fef52318eee.png

  执行ping操作后发现tcpdump并没有任何打印信息(那8个字节并不是ICMP的报文),即没有任何流量经过该接口。这种现象是符合预期的,因为当ping该接口的IP地址时,操作系统会认为报文不需要在"线路"上进行传输,由内核负责回应ping请求(当ping其他接口的IP地址时的现象也是一样的)。tcpdump抓包是在网络协议栈外进行的,ping本地IP地址时的报文会在协议层面处理,因此无法抓到报文。

      2.4 让 tcpdump监控到报文    

cc9dd99d0e1887e53572c0cb1666f01a.png

#尝试ping一下192.168.99.167/24网段的IP,#由于我们的程序中收到数据包后,啥都没干,相当于把数据包丢弃了,#所以这里的ping根本收不到返回包,#但在前两个窗口中可以看到这里发出去的四个icmp echo请求包,#说明数据包正确的发送到了应用程序里面,只是应用程序没有处理该包

    本次例子就到这里。

     如需测试代码可在后台留言“tun/tap icmp”

欢迎关注:

Linux虚拟网卡设备tun/tap介绍_2

linux下安装tun模块详细教程

参考文章:

https://backreference.org/2010/03/26/tuntap-interface-tutorial/

https://blog.youkuaiyun.com/sld880311/article/details/77854651

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值