palemoky
V2EX  ›  问与答

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

  •  
  •   palemoky · Sep 11, 2021 · 1798 views
    This topic created in 1711 days ago, the information mentioned may be changed or developed.

    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 中就有这样的两个映射关系:

    • 192.168.5.5:54321 <==> 43.1.1.1:443
    • 192.168.5.9:54321 <==> 43.1.1.1:443

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

    Supplement 1  ·  Jul 21, 2023
    今天在看《 TCP/IP 详解:卷 1 》(第二版),在 7.3.1 节提到了我的疑惑。普通的 NAT 确实会存在不同主机相同端口映射冲突的问题,所以现在都用 NAPT 来解决
    https://i.postimg.cc/L80r5n3W/NAT-vs-NAPT.png
    15 replies    2021-09-13 13:28:44 +08:00
    miyuki
        1
    miyuki  
       Sep 12, 2021 via iPhone
    在上层网关 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
        2
    weyou  
       Sep 12, 2021 via Android   ❤️ 1
    现在讲到 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
        3
    sujin190  
       Sep 12, 2021
    源地址变换,自然是源地址映射,你这源地址和目的地址映射看起来当然不对,不同源地址端口映射到公网之后 ip 相同但是端口不同啊,相应的时候目的地址端口就是映射的公网地址端口,一查就知道对应的是哪个内网地址端口了
    Tianao
        4
    Tianao  
       Sep 12, 2021 via iPhone
    首选楼主问的源 NAT ( NAPT ),那我们只讨论源 NAT 。

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

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

    ARP 查 MAC 什么的都有没关系,处理到 IP 层就够了,如果是在硬件路由器上做的,涉及到 CEF 快转、各种硬件 offload 、FIB 及 TCAM 工作原理,就不要乱猜了。
    echo1937
        5
    echo1937  
       Sep 12, 2021
    @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
        6
    palemoky  
    OP
       Sep 12, 2021
    @miyuki
    @weyou
    @sujin190
    @Tianao
    @echo1937
    理解各位说的都映射到同一 IP 的不同端口上,但我同时有另一个疑问,这种方式下,我不确定映射的 IP 是不是只有一个,如果是一个 IP,那可映射的端口号只有 65535-2 个,也就是说只能同时处理 65533 个连接,但局域网内电脑+手机可能有几十台设备,每台设备又会发很多的网络请求,65533 个够用吗?
    miyuki
        7
    miyuki  
       Sep 12, 2021 via iPhone
    @palemoky 如果足够多的设备都去请求同一个外网端口的话,确实存在这个问题
    Tianao
        8
    Tianao  
       Sep 12, 2021 via iPhone
    @palemoky #6 可以是一个,也可以是多个(一个池)。即使只有一个外网 IP,给几百台终端也是够用的。此外,你可以选择更激进的老化策略,也可以使用完全锥形节省源端口。
    FieldFarmer
        9
    FieldFarmer  
       Sep 12, 2021 via Android
    @palemoky 对于拥有一个 ipv4 地址的客户机来说,的确是最大不能超过 65535 同时去连某一个服务器的端口,只能通过增加 ip 的方式来解决这类问题,不过日常生活中很少会遇到在一个 ipv4 的公网 ip 下,需要这么多的长连接去访问同一个服务器的端口,大多数时间都是短连接,用完马上释放。
    你这个问题类比于 ipv4 不够用了怎么办。
    echo1937
        10
    echo1937  
       Sep 12, 2021 via iPhone
    @palemoky 楼上几位已经做了进一步解释,比如增加 ip 成为 ip 池,调整老化时间等等。

    实际日常过程中普通设备能保持的 nat 会话数很有限,一般三四千个就到头了,反倒这个问题是先遇到的。
    FieldFarmer
        11
    FieldFarmer  
       Sep 12, 2021 via Android
    @Tianao 同一 ip 区域下的 5 万多台终端在同一段时间使用了 tcp 连接同一服务器的同一端口,才会出现不够用的情况。
    这种概率会有多大?即便真的出现了,也不过是出现拥塞现象,待其他的设备释放连接,网络即可恢复。
    相反服务端出现这种情况次数更多,比如某博炸了,某宝卡了,这种没办法大多数情况下只能增加服务器数量。
    FieldFarmer
        12
    FieldFarmer  
       Sep 12, 2021 via Android
    @echo1937 从来都只有服务器考虑并发情况连接太多处理不过来,没见过客户端担心客户端太多导致自己排不上队的。。。。
    palemoky
        13
    palemoky  
    OP
       Sep 12, 2021 via iPhone
    @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
        14
    FieldFarmer  
       Sep 12, 2021
    @palemoky 普通的路由上面,应该是没有查看的功能的,一些软路由上面应该可以,关键字:linux 查看 nat 映射表
    zemul
        15
    zemul  
       Sep 13, 2021
    ngrok
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3139 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 44ms · UTC 11:11 · PVG 19:11 · LAX 04:11 · JFK 07:11
    ♥ Do have faith in what you're doing.