我在服务器上设置 VPN 时注意到,所有发出的数据包的源 IP 始终是服务器的公共 IP。但根据我对路由表的理解,它应该是 VPN 的 IP。而且,如果我使用ping -I 10.8.0.1 10.8.0.42
它,它又是我服务器的公共 IP。我在这里遗漏了什么?
tcpdump -n -i enp3s0 dst 213.225.3.191
这是使用以下命令执行 ping 时的输出ping -I 10.8.0.1 213.225.3.191
17:34:36.285695 IP 5.9.142.112 > 213.225.3.191: ICMP echo request, id 10747, seq 34, length 64
tcpdump -n -i tun0
这是使用以下命令执行 ping 时的输出ping -I 10.8.0.1 10.8.0.42
17:43:45.152792 IP 5.9.142.112 > 10.8.0.42: ICMP echo request, id 10834, seq 1, length 64
输出ip route
default via 5.9.142.97 dev enp3s0 proto static
5.9.142.97 dev enp3s0 proto kernel scope link src 5.9.142.112
10.8.0.0/30 via 10.8.0.2 dev tun0
10.8.0.0/24 via 10.8.0.2 dev tun0
10.8.0.2 dev tun0 proto kernel scope link src 10.8.0.1
输出route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default static.97.142.9 0.0.0.0 UG 0 0 0 enp3s0
static.97.142.9 0.0.0.0 255.255.255.255 UH 0 0 0 enp3s0
10.8.0.0 10.8.0.2 255.255.255.252 UG 0 0 0 tun0
10.8.0.0 10.8.0.2 255.255.255.0 UG 0 0 0 tun0
10.8.0.2 0.0.0.0 255.255.255.255 UH 0 0 0 tun0
输出iptables -L -v -n -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 584K packets, 39M bytes)
pkts bytes target prot opt in out source destination
4 336 MASQUERADE all -- * enp3s0 10.0.0.0/8 0.0.0.0/0
0 0 MASQUERADE all -- * enp3s0 10.0.0.0/8 0.0.0.0/0
285 18732 SNAT all -- * * 10.0.0.0/8 0.0.0.0/0 to:5.9.142.112
0 0 MASQUERADE all -- * enp3s0 10.0.0.0/8 0.0.0.0/0
0 0 MASQUERADE all -- * tun0 0.0.0.0/0 0.0.0.0/0
0 0 MASQUERADE all -- * tun0 10.0.0.0/8 0.0.0.0/0
0 0 MASQUERADE all -- * tun0 0.0.0.0/0 0.0.0.0/0
0 0 SNAT all -- * * 0.0.0.0/0 10.8.0.42 to:10.8.0.1
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
答案1
为了完全理解 Linux 中的数据包流iptables
,您需要此图或类似内容以供参考。在图中,ping
位于应用程序层的“本地进程”框中。
使用您当前的路由表,系统将“认为”只有发往 10.8.0.0/24 的流量才会被路由到 VPN 隧道接口;其他所有流量都必须enp3s0
通过 VPN 隧道传出。
当您运行 时ping -I 10.8.0.1 213.225.3.191
,目标 IP 不在 10.8.0.0/24 块中,因此enp3s0
将使用 。但出站路由经过网关 5.9.142.97,用于到达该网关的路由条目包括src 5.9.142.112
,指定要使用的源地址。
如果这不会改变源 IP,则 iptables 后路由表中的第一个 MASQUERADE 规则将会改变。
4 336 MASQUERADE all -- * enp3s0 10.0.0.0/8 0.0.0.0/0
该规则匹配所有从接口传出的数据包enp3s0
(由路由决策决定),其源 IP 在 10.0.0.0/8 范围内,而 10.8.0.1 匹配该范围。由于这是一条 MASQUERADE 规则,它会将传出数据包的源 IP 地址更改为数据包传出的网络接口的 IP 地址。第一个匹配获胜,因此该数据包通过后路由表处理完毕,然后通过 退出系统enp3s0
。
结果将与你看到的完全一致:
17:34:36.285695 IP 5.9.142.112 > 213.225.3.191: ICMP echo request, id 10747, seq 34, length 64
当您运行 时ping -I 10.8.0.1 10.8.0.42
,这是 的有效目的地tun0
,并且源地址对它也是有效的。路由决策完成。
在 iptables/netfilter NAT 后路由表中,前两个规则被限制为匹配通过 传出的流量enp3s0
,因此它们不适用。但随后传出的数据包会命中此 SNAT 规则:
285 18732 SNAT all -- * * 10.0.0.0/8 0.0.0.0/0 to:5.9.142.112
任何协议,检查。规则中未指定接口,因此它适用于tun0
。检查。源地址在 10.0.0.0/8 内,检查。目标地址任何地址,检查。它匹配。这是一条 SNAT 规则,因此它修改了年代源 IP 地址。它会更改源 IP至 5.9.142.112。这可能不是你想要的,但规则就是这么说的。
第一个匹配获胜,因此数据包现在已完成后路由表处理:此数据包的后续条目将不再处理。由于 NAT 后路由表是传出路径上的最后一个表,因此数据包将按原样退出系统。
结果与此传出的数据包完全匹配tun0
:
17:43:45.152792 IP 5.9.142.112 > 10.8.0.42: ICMP echo request, id 10834, seq 1, length 64
如果您计划通过 VPN 传输所有互联网流量,则您的路由表应该包含:
- 物理网络接口的路由
5.9.142.97 dev enp3s0 proto kernel scope link src 5.9.142.112
。您已经拥有该路由,因为它将在配置物理网络接口时自动生成。 - 通过网关 5.9.142.97 向 VPN 隧道远程端点的公共 IP 地址(不是 10.8.0.2)输入 /32(或 genmask 255.255.255.255)
enp3s0
条目。这样即使您将默认网关路由指向 VPN 接口,VPN 封装的数据包也能通过您的实际网络接口发出并到达远程 VPN 端点。否则,传出的 VPN 流量将被反复重新封装,从而形成路由循环,阻止 VPN 流量真正到达远程 VPN 端点。 - VPN 隧道本身的条目: 。配置接口
10.8.0.2 dev tun0 proto kernel scope link src 10.8.0.1
时,该条目也可能会自动生成。tun0
- 通过 10.8.0.2 的默认网关条目,将任何没有定义更具体路由的流量(即基本上所有尚未经过 VPN 封装的、流向远程 VPN 端点的流量)指向 VPN 隧道。
10.8.0.0/30 via 10.8.0.2
仅此而已。默认网关条目将执行和条目的工作10.8.0.0/24 via 10.8.0.2
。
除非您的系统充当其他系统的 VPN 网关,否则您可能根本不需要 NAT POSTROUTING 表中的任何条目。