没有/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.1
或ping 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 tun0
linux 内核知道到 10.0.3.4 的数据包应该发送到 tun0 设备。
删除tun0
做
sudo ip link set dev tun0 down
sudo ip tuntap del mode tun dev tun0