网络地址转换NAT:会话表、端口复用与排障实战 翻到这一章说明前面的路由表、子网划分、报文转发流程已经打过一遍底了。网络地址转换这个题目初学者往往觉得简单——不就是把私网地址换成一个公网地址吗可真到生产环境里出问题能让人连加三个小时班语音通了视频不通、内部员工访问不了自己公司发布在公网的业务、大并发下莫名其妙丢连接、抓包看到源地址怎么都对不上。我做了这么多年网络与系统这块见过太多配置看起来没问题、就是不通的现场九成情况下问题不在路由而在对NAT的转换时机、转换方向和会话状态理解得不够细。这一章我想做的事情是把网络地址转换从背概念拉到能干活的层面。不管你是刚入门、手上只有一台虚拟机做实验的新手还是已经在维护出口设备、被会话数和端口耗尽折腾过的老手下面这些内容都应该能对得上号。我会先从它究竟改写了什么讲起再把会话表这个核心机制拆开然后给一套完全可以在自己电脑上复现的实验配置接着按场景拆解选型和配置思路最后拿一整节讲排障——那部分是我个人觉得最值钱的东西因为教科书里基本不写。先给个整体判断NAT不是地址翻译它是会话状态的重写。你把这句话记牢后面九成的疑难杂症都能顺着这条线摸出来。1. 拆开NAT的外壳它到底在解决什么、改了什么1.1 地址不够用只是表层原因一说NAT几乎所有资料第一句都是为了缓解IPv4地址枯竭。这话没错但它只解释了一半。如果只是地址不够那我们把内网全部用保留地址段、出口做一对一映射就够了为什么实际工程里绝大多数用的是端口级复用PAT/NAPT几十上百个内网终端挤在同一个公网地址上因为真正的驱动力是三件事叠在一起公网地址成本、内网编址的自由度、以及隐藏内部拓扑带来的附加好处。我先说地址成本。早年公网地址还算宽裕一条出口给一个地址段不稀奇后来地址段越来越紧运营商给小企业客户的往往就是一个固定地址甚至动态地址。在这种条件下一对一映射根本撑不住几十台终端的并发访问必须靠端口维度做复用。这是PAT成为默认形态的直接原因。再说编址自由度。这条常被忽略但工程价值极高。内网你想怎么规划就怎么规划——按部门划段、按楼层划段、按业务划段完全不用考虑和公网地址冲突。将来换运营商、换地址段只需要动出口那几条转换规则内网一行配置都不用改。我经历过一次出口迁移就是因为前期内网规划得干净、NAT规则集中在出口设备上整个过程只花了半小时相反我见过内网直接拿公网段编址、没有做任何转换的环境改一次地址等于把整个园区重做一遍。第三点是隐藏拓扑。外部只能看到出口地址看不到里面有几台机器、怎么分段。这属于附带收益不该当成安全机制来宣传——真正做访问控制还得靠策略但客观上它确实减少了被扫描到的面。所以你在做方案的时候别只盯着地址够不够要把这三条一起摆上桌够不够用、要不要保留内网规划的弹性、出口地址是固定还是动态。这三条基本决定了你后面该选哪种形态。1.2 NAT改写的三个字段理解NAT最有效的方式不是记类型而是记住它动了报文里的哪几个字段。翻来覆去就三个源IP、目的IP、以及传输层的端口号。任意一种NAT形态都是这三个字段的重写组合。先说源地址转换SNAT。内网终端发包出去出口设备把源IP从私网地址改成公网地址同时——注意这个同时——把源端口也改掉并在自己的会话表里记一条映射内网 192.168.10.15:51234 对应 公网 203.0.113.10:40001。回包回来时目的地址是 203.0.113.10:40001设备查表改回 192.168.10.15:51234 送进内网。整个过程对两端主机完全透明它们都以为自己只是在和一个普通对端通信。这也是为什么很多人第一次抓包会懵在终端上抓到的源地址和在出口外侧抓到的源地址根本不是一个中间那一跳就是NAT。再说目的地址转换DNAT。外部用户访问 203.0.113.10:8443出口设备按规则把目的地址改成 192.168.10.20:443转发进内网。这里有个关键点容易被忽略DNAT之后回程必须做SNAT否则内网服务器看到源地址是外部真实地址它会直接把回包交给自己的默认网关——如果网关恰好不是做转换的那台设备回包路径就断了。所以你在设备上做发布服务通常要成对配置进来的做目的转换出去的回程做源转换。这条规则我在第五章还会再展开因为它是服务发布不通最常见的原因之一。端口重写则是PAT的精髓。一个公网地址理论上能提供六万多个端口严格说是 65535 减去保留段这就是单个地址能承载的并发会话上限。后面 2.3 节我会把这条边界算给你看。1.3 四种形态与选型对照把三个字段的组合穷举一下工程上常用的就是下面四类。我用一张表把它们的适用面、代价和典型误用摆出来这张表你可以直接拿去当选型参考。形态改写的字段映射关系适合场景常见误用静态一对一源或目的IP固定IP对固定IP需要固定出口地址的服务器、需被外部主动访问的主机用在小办公出口白白浪费公网地址动态地址池源IP多内网地址对多公网地址先到先得公网地址略多于并发主机数的场景地址池比并发数少导致后来者无法建连端口级复用PAT源IP源端口多内网地址对同一公网地址的不同端口绝大多数互联网出口大并发下端口耗尽却不自知目的转换端口映射目的IP目的端口公网IP:端口 对 内网IP:端口内网服务对外发布只做DNAT不做回程SNAT服务发布不通这里头需要多说两句的是动态地址池。它现在用得越来越少原因很现实地址池的本质是分时复用池子里有几个地址同时最多就只能有几个内网主机上网。一旦池子被占满后面的主机建连直接失败而且失败得很隐蔽——用户只看到网页转圈没有任何报错。我见过一个环境配了 8 个地址的池子部门扩到 40 人之后天天有人投诉上不了网查了半天才发现是这个原因。所以我个人的做法是除非明确需要多个固定出口地址比如对接只认地址白名单的外部系统否则一律直接上PAT简单、稳定、不给自己挖坑。还有一种情况要单独提醒目的转换和源转换可以同时出现在一条会话上也就是所谓双向NAT。最典型的场景是内网用户通过公网地址访问内网服务器专业上叫hairpin或回流以及两侧地址段重叠时的互访。这两块我放在 4.5 节细讲因为配置上差一个细节就不通而且不通的表现很容易误导排查方向。2. 摸清内部机制会话表、转换方向与端口分配2.1 会话表是NAT的心脏如果让我只保留一个关于NAT的知识点我会选会话表也叫连接跟踪表。它是一条条记录形如五元组A 映射到 五元组B状态、超时时间、使用计数。所有转换动作本质都是查这张表、改字段、再转发。这张表有三个特性直接决定了你在生产环境里会遇到什么问题。第一它是有状态的。第一个包进来时创建表项后续包命中表项直接转发不再逐包做规则匹配。这意味着两件事一是性能上比逐包查规则高得多二是表项一旦被异常清除正在传输的连接会立刻断掉。我遇到过有人为了清理一下直接重启了防火墙模块结果整个园区的视频会议全断就是因为会话表被清空了而重新建表需要时间。第二它是有容量上限的。设备的内存和会话数是有对应关系的几万到几百万不等。超限之后新连接直接被丢弃老连接可能被强制老化。这个上限在中小设备上很容易被触碰尤其是在有扫描流量、P2P流量、或者大量短连接的业务场景下。第三它有老化时间。不同协议的老化时间不一样TCP建立后通常较长常见几小时TCP半开较短UDP更短几十秒到几分钟。这个差异带来一个经典问题长连接的UDP应用比如某些心跳类业务如果心跳间隔大于老化时间中间的映射表项会被清掉后续包就被当成新连接处理表现为每隔一段时间就闪断一次。这个现象特别难查因为你在终端侧什么都看不出来。所以排查NAT问题第一个动作永远是看会话表而不是猜。2.2 转换发生在哪一跳转换发生的时机比转换规则本身更容易出错。原则上是源地址转换发生在报文离开内网侧接口时目的地址转换发生在报文进入内网侧接口前。这句话听着绕画到具体路径上就清楚了。假设设备有两个接口内网侧连接 192.168.10.0/24和外网侧203.0.113.10。内网终端访问外网报文先到内网侧接口此时做的是判断是否需要进行源转换的标记报文准备从外网侧发出时才真正执行源地址重写。反过来外网进来的报文先在外网侧接口被目的转换规则命中改成内网地址然后转发到内网侧接口。为什么顺序这样设计因为设备需要先知道这个报文要去哪里才能决定往哪个方向做转换。如果顺序搞反会出现转换了但路由不出去、或者路由出去了但没转换的情况。工程上有两个由此衍生的坑值得单独提。坑一转换规则和路由必须对得上。我见过一种配置DNAT把目的地址改成了 192.168.20.20但设备上的路由表里 192.168.20.0/24 指向的是另一台设备结果报文被转换后又被送回了错误的方向形成环路或者直接丢弃。查这种问题先看路由再看规则顺序别反。坑二同一台设备上的接口方向标记要准确。有些设备的配置里需要显式指定内网侧和外网侧标错了就会出现CPU跑满但流量不通的诡异现象——因为报文在两个方向上都匹配不到转换规则一直走慢路径。2.3 PAT端口分配与耗尽的真实边界这一节我想算点具体的数因为端口会耗尽这句话大家都会说但多数人不知道边界在哪也就不知道该不该担心。一个公网IPv4地址传输层端口是16位范围 0 到 65535共 65536 个。实际可用要扣掉 0 到 1023 这段知名端口虽然做转换时技术上可以用但为了避免和对端服务端口冲突绝大多数实现会避开、以及实现上的保留段。粗略按64000 个可用端口估算是工程上常用的口径。关键在这里这 64000 个端口是按目的地址目的端口分别计数的不是全局共享。也就是说内网终端访问 198.51.100.10:443这一组映射最多约 64000 条并发同时访问 198.51.100.11:443又是另外 64000 条访问同一台服务器的不同端口也是分开算的。所以真正会出现端口耗尽的场景是大量内网终端同时挤向同一个目的IP、同一个目的端口。最典型的是所有人都访问同一个云服务商的同一个服务地址或者大量终端同时向同一个更新服务器拉包。再叠加一个因素TCP的TIME_WAIT。连接正常关闭后端口不会立刻释放要等一段时间通常几十秒到两分钟。如果业务是大量短连接、高频建连的模式比如老式的短轮询接口、某些监控上报那么有效可用端口会被大量TIME_WAIT占用实际并发能力远低于 64000。我见过一个极端案例某业务每秒建几百个短连接访问同一个外部接口不到半小时就把出口地址的端口打满了表现是新连接请求全部超时而链路带宽只用了不到 5%。怎么缓解我按优先级给几个手段一是加公网地址用地址池把压力摊开这是最直接的二是优化应用侧建连方式改成连接复用、长连接、或者加本地缓存减少外部请求这治本三是调整TIME_WAIT回收策略这个要谨慎改过头会影响连接可靠性四是限制单主机的并发防止个别终端把端口吃光。这里顺带说一句排查手法当你怀疑端口耗尽时看设备上当前会话数/规格上限以及单个公网地址的映射数这两个数字比看带宽利用率有用得多。2.4 ALG那些被协议坑过的场景有一类协议光改IP和端口是不够的因为它把地址信息写在了应用层的载荷里。最典型的是FTP控制连接建立后双方会通过PORT或PASV命令协商数据连接的地址和端口。如果只做三层四层的转换控制连接能通但载荷里的地址还是私网地址对端根本没法连——于是就出现了那个经典现象能登录但列不出目录、传不了文件。这种场景就需要ALG应用层网关介入它会在转换报文头的同时顺带改写载荷里的地址字段。类似的协议还有SIP语音信令里带着媒体地址、某些数据库或管理协议、以及一些老式的多媒体协议。ALG这东西我的态度很明确能用就别关但一定要知道它会带来什么副作用。副作用主要有两个。一是它增加了设备对应用层内容的解析负担某些实现里ALG会显著拉低转发性能二是它对协议的解析不一定完备遇到加密的信令比如加密的SIP就完全失效这时候只能靠其他办法——比如让服务器侧直接配置公网地址、或者用专门的会话边界设备。还有一个非常隐蔽的坑ALG改写了载荷但应用层有自己的完整性校验。某些协议会对载荷做签名或者哈希ALG一改校验就失败连接被对端拒绝。这种问题抓包看是连接建立成功、随后立刻被RST非常难定位。我的经验是新上一类业务先在测试环境单独验证重点看它有没有在载荷里带地址有的话就专门测一遍。到这里第一章的为什么和改了什么就算讲完了。接下来我把它落到具体操作上。3. 动手搭一套可复现的NAT实验3.1 拓扑与地址规划纸上谈兵没意义我给一套你在自己电脑上就能搭出来的环境。用虚拟机或者容器都行三台就够一台当内网终端一台当出口设备一台当外部服务端。地址规划我全部用文档保留地址段避免和你现有环境冲突角色接口地址说明内网终端eth0192.168.10.15/24网关 192.168.10.1模拟普通办公终端出口设备eth0内网侧192.168.10.1/24内网网关出口设备eth1外网侧203.0.113.10/24网关 203.0.113.1模拟公网地址内部服务器eth0192.168.10.20/24网关 192.168.10.1模拟对外发布的服务外部服务端eth0198.51.100.50/24网关 198.51.100.1模拟互联网上的对端这套规划的好处是地址段是标准保留的不会和你家里的路由器撞同时把内网服务器和内网终端放在同一网段方便后面演示hairpin回流。第一步永远是打开转发。这一步漏了后面所有配置都白做而且现象是内网能ping通网关但出不去非常容易误判成NAT规则写错了。sysctl -w net.ipv4.ip_forward1 # 永久生效写进配置文件 echo net.ipv4.ip_forward 1 /etc/sysctl.conf sysctl -p注意在容器里做实验时转发开关可能是隔离的命名空间级配置宿主机开了不代表容器里开了要在容器内部再确认一次。3.2 用netfilter实现SNAT与DNAT我选Linux上的netfilter做演示原因很简单它规则透明、日志清晰、每台机器都能跑不像专用设备那样黑盒。理解了这里的机制换到任何设备上都是同一套思路只是命令写法不同。先做最基础的源地址转换让内网终端能上网# 老一点的写法用iptables iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth1 -j SNAT --to-source 203.0.113.10 # 出口地址是动态的时候用MASQUERADE自动取接口地址 iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth1 -j MASQUERADE这两条的区别值得说清楚SNAT --to-source是写死一个地址适合固定地址出口MASQUERADE是每次动态读取出口接口的地址适合拨号或动态分配的场景代价是每次都要查接口地址性能略低一点点。出口地址固定就用SNAT动态才用MASQUERADE这是个习惯问题但养成之后能避免地址变了规则不跟着变的故障。同样的规则用nftables写语法更现代nft add table ip nat nft add chain ip nat postrouting { type nat hook postrouting priority srcnat; } nft add rule ip nat postrouting ip saddr 192.168.10.0/24 oifname eth1 snat to 203.0.113.10接着做目的转换把外部对 203.0.113.10:8443 的访问转到内网服务器的 443iptables -t nat -A PREROUTING -d 203.0.113.10 -p tcp --dport 8443 -j DNAT --to-destination 192.168.10.20:443配完这条从外部服务端去访问 203.0.113.10:8443理论上应该能通。如果通不了按这个顺序查一是确认外部服务端的路由能不能到 203.0.113.10实验环境里经常忘了给外部服务端配网关二是确认内网服务器有没有开监听、防火墙有没有放行三是确认回程——内网服务器的默认网关必须是 192.168.10.1如果它把回包发到别处连接就建立不起来。第三种情况我要重点提醒因为它和直觉相反。很多人以为DNAT做完就完事了实际上报文被送进内网后服务器看到的源地址是 198.51.100.50它回包的目的地址就是 198.51.100.50走默认网关出去正好经过出口设备此时出口设备查到会话表里有这条记录会把源地址改回 203.0.113.10——这个过程是自动的不需要额外配SNAT前提是回程路径经过同一台设备。但如果内网服务器有多个网卡、或者回程走了另一条链路会话表就查不到回包会带着内网地址直接出去被上游丢弃表现为外部访问超时、服务器侧看连接已建立。这种单通现象极其常见我的处理原则是做DNAT的环境一定要保证回程对称做不到对称就得显式加一条SNAT把回程拉回来。3.3 hairpin回流与端口映射现在有个新需求内网终端 192.168.10.15 想访问自己公司发布在公网的业务输入的是 203.0.113.10:8443。按直觉这条流量从内网侧进、又要从内网侧出应该能被处理。但默认情况下它不通。原因还是会话表和转换顺序。报文从内网侧接口进来目的地址是 203.0.113.10设备按目的转换规则把它改成 192.168.10.20然后要转发回内网侧接口。此时报文源地址还是 192.168.10.15服务器收到后回包给 192.168.10.15走二层直接送达根本不经过出口设备——所以内网终端收到的是一个源地址为 192.168.10.20 的响应而它期望的是 203.0.113.10TCP握手直接失败。解决办法是让回程也必须经过设备也就是在进入内网时再做一次源地址转换把源地址改成设备的内网侧地址这样服务器回包就送到设备设备查会话表再改回去。配置上加一条# 对来自内网的、目的为公网地址的流量做源转换强制回程经过设备 iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -d 192.168.10.20 -p tcp --dport 443 -j SNAT --to-source 192.168.10.1这条规则的作用是内网访问内网服务器时把源地址改成网关地址。看起来多此一举实际上是hairpin能通的关键。注意这条规则要写得足够精确只匹配需要回流的那部分流量。写宽了会波及正常的内网互访导致内网通信全部绕行设备性能下降不说还会引入额外的单点故障。端口映射这块还有个实操细节尽量做端口对端口别做端口对端口段的批量映射。有些管理员图省事把 8000-8100 整段映射进去结果暴露了一堆自己都不知道在跑的服务。我的习惯是一个服务一条规则写清楚注释定期清理。3.4 网络设备侧的配置思路对照前面用netfilter讲机制是因为它把每一步都摊开了。换到专用网络设备上命令长得不一样但逻辑是同一套。我把对应关系列出来你照着套就行要做的事通用配置思路关键关注点内网出口上网定义内网侧/外网侧接口配源转换规则指定出口地址或地址池接口方向标记别搞反地址池容量要大于并发主机数服务对外发布配目的转换公网IP:端口 到 内网IP:端口必要时同步配回程源转换回程对称性安全策略要放行转换后的真实地址双向互访同时配源转换和目的转换转换顺序、匹配精确度多出口选路按源地址或按目的地址分流配合不同转换规则会话粘性避免同一连接来回切链路这里有个经验设备上的安全策略匹配的是转换后的地址。这一点和很多人的直觉相反——他们写了允许访问 203.0.113.10:8443 的策略结果不通因为报文进到策略检查点时目的地址已经被改成 192.168.10.20 了。所以策略要放行真实的内网地址。这个坑我在至少三个不同环境里见过每次都要花时间解释。还有一个部署顺序的建议先在设备上把转换规则和安全策略都写好再做连通性测试不要一边加规则一边测。因为每加一条规则可能改变前面测试的结论混着测很容易得出错误判断。4. 场景化拆解不同需求下怎么选、怎么配4.1 小型出口与家庭网关这个场景的典型特征是出口地址可能是动态的、终端数量在几十台以内、没有人专职维护。这种情况下我的建议非常明确——只用PAT不要碰地址池和静态映射。理由有三条。第一动态地址下做静态映射根本做不了规则会随地址变化而失效除非配合地址变化时的自动更新机制但那又增加了复杂度。第二几十台终端的并发压力完全在单地址的能力范围内前面算过单个地址对单个目的地址的并发上限是六万多日常办公根本摸不到边。第三越简单的配置越不容易出故障而这类环境最怕的就是出了故障没人会修。配置上就是把内网段整体做源转换出口用自动取地址的方式。唯一需要注意的是别把管理地址也一起转换了否则从外部访问管理界面会失效。做法是在规则里排除掉管理网段或者把管理口单独放在一个不做转换的接口上。另外提一句动态地址带来的一个实际问题地址变化后原有的会话表项会失效表现为网断了十几秒又自己好了。这在拨号环境里是正常现象不用当成故障去查。如果业务对断线敏感那就该考虑固定地址了。4.2 多出口链路与地址池企业有一定规模之后常见的是两条出口链路一条主用一条备用或者两条按业务分流。这时候NAT的设计要跟着路由策略一起考虑不能单独看。先说地址池的容量问题。假设两条链路各有一个公网地址内网有两百台终端。如果你给每条链路各配一个地址的池子那么每条链路最多承载六万多条到同一目的的并发正常办公够用但如果业务里有大量短连接访问同一个外部服务就要警惕TIME_WAIT堆积。这种情况我建议直接上多地址池把压力摊开。再说分流。按源地址分流的做法是把内网按部门划成两段一段走链路A、一段走链路B各自的转换规则绑定各自的出口地址。这种做法简单、会话粘性好缺点是流量分布不均时不好调。按目的地址分流更精细但需要维护地址列表而且新业务上线容易漏配。我踩过的一个坑是链路切换时会话中断。主链路断了路由切到备链路但原有的会话表项还绑在主链路的出口地址上这些连接就废了。表现是切换后一部分人能用、一部分人不行非常迷惑。解决办法一是让会话表随链路状态一起清理二是应用侧做重连重试。前者是设备能力问题后者是应用健壮性问题两边都得考虑。4.3 内网服务对外发布服务发布看起来是最简单的需求一条目的转换规则的事。但实际工程里要考虑的东西不少。第一个是端口选择。能不占80/443就不占尽量用高位端口减少被自动扫描命中的概率。这不是安全机制但能显著降低噪音。第二个是只映射必要端口。我见过把整台服务器的所有端口都映射出去的环境理由是方便调试结果半年后发现有台机器上跑着测试用的管理服务一直暴露在外。我的做法是列一张清单写清楚每个映射对应的业务、负责人、开通时间定期复核。第三个是回程的可靠性。前面说过回程必须对称。如果内网服务器有多个网卡做业务隔离一定要确认它的默认路由指向做转换的那台设备或者在做转换的设备上显式加回程源转换。这条我建议写进上线检查清单因为它的故障表现外部超时、内部看连接正常太容易误判了。第四个是日志。服务发布的流量一定要能追溯到源地址。如果做了源转换原始源地址就丢了排查攻击或者异常访问时会很被动。能让设备记录转换前的源地址就一定要记实在不行就在业务侧做应用层日志。4.4 容器与虚拟化环境的NAT容器环境的网络模型本质上就是把NAT做进了宿主机容器有自己的地址空间出宿主机时做源转换外部访问容器时做目的转换。理解了前面几节这里的现象就都好解释了。最常见的困惑是容器里看不到真实客户端地址。因为出宿主机时做了源转换服务端看到的源地址是宿主机的地址。如果业务需要真实客户端地址比如做限流、做地域统计就得改网络模式或者让上游把真实地址通过应用层头部带过来。第二个困惑是容器访问自己映射出去的地址不通。这就是 3.3 节讲的hairpin问题在容器场景的翻版解决方案的思路完全一样让回程也经过做转换的那一层。第三个是端口冲突。宿主机的端口是全局资源两个容器抢同一个宿主机端口就起不来。这个不是NAT的问题但排查时容易往NAT上想。我的经验是容器起不来先看端口占用别急着怀疑网络配置。4.5 地址重叠与双向NAT这个场景比较特殊但一旦遇上就很棘手两个内网用了相同的地址段现在要互访。比如某公司有两个分部都用 192.168.10.0/24现在要打通。直接路由是不行的因为地址冲突。这时候就要在中间做双向转换把A方的 192.168.10.0/24 转换成一个虚拟网段比如 172.16.10.0/24B方访问 172.16.10.x 时中间设备把它转换成对应的 192.168.10.x反过来B方的地址也要做类似转换。配置上有两个要点。一是转换要成对去方向改目的地址回方向改源地址两条规则必须严格对应任何一条写错都会导致单向不通。二是转换后的虚拟网段不能和现有任何网段冲突规划时要留足余量。这种方案我不太推荐长期使用因为它让地址规划变得复杂后续每加一个网段都要维护一堆规则。如果条件允许还是推动一侧做地址重规划一次性解决问题。但在不能改动现有环境的前提下双向NAT是可行的过渡方案。5. 排障实录症状、定位路径与速查表5.1 两个必会动作看会话、抓包遇到NAT相关问题我固定做两个动作顺序不能乱。第一个动作是看会话表。在Linux上就是看连接跟踪表# 看当前的连接跟踪记录 conntrack -L # 只看某个地址相关的 conntrack -L | grep 192.168.10.20 # 统计当前会话总数 conntrack -C在专用设备上通常是类似的会话/连接查看命令。这一步能回答三个关键问题连接有没有建立有表项说明至少有一个方向的包到达过、转换关系对不对表项里的原始五元组和转换后五元组、状态是什么是否卡在半开。第二个动作是在三个点上抓包内网侧、外网侧、以及服务端。三个点的抓包对比基本能把问题锁死。判断逻辑很简单内网侧外网侧结论有请求源地址是内网地址无转换或转发没生效查规则和转发开关有请求源地址是内网地址有请求源地址是公网地址转换正常问题在对端或回程有请求有请求但回包没有从外网侧进来回程路由问题有请求无回包有请求无回包对端没响应或中间被拦抓包的时候记住一件事在做过转换的一侧抓看到的地址和终端上看到的不是一回事这是正常的别以为自己抓错了接口。我见过有同事因为这个怀疑抓包工具坏了浪费了不少时间。5.2 高频故障速查表下面这张表是我这些年整理出来的基本覆盖了八成以上的现场问题。你可以直接拿去当检查单。现象大概率原因快速验证处理方向内网能ping网关上不了外网转发未开启或源转换规则未命中查转发开关看外网侧抓包有无转换后的流量开启转发核对规则的源地址范围和出接口外部访问服务超时内部看已连接回程路径不对称在服务端抓包看回包目的地址修默认网关或显式加回程源转换服务发布后内网用户访问公网地址不通hairpin未处理内网侧抓包看回包源地址增加内网进入时的源转换规则能登录但传不了文件FTP类应用层载荷地址未改写抓包看载荷里的地址字段开启对应协议的ALG或改用被动模式、服务端配公网地址大并发下新连接失败带宽却很低端口耗尽或会话数超限统计单个公网地址的映射数加公网地址、优化建连方式、限制单机并发每隔固定时间闪断UDP老化时间短于心跳间隔对比心跳间隔和老化时间调整老化时间或缩短心跳间隔转换规则看着没问题但不通接口方向标记错误或安全策略匹配的是转换后地址检查接口角色定义检查策略里的地址修正方向策略放行真实内网地址换运营商后部分业务不通出口地址变化静态映射失效核对当前出口地址和规则里的地址静态场景改固定地址或改用动态适配方式5.3 不报错但很折磨人的细节有些问题不会给你任何错误提示只能靠经验。第一个是MTU。做隧道封装或者某些转换场景时报文长度会超出链路MTU需要分片但分片报文可能被中间设备丢弃。表现是小包能通、大包卡住——ping得通网页打开一半、文件传到一定大小就断。标准做法是在转发路径上做MSS钳制iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu这条规则的作用是在握手阶段就把双方协商的MSS值压到路径MTU以下避免后续大包被丢。这个坑我在做跨网络互联时遇到过好几次每次现象都一样登录正常、页面加载到一半卡死。第二个是分片报文的转换。非首片报文里没有传输层头只有IP头如果转换规则依赖端口匹配非首片就匹配不上。正常实现会用会话表把分片关联起来但某些情况下比如分片乱序、或者会话表被清会关联失败。表现是大数据传输丢包、小请求正常。遇到这种情况先确认路径MTU是否合理能不让它分片就别让它分片。第三个是时间同步。这个听起来和NAT没关系但排查时会要命如果设备和日志服务器时间不同步你按时间戳去对齐两边的日志会发现完全对不上。我现在的习惯是做任何跨设备排查之前先确认时间同步正常。第四个是配置正确但顺序错。规则是有匹配顺序的先命中的生效。如果前面有一条宽泛的规则后面的精确规则永远不会被执行。这种问题在规则越加越多之后特别容易出现。我的做法是新增规则时先确认它应该插在哪个位置而不是无脑追加到末尾同时定期做一次规则梳理把失效的、重复的清掉。5.4 我踩过的坑与避坑清单最后分享几条实打实的经验都是踩过之后才记住的。第一条不要在生产环境边配边测。我有一次在出口设备上加服务发布规则加一条测一次结果测到第四条的时候前面三条的表现全变了——因为规则之间的匹配顺序被改变了。后来我改成先把规则全部写完、再统一验证效率反而高。这个习惯一直保留到现在。第二条所有转换规则都要有注释和台账。一条规则写映射8443到内网某服务器半年后没人知道是哪台、干什么用的。我的做法是规则里写清楚业务名另外维护一张表记录业务、负责人、开通时间、审核记录。听起来麻烦但清理和审计的时候能救命。第三条改之前先备份改之后先看会话。配置备份是基本操作但改完看会话这一步很多人省了。改完立刻看会话表能第一时间发现规则写反了导致所有连接重建这种问题比等用户投诉快得多。第四条别用NAT去实现本该用策略做的事。有人喜欢用地址转换来做访问控制比如只有转换到这个地址的才能访问。这种做法隐蔽、难维护、而且容易出安全漏洞。访问控制就该在策略层做转换层只负责转换。第五条留出排障通道。做服务发布的时候一定给自己留一条能进去的路别把所有入口都封死。我见过有人配错了规则把自己锁在外面最后只能去机房接console。这个教训值一次现场跑腿。第六条关注老化时间和业务心跳的匹配。这个前面提过但值得再说一次。上线任何长连接业务之前对一下心跳间隔和设备的老化时间别等出问题再回头查。一般建议心跳间隔不超过老化时间的一半留足余量。这套东西讲下来其实核心就一句话NAT是会话状态的重写不是简单的地址替换。你把会话表当成主线去理解每一个现象绝大多数问题都能自己推出来。剩下的那些推不出来的抓三个点的包基本也就清楚了。