1. 先从一张“共享上网”的拓扑说起
很多人问NAT到底是什么,其实你家里那台路由器就已经在跑了。光猫拨号拿到一个公网IP,手机、电脑、电视全部走这个IP出去,运营商看到的永远是那个公网地址,这就是最基本的NAPT。不过NAT在真实场景里要复杂得多,尤其是涉及SNAT、Connection Tracking(连接跟踪)和Session Persistence(会话保持)时,很多细节踩过坑才理解得了。
我最早接触NAT是在做企业出口设备替换的时候,一个几百人的办公网要切换到新的防火墙,领导给的期限是周五晚上到周一早上。结果切换当晚就出问题:内网用户访问部分银行网站时频繁掉线,明明路由和策略都放通了,日志里却全是NAT会话被重置的记录。后来排查到根因是连接跟踪表老化时间太短,长连接被中途切断,而银行那边的防火墙又因为会话状态不匹配,直接把包丢了。那次之后我彻底把NAT的这几块机制啃了一遍,今天这篇就当作一个系统性的复盘。
这篇文章适合谁看?一个是刚入门网络、对NAT只有概念性认知的工程师,另一个是在做企业网或数据中心运维、被偶发丢包和会话异常折磨过的人。我会从SNAT的转换逻辑开始,讲到连接跟踪表如何工作,再展开会话保持为什么不能盲目依赖,最后给你一组可落地的排查命令和配置建议。全程用真实拓扑和命令行记录的方式来讲,读完你至少能独立复现一次“NAT只能进不能出”这种经典故障的根本原因。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. NAT的整体处理模型:一次数据包要过几道关
2.1 NAT不是“改个IP”那么简单
很多教程会把NAT画成一个盒子:进来一个包,把源IP改掉,扔出去。这个说法没错,但掩盖了关键问题——回程包怎么知道该转给谁?
举例说明。内网主机 192.168.1.100 访问外网服务器 8.8.8.8,经过出口路由器时,源IP被改成 100.64.0.1(假设是运营商分配的地址),同时源端口从 12345 被改成 50000。服务器回包时,目的地址是 100.64.0.1:50000,这台出口路由器必须能反查出一张表——这个地址对应的是 192.168.1.100:12345。这张表,就是NAT的核心状态。
所以说,一次完整的NAT流程至少包含五个环节:连接发起、转换查询、源地址替换、回程反查、老化回收。任何一个环节出问题,表现都是“能发包出去但收不到回包”。按照 Linux 内核 netfilter 的处理顺序,NAT 的钩子点分布在 PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING 五条链上,其中 SNAT 发生在 POSTROUTING,DNAT 发生在 PREROUTING。这一点决定了你可以用 iptables 的 raw 表跳过连接跟踪,但代价是NAT也无法工作。
2.2 状态表与流量的“双向绑定”
NAT能运作的根基,是它把一对双向的包关联成了同一个“连接”。这里说的连接不是TCP那种握手建立的概念,而是一个四元组:协议、源IP、源端口、目的IP、目的端口。对UDP也一样处理,因为连接跟踪并不依赖TCP状态机,它强制为所有IP流量都建立状态条目。
我这里用一个生活化类比:连接跟踪表就像一个前台登记簿。每一个内网用户出门办事,前台记下“这个人住在3栋502,今天穿了红衣服出去”。等外面有人找“穿红衣服的人”,前台一翻登记簿,就知道要带去3栋502。如果没有这个登记簿,回程包到了门口只会一脸茫然。
所以NAT转换和连接跟踪不是两个独立的功能,而是耦合在一起的一个状态机。SNAT修改数据包后,一定会把转换关系写入连接跟踪表;回包时,内核先查询conntrack表,命中后再执行反向NAT。这也解释了为什么很多防火墙设备会把“允许已建立连接”和“允许新连接”分开配置——ASPF(防火墙状态检测)本质上就是在用连接跟踪表做会话方向的判定。
2.3 为什么说NAT破坏了“端到端透明性”
写这节之前我特意查了相关热搜词,“nat测试”“华为静态nat实验”“ensp动态nat”这类词暴露了一个很典型的学习痛点:大家在做实验时,NAT能通,也能看到转换条目,但一旦涉及“内网主动访问外网”和“外网主动访问内网”的双向互通,就开始混乱。
这背后的根本原因在于,NAT改变了IP数据包的语义。原本IP协议假设每个IP都代表一个唯一的终端,但NAT之后,一个公网IP背后可能挂着几百个内网设备,应用层协议压根感知不到这一点。FTP的主动模式为什么在NAT后面会挂?因为FTP控制连接里携带了内网IP地址,数据连接需要另行建立,而旧式NAT不会去解析FTP载荷。这个问题的标准解法是ALG(应用层网关),也就是让NAT设备能识别并改写特定协议的载荷内容。华为设备上的 nat alg 和 Linux 下的 nf_nat_ftp 模块,干的就是同一件事。
了解了整体模型之后,下面分三块讲具体机制。
3. SNAT的落地细节与常见误区
3.1 SNAT与MASQUERADE到底怎么选
SNAT的核心动作,是把报文的源地址(有时连带源端口)改写成指定IP。Linux iptables 里对应规则是:
bash复制iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 100.64.0.1
这条规则的意思是:凡是来自 192.168.1.0/24、从 eth0 出去的包,源地址一律改成 100.64.0.1。此时内核会在路由之后、真正发送之前执行改写,同时记录在conntrack表里。
而MASQUERADE与SNAT的区别在于,MASQUERADE不指定固定源IP,它会自动选择出口接口的当前IP:
bash复制iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o pppoe-wan -j MASQUERADE
这两条命令,很多教程会告诉你“MASQUERADE适合拨号场景,因为IP会变”,但真正的原因值得多说一句:SNAT如果指定了一个本机不存在的IP,包发出去后回程路由根本不会走到这台设备。MASQUERADE每次发包时都会查询出口接口的当前地址,所以对动态拨号是天然安全的。代价是每条新连接的建立都要多一次路由查找,但这点性能损耗对家用和中小型网络可以忽略。硬要选型的话,固定IP用SNAT,动态出口用MASQUERADE。
3.2 端口复用与连接数限制
很多人没想过一个问题:内网有500台设备同时上网,出口只有一个公网IP,那端口够用吗?TCP的端口范围是0到65535,出去一个连接占一个源端口,那岂不是最多只能支持六万多个连接?
实际上NAT设备会在做源地址转换的同时,做源端口转换。也就是说,内网100台机器,哪怕大家访问的都是同一个目标服务器的80端口,NAT设备也可以给每台机器分配不同的源端口,从而用同一个公网IP加一堆不同端口来区分会话。这就是NAPT(网络地址端口转换),也是目前所有家用路由和防火墙的默认模式。
但这里有一个很容易被忽略的坑:端口耗尽。如果内网有大量P2P下载、视频会议、长连接应用,一张公网IP最多同时维护约六万个活跃连接(除去系统保留端口),这还没算TIME_WAIT状态占用的部分。解决思路一般有三个方
