公网数据包如何通过 NAT 传递给内网的程序?

2021-09-11 23:57:53 +08:00
 palemoky

NAT 为了减缓 IPv4 的消耗而被广泛应用,比如最常见的家庭局域网。

假设我 192.168.5.5 访问 43.1.1.1 的公网资源,请求数据包经过 NAT 的时候我理解会改写 IP 层的源主机 IP 地址,将内网 IP 改为公网 IP, 此时 NAT 维护了 192.168.5.5:54321 <==> 43.1.1.1:443 这样的映射关系,然后数据包就在公网传递。现在的问题是,响应数据包到了 NAT 是如何处理的?是通过查询到响应报文中有 43.1.1.1:443,再去 NAT 映射关系中查到 192.168.5.5:54321,然后通过 ARP 再查到对应主机的 MAC 地址交付数据包吗?如果是这样,就会有一个问题,假设另一个设备 192.168.5.9 也访问了 43.1.1.1:443,恰巧客户端端口号也是 54321,那此时 NAT 中就有这样的两个映射关系:

那 43.1.1.1:443 的响应报文此时 NAT 如何正确投递呢?当连接释放时,NAT 也会删除对应的映射关系吗?还是通过有效期等淘汰机制清理呢?

1348 次点击
所在节点    问与答
15 条回复
miyuki
2021-09-12 00:09:03 +08:00
在上层网关 192.168.1.1 (假设)会被继续 NAT
比如 192.168.1.1 的上级 ip 是 1.2.3.4,192.168.5.5 的数据包 NAT 到从 1.2.3.4:5000 出去到 43.1.1.1:443,195.68.5.9 从 1.2.3.4:5001 出去到 43.1.1.1:443
weyou
2021-09-12 00:10:40 +08:00
现在讲到 NAT 大多数是 NAPT(Network Address Port Translation),就是加入端口映射的 NAT 。所以你例子中的映射关系里会有一个外部端口,当发生你所说的内网有多台设备用相同的源端口出去的话,会发生 NAT 外部源端口的改变,比如:
192.168.5.5:54321 <=>ext port 54321<=>43.1.1.1:443
192.168.5.9:54321 <=> ext port 54322<=>43.1.1.1:443
这样对于响应包如何进来的就一目了然了
sujin190
2021-09-12 00:19:12 +08:00
源地址变换,自然是源地址映射,你这源地址和目的地址映射看起来当然不对,不同源地址端口映射到公网之后 ip 相同但是端口不同啊,相应的时候目的地址端口就是映射的公网地址端口,一查就知道对应的是哪个内网地址端口了
Tianao
2021-09-12 00:34:02 +08:00
首选楼主问的源 NAT ( NAPT ),那我们只讨论源 NAT 。

转换后的源端口可以作为标识,比如 5.5 转出去是源端口还是 54321,5.9 转出去就是 54322 了(具体是多少取决于源端口保持策略),这样就不存在源端口复用的情况。至于转换后的源端口标识的是特定的内网主机呢,还是的特定连接呢,这取决于 NAPT 策略(完全锥形、对称型等)。部分特殊应用( SIP 、FTP 等)还有 ALG 辅助。

映射关系释放、老化问题,会以 TCP FIN ALG 等作为老化时机和时间的参照和辅助(加速老化等),也有针对半连接等情况的兜底老化(不然就相当于内存泄漏了),但具体都取决于软件实现和参数配置,没有协议规范。

ARP 查 MAC 什么的都有没关系,处理到 IP 层就够了,如果是在硬件路由器上做的,涉及到 CEF 快转、各种硬件 offload 、FIB 及 TCAM 工作原理,就不要乱猜了。
echo1937
2021-09-12 00:37:33 +08:00
@weyou #2 2 楼的说法是正确的。

你说的这种情况叫做 PAT ( port-address-translation )是端口地址转换。
具体内容可以查看 https://zh.wikipedia.org/wiki/%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%8D%A2
palemoky
2021-09-12 00:57:02 +08:00
@miyuki
@weyou
@sujin190
@Tianao
@echo1937
理解各位说的都映射到同一 IP 的不同端口上,但我同时有另一个疑问,这种方式下,我不确定映射的 IP 是不是只有一个,如果是一个 IP,那可映射的端口号只有 65535-2 个,也就是说只能同时处理 65533 个连接,但局域网内电脑+手机可能有几十台设备,每台设备又会发很多的网络请求,65533 个够用吗?
miyuki
2021-09-12 01:04:26 +08:00
@palemoky 如果足够多的设备都去请求同一个外网端口的话,确实存在这个问题
Tianao
2021-09-12 01:08:53 +08:00
@palemoky #6 可以是一个,也可以是多个(一个池)。即使只有一个外网 IP,给几百台终端也是够用的。此外,你可以选择更激进的老化策略,也可以使用完全锥形节省源端口。
FieldFarmer
2021-09-12 02:01:15 +08:00
@palemoky 对于拥有一个 ipv4 地址的客户机来说,的确是最大不能超过 65535 同时去连某一个服务器的端口,只能通过增加 ip 的方式来解决这类问题,不过日常生活中很少会遇到在一个 ipv4 的公网 ip 下,需要这么多的长连接去访问同一个服务器的端口,大多数时间都是短连接,用完马上释放。
你这个问题类比于 ipv4 不够用了怎么办。
echo1937
2021-09-12 02:08:33 +08:00
@palemoky 楼上几位已经做了进一步解释,比如增加 ip 成为 ip 池,调整老化时间等等。

实际日常过程中普通设备能保持的 nat 会话数很有限,一般三四千个就到头了,反倒这个问题是先遇到的。
FieldFarmer
2021-09-12 02:09:59 +08:00
@Tianao 同一 ip 区域下的 5 万多台终端在同一段时间使用了 tcp 连接同一服务器的同一端口,才会出现不够用的情况。
这种概率会有多大?即便真的出现了,也不过是出现拥塞现象,待其他的设备释放连接,网络即可恢复。
相反服务端出现这种情况次数更多,比如某博炸了,某宝卡了,这种没办法大多数情况下只能增加服务器数量。
FieldFarmer
2021-09-12 02:13:41 +08:00
@echo1937 从来都只有服务器考虑并发情况连接太多处理不过来,没见过客户端担心客户端太多导致自己排不上队的。。。。
palemoky
2021-09-12 08:33:58 +08:00
@FieldFarmer 所以说访问 43.1.1.1:443 会在 NAT 新增映射 192.168.5.5:54321 <==> 43.1.1.14:569,访问 44.2.2.2:443 会新增 192.168.5.5:49856 <==> 44.2.2.2:1443 ?如果这样,确实局域网内同时访问同一 IP 的同一端口是极端情况。
我尝试直接看华硕路由器和 FriendlyWRT 的 NAT 表,但查了半天资料都没找到怎么看
FieldFarmer
2021-09-12 11:20:07 +08:00
@palemoky 普通的路由上面,应该是没有查看的功能的,一些软路由上面应该可以,关键字:linux 查看 nat 映射表
zemul
2021-09-13 13:28:44 +08:00
ngrok

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/801291

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX