我正在尝试更改 ICMP 回复数据包的目标 IP 地址。
ICMP 回复从我的 IPSEC 隧道进入路由器(我不完全确定为什么它在 tcpdump 中显示两次):
14:28:09.562030 IP 35.182.188.86 > 54.76.131.136: ICMP echo request, id 28997, seq 1259, length 64
14:28:09.641595 IP 54.76.131.136 > 35.182.188.86: ICMP echo reply, id 28997, seq 1259, length 64
14:28:09.641645 IP 54.76.131.136 > 35.182.188.86: ICMP echo reply, id 28997, seq 1259, length 64
我尝试使用以下命令在 PREROUTING 表上将目标 IP 更改为本地 IP (172.31.20.219):
sudo iptables -t nat -A PREROUTING --source 54.76.131.136 --destination 35.182.188.86 -j DNAT --to-destination 172.31.20.219
因此表格如下所示:
ubuntu@ip-172-31-23-13:~$ sudo iptables-save -c
# Generated by iptables-save v1.6.0 on Tue Oct 3 14:58:19 2017
*nat
:PREROUTING ACCEPT [33:2711]
:INPUT ACCEPT [32:2627]
:OUTPUT ACCEPT [8:1080]
:POSTROUTING ACCEPT [9:1164]
[0:0] -A PREROUTING -s 54.76.131.136/32 -d 35.182.188.86/32 -j DNAT --to-destination 172.31.20.219
COMMIT
# Completed on Tue Oct 3 14:58:19 2017
# Generated by iptables-save v1.6.0 on Tue Oct 3 14:58:19 2017
*raw
:PREROUTING ACCEPT [2646:283498]
:OUTPUT ACCEPT [998:168846]
[1954:164136] -A PREROUTING -s 54.76.131.136/32 -d 35.182.188.86/32 -j LOG
[821:68964] -A PREROUTING -s 54.76.131.136/32 -d 35.182.188.86/32 -j TRACE
COMMIT
# Completed on Tue Oct 3 14:58:19 2017
然而,IP 变化并没有发生。
使用
sudo iptables -t raw -A PREROUTING --source 54.76.131.136 --destination 35.182.188.86 -j LOG
我可以看到可以在原始表上进行匹配:
Oct 3 14:25:20 ip-172-31-23-13 kernel: [ 889.588090] IN=eth0 OUT= MAC=02:fc:a0:12:56:64:02:7f:fe:dc:a4:0d:08:00 SRC=54.76.131.135 DST=35.182.188.85 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=64700 PROTO=ICMP TYPE=0 CODE=0 ID=28997 SEQ=1091
但它似乎与 nat 表不匹配。
有人能提供建议为什么目标 IP 没有改变或如何进一步调试吗?看起来很奇怪。
我正在使用 Ubuntu 16.04。传入流量通过 StrongSwan 设置的 IPSEC 隧道传入。
谢谢
答案1
ICMP Echo 回复数据包是已建立流的一部分。这意味着,当内核在正常情况下收到此类数据包时,它已经在期待它(在初始 ICMP Echo 请求之后),因此 nat 所需的基础模块 conntrack 已为其创建了期望条目。在这种情况下,nat 表将短路,甚至不会针对此回复数据包执行。
参考:https://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html#ss3.2(NAT)
该表与“过滤器”表稍有不同,因为只有新连接的第一个数据包才会遍历该表:此遍历的结果将应用于同一连接中的所有未来数据包。
要检查此行为,请在事件监控模式下使用 conntrack 命令(来自 conntrack 包)。以下是向 Google 执行一次 ping 的示例:
# conntrack -E
[NEW] icmp 1 30 src=192.168.3.2 dst=8.8.8.8 type=8 code=0 id=12837 [UNREPLIED] src=8.8.8.8 dst=198.51.100.5 type=0 code=0 id=12837
[UPDATE] icmp 1 30 src=192.168.3.2 dst=8.8.8.8 type=8 code=0 id=12837 src=8.8.8.8 dst=198.51.100.5 type=0 code=0 id=12837
[DESTROY] icmp 1 src=192.168.3.2 dst=8.8.8.8 type=8 code=0 id=12837 src=8.8.8.8 dst=198.51.100.5 type=0 code=0 id=12837
第一个数据包将创建 [NEW] 条目,因此将通过 nat 表,从而有机会改变期望(在此示例中为经典的 SNAT/MASQUERADE)。此流的其他数据包仅使用 conntrack 期望进行处理,直到条目被销毁(此 icmp 的超时时间为 30 秒)。
使用 nat 规则将与初始 ICMP Ping Echo 请求一起工作,因为它将是一个新的流。
您没有说明您实际上想要用这一切做什么。如果您的目标是将数据包复制到 172.31.20.219,您应该尝试 TEE 目标(man iptables-extensions)。