【问题标题】:How to interface with the Linux tun driver如何与 Linux tun 驱动程序交互
【发布时间】:2010-11-03 11:19:56
【问题描述】:

我很难解决这个问题 - 我正在尝试编写一个与 Linux 隧道驱动程序交互的程序。在一个非常基本的层面上,我只是想创建一个能够通过网络隧道传输数据的应用程序。但是,我完全不知道如何正确设置隧道驱动程序以完成此操作。

我在 Ubuntu 9.04 上开发,我已经加载了隧道驱动内核模块。

存在设备/dev/net/tun,但没有/dev/tunX 设备。我无法使用 ifconfig 创建这些设备 - 例如,每当我运行 /sbin/ifconfig tun0 up 时,我都会收到以下错误:

tun0:获取接口标志时出错:没有这样的设备。

如果我尝试查看/dev/net/tun 设备,则会出现以下错误:

cat: /dev/net/tun: 文件描述符处于错误状态。

试图通过一个小程序打开/dev/tunX,基本上,一个简单的

tun_fd = open( "/dev/tun0", O_RDWR )

返回 -1:应用程序以 root 身份运行,但仍无法打开此隧道设备。可以打开/dev/net/tun,但这似乎不会生成新的/dev/tunX 设备来代替使用。

所以,总而言之 - 如何编写一个希望使用 Linux 隧道驱动程序的应用程序?任何见解将不胜感激。

谢谢; ~罗伯特

【问题讨论】:

    标签: c driver tunnel tun


    【解决方案1】:

    没有/dev/tunX 设备文件。相反,您打开/dev/net/tun 并通过ioctl() 将其配置为“指向”tun0。为了展示基本过程,我将使用命令行工具ip tun tap 创建 TUN 接口,然后展示从该 TUN 设备读取的 C 代码。所以通过命令行创建tun接口:

    sudo ip tuntap add mode tun dev tun0
    ip addr add 10.0.0.0/24 dev tun0  # give it an ip
    ip link set dev tun0 up  # bring the if up
    ip route get 10.0.0.2  # check that packets to 10.0.0.x are going through tun0
    ping 10.0.0.2  # leave this running in another shell to be able to see the effect of the next example
    

    现在我们创建了tun0。要从用户空间程序读取/写入此接口的数据包,您需要使用ioctl() 与/dev/net/tun 设备文件进行交互。这是一个示例,它将读取到达tun0 接口的数据包并打印大小:

    #include <fcntl.h>  /* O_RDWR */
    #include <string.h> /* memset(), memcpy() */
    #include <stdio.h> /* perror(), printf(), fprintf() */
    #include <stdlib.h> /* exit(), malloc(), free() */
    #include <sys/ioctl.h> /* ioctl() */
    
    /* includes for struct ifreq, etc */
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <linux/if.h>
    #include <linux/if_tun.h>
    
    int tun_open(char *devname)
    {
      struct ifreq ifr;
      int fd, err;
    
      if ( (fd = open("/dev/net/tun", O_RDWR)) == -1 ) {
           perror("open /dev/net/tun");exit(1);
      }
      memset(&ifr, 0, sizeof(ifr));
      ifr.ifr_flags = IFF_TUN;
      strncpy(ifr.ifr_name, devname, IFNAMSIZ); // devname = "tun0" or "tun1", etc 
    
      /* ioctl will use ifr.if_name as the name of TUN 
       * interface to open: "tun0", etc. */
      if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) {
        perror("ioctl TUNSETIFF");close(fd);exit(1);
      }
    
      /* After the ioctl call the fd is "connected" to tun device specified
       * by devname ("tun0", "tun1", etc)*/
    
      return fd;
    }
    
    
    int main(int argc, char *argv[])
    {
      int fd, nbytes;
      char buf[1600];
    
      fd = tun_open("tun0"); /* devname = ifr.if_name = "tun0" */
      printf("Device tun0 opened\n");
      while(1) {
        nbytes = read(fd, buf, sizeof(buf));
        printf("Read %d bytes from tun0\n", nbytes);
      }
      return 0;
    }
    

    【讨论】:

    • 此答案缺少以下语句:#include &lt;unistd.h&gt; 用于函数 read() 和 close()。
    【解决方案2】:

    阅读/usr/src/linux/Documentation/networking/tuntap.rst。

    您应该open /dev/net/tun 设备。随后打开的 fd 上的ioctl 将创建tun0(或您希望命名的任何名称)网络接口。 Linux 的网络接口不对应任何/dev/* 设备。

    【讨论】:

    • @rmrobins;你做了什么来真正让它工作?我相信我的问题与您的原始问题非常相似。我有 /dev/net/tun 设备可见,但打开它不会产生网络接口。我一直在尝试使用 br_select.c 和 br_sigio.c 示例。
    • 如上所述,打开/dev/net/tun。然后,将使用 ioctl 来创建实际的接口本身。 ioctl 称为 TUNSETIFF,参数是 struct ifreq 类型。 ifreq 结构的标志应设置为 IFF_TUN。一旦 ioctl 返回,ifreq 结构的 ifr_name 字段将设置为打开的接口的名称。希望这会有所帮助!
    【解决方案3】:

    我遇到了一个很好的介绍教程

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

    它带有一个源压缩包。

    它与此问题在同一组 Google 搜索结果中。 :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-02
      • 2019-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-15
      相关资源
      最近更新 更多