因此,在您的配置中,您尝试发送到网络的所有数据包最初都源自10.0.0.1(因为它们正在通过tun0接口且其本地地址是10.0.0.1)。您捕获了数据包,到目前为止一切都很好。
现在,tun0进一步发送数据包。源地址是,10.0.0.1并且您希望数据包通过其他接口离开(wlp2s0针对您的情况)。那是路由,所以让我们先启用路由:
sysctl -w net.ipv4.ip_forward=1
在此之后,如果你看tcpdump的wlp2s0,你可以看到的数据包离开与源地址10.0.0.1,而不是与WLAN接口的源地址(你期望我猜的)。因此,我们需要更改源地址,这就是源NAT。在linux中,借助netfilter / iptables很容易:
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.1 -j MASQUERADE
另请检查您的FORWARD连锁店是否有ACCEPT政策,或者您需要允许转发以下内容:
iptables -A FORWARD -i tun0 -o wlp2s0 -s 10.0.0.1 -j ACCEPT
iptables -A FORWARD -i wlp2s0 -o tun0 -d 10.0.0.1 -j ACCEPT
现在一切都应该正常工作:linux内核进行路由,它将数据包从tun0接口移动到wlp2s0。网络过滤器应在源IP改变10.0.0.1你的wlp2s0接口分配地址的输出数据包。它存储所有连接,并且当回复数据包返回时(如果有),它将wlp2s0接口分配地址的目标地址更改为10.0.0.1(“ conntrack”功能)。
好吧,应该,但是没有。看起来,netfilter与这种复杂的路由配置以及同一数据包首先经过OUTPUT链然后被路由然后进入链这一事实混淆了PREROUTING。至少在Debian 8上,它不起作用。
解决netfilter问题的最佳方法是TRACE:
modprobe ipt_LOG
iptables -t raw -A OUTPUT -p icmp -j TRACE
iptables -t raw -A PREROUTING -p icmp -j TRACE
我仅启用对ICMP数据包的跟踪,您可以使用其他过滤器进行调试。
它将显示数据包通过哪些表和链。而且我可以看到数据包在FORWARD链中没有前进(并且nat/POSTROUTING实际上并没有被链捕获SNAT)。
下面是使这项工作的几种方法。
方法1
取消混淆Netfilter的最佳方法是更改tun0.c应用程序中数据包的源IP地址。这也是最自然的方法。我们需要在向外的途中将10.0.0.1更改为10.0.0.2,在返回的途中将10.0.0.2更改为10.0.0.1。
我已经tun0.c使用源地址更改代码进行了修改。这是新文件,这是您的补丁文件tun0.c。对IP标头的更改还涉及校验和校正,因此我从OpenVPN项目中获取了一些代码。这是我在干净重启并tun0_changeip.c启动后执行的命令的完整列表 :
ifconfig tun0 inet 10.0.0.1/30 up
sysctl -w net.ipv4.ip_forward=1
ip route add default dev tun0 table John
ip rule add from all lookup John
ip rule add from 10.0.0.2 lookup main priority 500
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.2 -j MASQUERADE
请注意,在这种情况下,您无需关闭反向路径过滤,因为一切都是合法的- tun0仅接收和发送属于其子网的数据包。您也可以执行基于源的路由,而不是基于接口的路由。
方法2
有可能SNAT在数据包到达tun0接口之前执行。虽然不是很正确。在这种情况下,您肯定需要关闭反向路径过滤:
sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0
现在,执行SNAT:iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source ip.address.of.your.wlan.interface
在这里,我们在数据包到达设备之前更改源地址tun0。tun0.c代码以“原样”(更改了源地址)重发这些数据包,并成功地通过wlan接口路由了这些数据包。但是您可能在wlan接口上有一个动态IP并想要使用MASQUERADE(为了不显式指定接口地址)。这是您可以利用的方式MASQUERADE:
iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source 10.0.55.1
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.55.1 -j MASQUERADE
请注意10.0.55.1IP地址-有所不同。您可以在这里使用任何IP,没关系。如果我们之前更改源IP,则数据包到达接口上的nat/POSTROUTING链wlp2s0。现在,WLAN接口不再依赖于静态IP。
方法3
您也可以使用fwmark。这样SNAT,您将不需要,但仅捕获外发数据包:
首先,我们需要为此禁用反向路径过滤,tun0因为它将转发属于另一个网络的数据包:
sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0
Now let's alter the routing rules a bit:
# Delete old rules
ip rule del iif tun0 lookup main
ip rule del from all lookup John
# Packets will start going from wlan interface so they will have source address of it
iptables -t mangle -A OUTPUT -o wlp2s0 -j MARK --set-mark 1
ip rule add fwmark 0x1 lookup John
这是在我的Debian 8机器上运行的路由和网络过滤器的另一个“ hack” ,但是我仍然建议采用第一种方法,因为它更自然并且不使用任何hack。
您也可以考虑将应用程序构建为透明代理。我认为这比分析tun设备的数据包要容易得多。
-j SNAT,而不是-s SNAT