具有Tun接口的I / O

其目的是让一个程序拦截一个IP数据包的集合并读取其原始内容,然后在修改之后将其重新插入networking。

我的方法是build立一个Tuntap接口(Tun,具体),然后让iptables和类似的redirect到这个隧道接口所需的数据包。

出于testing的目的,我已经编写了这个简短的shell脚本来设置Tun界面并添加所需的规则。 现在,我打算对来自本地机器发送的123.123.123.123目的地的任何数据包进行testing。 这里是启动脚本:

 # Set up the tunnel ip tuntap add dev maintun mode tun ifconfig maintun inet 10.10.10.1 netmask 255.255.255.0 up # Mark packets for forwarding to tun iptables -t mangle -A PREROUTING -d 123.123.123.123 -j MARK --set-mark 2 # Apply ClientRouter table to mark 2 as it's defined in /etc/iproute2/rt_tables # 201 ClientRouter ip rule add fwmark 2 table ClientRouter # Apply gw if to ClienRouter ip route add default via 10.10.10.1 dev maintun table ClientRouter 

我开始编写一个perl脚本来从Tun设备读取,但是我一次卡住多个点:

  1. 在我看来,这样做的方法是让脚本自己通过调用/dev/net/tun的文件句柄来调用ioctl()来创build接口,但是我不确定ioctl()想要的其他论点。 这导致我接下来的两点:
  2. 我看到提到第二个论点是TUNSETIFF 。 我所知道的是它必须是数字。 这是什么要求?
  3. 从我所搜集到的情况来看,第三个论据应该是某种标志,但是我没有设法find他们的信息。 据推测,一个标志将是select,如果它应该是一个Tun或Tap隧道。 有关于此的任何信息?

当我坚持使用ioctl()标志时,我想退后一步,问:如何从Tun设备中读取程序,最好是事先设置的预先configuration的程序?

另外,如果有人看到启动脚本有任何问题,请随时发声。

虽然理想的情况下,这个解决scheme将会在perl中,但这并不是必须的,只是这是我能够阅读的最简单的语言。 Java也是体面的。 不幸的是,我的C语言能力还没有达到应有的水平。

编辑:

如果采用不同于Tun / Tap的方法,我们可以按照第一段所述的方式进行操作,当然任何build议都会受到欢迎。


注意:

我碰到了这个问题 ,虽然类似,但它并没有提供ioctl()争论的答案。 然而,这是什么表明需要一个ioctl()调用。

首先,TUN / TAP接口记录在Linux内核文档中 ,如果您还没有看过,那么值得一读。 这些例子当然是用C语言编写的,但希望仍然有用。

我看到提到第二个论点是TUNSETIFF 。 我所知道的是它必须是数字。 这是什么要求?

这是一个C库常量,可以用下面的代码来确定它的值:

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <linux/if.h> #include <linux/if_tun.h> int main(int argc, char **argv) { printf("TUNSETIFF: %d\n", TUNSETIFF); return 0; } 

我的系统上返回:

 TUNSETIFF: 1074025674 

从我所搜集到的情况来看,第三个论据应该是某种标志,但是我没有设法找到他们的信息。 据推测,一个标志将是选择,如果它应该是一个Tun或Tap隧道。 有关于此的任何信息?

第三个参数是指向具有包含设备名称的ifr_name属性和包含标志的ifr_flags属性的结构的指针。 内核文档提供了以下示例代码:

  /* Flags: IFF_TUN - TUN device (no Ethernet headers) * IFF_TAP - TAP device * * IFF_NO_PI - Do not provide packet information */ ifr.ifr_flags = IFF_TUN; if( *dev ) strncpy(ifr.ifr_name, dev, IFNAMSIZ); if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ close(fd); return err; } 

您可以使用与我们用来查找TUNSETIFF值相同的代码找到不同标志( IFF_TUNIFF_TAP )的值。

如果您使用Perl编写代码,则需要一种方法来创建相应的C兼容结构。 我的Perl过于生疏,无法提供正确的解决方案。

但是,似乎有很多Perl模块可以简化整个过程: