答案1
网络过滤器与路线无关。这是解释下面发生的事情的重要因素。网络过滤器的 NAT 处理会改变地址,并且在某些情况下,当在路由决策之前完成此操作时,这会反过来改变路由决策。网络过滤器本身并不进行路由决策:这只是路由堆栈的作用。
我假设低于此Linux路由器没有额外的防火墙规则(默认情况下iptables 筛选表),因为问题中从未提及。另外,为了避免增加需要解决的案例,我假设除了linux-srv(和Linux路由器)在 10.99.99.0/24 LAN 中(解决它们也不难)。
关于删除 1.1.1.6
SNAT 发生在 POSTROUTING 时,在任何路由决策之后。如果 SNAT 发现 IP 匹配给定条件,它将添加一个 conntrack 条目来处理回复。类似的事情发生在Linux路由器(使用conntrack -E -e NEW
):
[NEW] tcp 6 120 SYN_SENT src=10.99.99.50 dst=8.8.8.8 sport=57490 dport=80 [UNREPLIED] src=8.8.8.8 dst=1.1.1.6 sport=80 dport=57490
它不是网络过滤器的工作是确保回复确实会回来。这又是路由堆栈的工作(包括外部路由)Linux路由器没有控制权)。
删除之前,1.1.1.6 的 IP 地址为Linux路由器。添加此 IP 的接口并不重要,因为 Linux 遵循弱宿主模型:它可以回答在任何接口上收到的对此 IP 的查询。删除此条目不会阻止接收 1.1.1.6 的数据包,因为M10i有一条到达 1.1.1.6 的特定路线:使用 1.1.215.48 属于Linux路由器。所以Linux路由器从未收到此 IP 的 ARP 请求:ARP 请求来自M10i始终为 1.1.215.48(并且同样表示,M10i的 ARP 表将仅缓存 1.1.215.48,而不是 1.1.1.6)。这意味着该 IP 的存在并不重要:Linux路由器将要总是接收 1.1.1.6 的流量。但现在有一个不同之处:
- 如果传入数据包与先前创建的 conntrack 条目不匹配
如果数据包与之前的活动无关linux-srv,该数据包将到达第一个路线决定,如所示这个示意图。根据其当前的路由表应该是这样的:
# ip route get from 198.51.100.101 iif eth0 1.1.1.6
1.1.1.6 from 198.51.100.101 via 1.1.215.60 dev eth0
cache iif eth0
如果是的话M10i(或 1.1.215.32/27 LAN 中的任何系统),Linux路由器还会不时添加 ICMP 重定向,如下所示:
# ip route get from 1.1.215.60 iif eth0 1.1.1.6
1.1.1.6 from 1.1.215.60 via 1.1.215.60 dev eth0
cache <redirect> iif eth0
无论如何,对于来自互联网的数据包,数据包将被发送回M10i,这可能正在实施严格反向路径转发:这个路由回的数据包将被丢弃M10i,因为其源 (198.51.100.101) 位于其路由表的错误一侧,因此被严格路径转发过滤。如果没有严格的反向路径转发,这将导致之间的循环M10i和Linux路由器直到数据包的 TTL 减至 0,然后数据包也被丢弃。
- 如果传入数据包做匹配先前经过 NAT 并由 conntrack 跟踪的流。
上一个示例:从 8.8.8.8 tcp 端口 80 到 1.1.1.6 端口 57490 收到的回复数据包,将通过以下方式跟踪conntrack -E
:
[UPDATE] tcp 6 60 SYN_RECV src=10.99.99.50 dst=8.8.8.8 sport=57490 dport=80 src=8.8.8.8 dst=1.1.1.6 sport=80 dport=57490
[UPDATE] tcp 6 432000 ESTABLISHED src=10.99.99.50 dst=8.8.8.8 sport=57490 dport=80 src=8.8.8.8 dst=1.1.1.6 sport=80 dport=57490 [ASSURED]
在某个预路由点,连线将处理“de-SNAT”(提醒一下,这个数据包将永远不会再次穿越iptables' nat表,这个在之前的原理图里也有写:仅针对“新”连接查阅“nat”表)。目标 IP 现在更改为 10.99.99.50,数据包到达第一个路由决策:它被路由到linux-srv。一切正常。
所以我解释了删除 1.1.1.6 时会发生什么:不会影响linux-srv作为互联网客户端,但会造成一些轻微的干扰M10i和Linux路由器对于不相关的入口数据包。
如果您希望互联网上的一些客户能够到达linux-srv使用 DNAT 规则Linux路由器,然后对于受影响的连接(例如:网络服务器linux-srvTCP 端口 80),一切都会正常运行而不会中断。对于其他尝试,再次存在一个小问题M10i和Linux路由器。
关于删除 SNAT 规则的源 IP 选择器/过滤器
未提供信息:传出接口上是否还有选择器/过滤器。下面的两个规则将从iptables -t nat -n -L
(但不是从iptables -t nat -n -v -L
或更好)获得相同的输出iptables-save
:
iptables -t nat -A POSTROUTING -o eth0 -s 10.99.99.254 -j SNAT --to-source 1.1.1.6
或者
iptables -t nat -A POSTROUTING -s 10.99.99.254 -j SNAT --to-source 1.1.1.6
实际上,在这种情况下如果您现在使用以下两个命令中的任何一个都没有关系:
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 1.1.1.6
iptables -t nat -A POSTROUTING -j SNAT --to-source 1.1.1.6
- 1.1.1.6 仍然属于Linux路由器
因为无法看到来自 eth0 端的私有 IP 目标地址,Linux路由器只能有效地路由一IP地址:linux-srv的 10.99.99.50 并且此路由仅在首先从 10.99.99.50 发起时才会发生,因此它被 SNAT 到公共 IP。自从iptables仅在初始连接(状态 NEW)时创建新的 conntrack 条目,此后 conntrack 条目将不再更改,一切都会正常工作。
1.1.1.6 被删除Linux路由器
为了linux-srv当连接到互联网时,一切仍然会按预期工作:前面的解释也适用。
对于从外部到 1.1.1.6 的任何未知传入连接(例如,来自 198.51.100.101):
路由堆栈确定 1.1.1.6 应路由到M10i(参见前面的解释)。在状态 NEW 下添加一个临时 conntrack 条目,并且数据包到达 nat/POSTROUTING:数据包被 SNAT 到 1.1.1.6 并发送回M10i。M10i有一条到 1.1.1.6 的路由,并再次将更改后的数据包发送到Linux路由器源和目标 IP 均为 1.1.1.6(由于源位于其路由表的正确一侧,因此严格反向路径转发甚至不会删除它)。Linux路由器
conntrack -E
接收到一个数据包...从那里我无法判断它是否是一个错误,但这是在使用从 198.51.100.101 接收到的单个 TCP SYN 数据包重现您的情况的实验中捕获的内容:# conntrack -E [NEW] tcp 6 120 SYN_SENT src=198.51.100.101 dst=1.1.1.6 sport=48202 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=48202 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=48202 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=60062 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=60062 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=23442 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=23442 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=54429 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=54429 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=7652 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=7652 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=34503 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=34503 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=49256 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=49256 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=58399 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=58399 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=54522 [...]
即使 netfilter 的行为不正常,之间也确实存在循环M10i和Linux路由器(直到 TTL 降至 0)。
结论
不要删除本地 IP 地址 1.1.1.6。您正在造成路由问题,但事实并非如此网络过滤器纠正这些路由问题的作用。即使您添加防火墙规则来防止这些循环,使用不正确的路由也不是明智的行为。
同样,您可以选择删除 SNAT 规则的源 IP 选择器,但如果也没有选择接口,则最好不要删除:(即,如果您选择此规则:)iptables -t nat -A POSTROUTING -j SNAT --to-source 1.1.1.6
。它之所以起作用,是因为有私有 IP 地址,在互联网上不可路由。如果不是这种情况,任何来自外部的连接都会尝试到达后面的 LANLinux路由器的 eth2 接口将被 SNAT 到 1.1.1.6。
例如,如果您添加 DNAT 规则以获取来自以下位置的某些服务,情况也会如此:linux-srv可从互联网访问,防止linux-srv永远不会看到与 1.1.1.6 不同的源地址。这是模拟中的一个具体示例(1.1.1.6 的正常恢复到Linux路由器):
# ip -br a
lo UNKNOWN 127.0.0.1/8 1.1.1.6/32
eth0@if5 UP 1.1.215.48/27
eth2@if4 UP 10.99.99.254/24
# iptables -t nat -A PREROUTING -d 1.1.1.6 -p tcp --dport 80 -j DNAT --to-destination 10.99.99.50
# iptables-save | grep -v ^#
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -d 1.1.1.6/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.99.99.50
-A POSTROUTING -j SNAT --to-source 1.1.1.6
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
# conntrack -E
[NEW] tcp 6 120 SYN_SENT src=198.51.100.101 dst=1.1.1.6 sport=45752 dport=80 [UNREPLIED] src=10.99.99.50 dst=1.1.1.6 sport=80 dport=45752
[UPDATE] tcp 6 60 SYN_RECV src=198.51.100.101 dst=1.1.1.6 sport=45752 dport=80 src=10.99.99.50 dst=1.1.1.6 sport=80 dport=45752
[UPDATE] tcp 6 432000 ESTABLISHED src=198.51.100.101 dst=1.1.1.6 sport=45752 dport=80 src=10.99.99.50 dst=1.1.1.6 sport=80 dport=45752 [ASSURED]
虽然可能不清楚,但这意味着预期回复是从 10.99.99.50 到 1.1.1.6(而不是 198.51.100.101):linux-srv对真正连接到它的 IP 地址保持盲目,它总是会看到 1.1.1.6。