24

我很难解决这个问题 - 我正在尝试编写一个与 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 隧道驱动程序的应用程序?任何见解将不胜感激。

谢谢; 〜罗伯特

4

3 回答 3

28

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

ip addr show # my eth0 inet address is 10.0.2.15/24 as Im running on a VirtualBox vm with Ubuntu 18.04 guest
sudo ip tuntap add mode tun dev tun0
sudo ip addr add 10.0.3.0/24 dev tun0  # give it an address (that does not conflict with existing IP)
sudo ip link set dev tun0 up  # bring the if up
ip route get 10.0.3.50  # check that packets to 10.0.3.x are going through tun0
# 10.0.3.50 dev tun0 src 10.0.3.0 uid 1000 
ping 10.0.3.50 # leave this running in another shell to be able to see the effect of the next example, nobody is responding to the ping

tun0创建并且所有到目标 IP 地址 10.0.3.x 的数据包都将被路由到tun0

要从用户空间程序读取/写入此接口的数据包,您需要/dev/net/tun使用ioctl(). 这是一个示例,它将读取到达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() */
#include <unistd.h> /* read(), close() */

/* 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;
}

如果你有ping 10.0.3.1ping 10.0.3.40正在运行,你会Read 88 bytes from tun0定期看到。

您还可以使用 netcat UDP 进行测试,nc -u 10.0.3.3 2222并键入 text + Enter。

如果没有打印任何内容,则很可能分配给 tun0 的 id 地址/ip 范围不可访问/可路由/可寻址。确保ip route get 10.0.3.4显示10.0.3.4 dev tun0linux 内核知道到 10.0.3.4 的数据包应该发送到 tun0 设备。

删除tun0

sudo ip link set dev tun0 down
sudo ip tuntap del mode tun dev tun0
于 2016-03-01T23:42:25.537 回答
21

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

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

于 2009-06-16T20:30:34.183 回答
3

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

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

它带有一个源压缩包。

它与这个问题在同一组谷歌结果中。:-)

于 2012-05-30T04:42:19.080 回答