为什么 NAT 不从机器的 TCP 和 UDP 端口池中保留端口?

Yd *_*hrk 8 networking iptables nat

我做了两个实验。这是他们俩的网络:

        [private network]     [public network]
    A -------------------- R ----------------- B
192.168.0.5     192.168.0.1|192.0.2.1       192.0.2.8
Run Code Online (Sandbox Code Playgroud)

一个的默认网关[R R有 IPv4 转发活动和以下 iptables 规则:

iptables -t nat -A POSTROUTING -p TCP -j MASQUERADE --to-ports 50000
Run Code Online (Sandbox Code Playgroud)

目的是,来自A 的任何 TCP都将使用R的端口 50000屏蔽为 192.0.2.1 。

我在B上的端口 60000 上使用nc -4l 192.0.2.8 60000.

然后我从A打开了一个连接:nc -4 192.0.2.8 60000

A开始发送如下所示的数据包:

192.168.0.5:53269 -> 192.0.2.8:60000
Run Code Online (Sandbox Code Playgroud)

R将其翻译成

192.0.2.1:50000 -> 192.0.2.8:60000
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。

然后我试图打开下面的客户端- [R :nc -4 192.0.2.8 60000 -p 50000。 我发了消息,没有任何反应。在R的 tcpdump上看不到数据包。

因为伪装规则存在,或者至少因为它处于活动状态,我本来希望R的 nc 失败并显示错误消息“nc:地址已在使用中”,如果我将两个 nc 绑定到同一个端口,就会发生这种情况。

然后我等了一会儿,这样 conntrack 的映射就会消失。

第二个实验包括我首先尝试打开R的客户端。R开始与B交谈就好了。如果我然后从A打开连接,它的数据包将被忽略。A的 SYN 到达R,但它们没有得到答复,甚至 ICMP 错误也没有答复。我不知道这是因为R知道它的伪装端口用完了,还是因为 Linux 完全被搞糊涂了(它在技术上屏蔽了端口,但已经建立的连接以某种方式干扰了)。

我觉得 NAT 的行为是错误的。我可能不小心为伪装(特别是--to-ports在 iptables 规则期间未指定)和服务配置了一个端口,内核将默默地丢弃连接。我也没有在任何地方看到任何记录。

例如:

  • AB发出正常请求。使用端口 50k 的R掩码。
  • AR进行 DNS 查询。由于T是递归的,R(纯属巧合,使用临时端口 50k)在端口 53 上查询权威名称服务器Z。

刚刚发生了碰撞;R现在使用端口 50k 进行两个独立的 TCP 连接。

我猜这是因为您通常不会在路由器上发布服务。但是话又说回来,当它被主动伪装时,它会伤害内核从 TCP 端口池“借用”端口吗?

我知道我可以将临时端口与--to-ports. 但是,这似乎不是默认行为。NAT 和临时端口都默认为 32768-61000,这令人毛骨悚然。

(我通过查询 /proc/sys/net/ipv4/ip_local_port_range 找到了临时范围,并通过在单独的实验中简单地对大量 UDP 请求进行 NAT 来找到 NAT 范围 - 并在服务器端打印源端口。我找不到一种使用 iptables 打印范围的方法。)

Yd *_*hrk 2

当内核主动伪装时,从 TCP 端口池“借用”端口会伤害内核吗?

我想答案是“不,但这并不重要”。

我错误地认为R仅使用响应数据包的目标传输地址来判断它是前往A还是其自身。它实际上似乎使用整个源-目标传输地址元组来标识连接。因此,NAT 使用同一个( R拥有的)端口创建多个连接实际上是正常的;它不会造成任何混乱。因此,TCP/UDP 端口池并不重要。

现在我想起来,这是非常明显的。

然后我尝试在R上打开以下客户端:nc -4 192.0.2.8 60000 -p 50000。我发了消息,什么也没发生。在R的 tcpdump上看不到任何数据包。

这是我搞砸的实验部分。

发生故障是因为源传输地址目标传输地址相同,而不仅仅是因为源地址相同。

如果我这样做,说,nc -4 192.0.2.8 60001 -p 50000它确实有效。即使它使用与 NAT 掩码相同的端口。

我觉得NAT的行为是错误的。我可能会意外地为伪装(特别是在 iptables 规则期间未指定--to-ports)和服务配置端口,并且内核将默默地删除连接。

不会,因为屏蔽连接和R启动的连接很可能具有不同的目的地。

因为伪装规则存在,或者至少因为它处于活动状态,所以我预计R的 nc 会失败,并显示错误消息“nc:地址已在使用中”,如果我将两个 nc 绑定到同一端口,就会发生这种情况。

我仍在寻找对此问题的可靠答案,但一切似乎都表明“这是其实施方式的不利后果,而且它很小,我们愿意忍受它。”