因此,在您的配置中,您尝试发送到网络的所有数据包最初都源自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.1
IP地址-有所不同。您可以在这里使用任何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