NAT网络地址转换:原理、选型与故障排查实战 1. 先搞清楚网络地址转换到底在解决什么问题网络地址转换这四个字很多人第一次接触是在教材的某一章里看到一堆私网地址段、地址池、端口复用之类的名词考试能过真到了机房里配的时候还是一脸茫然。我带的几个新人里几乎每个人都会问同一个问题内网全用私有地址出口做一个转换就完事了为什么还要分静态、动态、NAPT、NAT Server 这么多种答案其实不在地址不够用这五个字上而在边界这两个字上。先把最朴素的事实摆出来。IPv4 地址空间是 32 位理论上限约 43 亿个这个数字在互联网早期看起来遥不可及但地址分配是按块来的早期申请到的机构动辄拿到一个 A 类或者十几个 B 类实际使用率极低。等到大家意识到问题的时候可分配的地址块已经所剩无几。网络地址转换就是在这个背景下被推上台面的让内网的一大批设备共用少量的公网地址出网从而把地址消耗的速度压下来。这部分是教科书讲的没问题但它只解释了为什么会有这个技术没解释为什么这个技术长成了现在这个样子。真正决定网络地址转换形态的是边界这个思路。一个组织内部的通信源和目的都在自己掌控范围内地址怎么规划是自己的事一旦跨出边界就必须遵循公网的游戏规则用公网认可的地址。于是边界设备天然成了一个转换点进出的报文在这里改写地址字段内部拓扑对外完全不可见。这个设计带来两个副产品一个是地址复用一个是天然的内网屏蔽——外部无法直接寻址到内网主机因为内网地址在公网上根本不存在路由。很多年之后大家在讨论边界防护的时候才回过头发现网络地址转换顺手做了一件安全上的好事虽然它从来不是为安全设计的。理解了这一层再看那些五花八门的类型就不会觉得是硬凑出来的。静态转换解决的是外部要主动找我的问题动态转换解决的是我有多个公网地址想轮着用的问题**NAPT网络地址端口转换**解决的是我只有一个公网地址但内网有几百台机器的问题目的转换解决的是外部请求怎么精准送到内部某台服务器的问题。每一种形态背后都是一个具体的、真实存在的需求而不是为了丰富考纲。还有个经常被忽略的点网络地址转换是有状态的。它不是简单地把报文头的某个字段替换掉就完事而是在设备内部维护一张会话表记录谁转换成了谁、跟谁在通信。这张表决定了回程报文能不能正确还原也决定了这个技术天生带着会话老化、端口耗尽、状态不同步这些工程问题。后面聊排查的时候百分之八十的疑难杂症最后都会绕回这张表。我在实际项目里见过太多配是配通了但不知道为什么通的情况。有一次割接一位同事把源转换规则挂在了错误的接口方向上内网访问外网正常外网访问内网服务器却时通时不通查了大半天以为是路由问题。后来抓包才发现回程报文的目的地址根本没被还原服务器发出的响应包带着私网源地址直接冲进了公网中途被上游丢弃。这类问题不看会话表、不看抓包光看配置是看不出来的。2. 网络地址转换的几种形态与选型逻辑2.1 静态转换给对外的服务留一个固定门牌静态转换是最容易理解的一种一条规则绑定一个私网地址和一个公网地址一对一永久有效。它的价值不在于节省地址而恰恰在于不节省——我需要一个稳定的、外部可以主动访问的入口。比如对外发布的 Web 服务、邮件服务、需要被第三方回调的接口这些场景下地址必须是确定的不能今天这个明天那个。选型时的判断标准很简单这个服务是否需要被外部主动发起连接。如果是静态转换或者静态端口映射就是必选项如果只是内网主动出去访问那就完全没必要占用一个宝贵的公网地址。我在做地址规划的时候有个习惯先把所有需要被访问的服务列一张表按重要性排序然后才去分配公网地址剩下的地址全部丢进地址池给 NAPT 用。这个顺序反了的话很容易出现地址池不够用、又要临时调整的情况。静态转换有个容易被忽视的细节它不改变端口。一对一的地址映射源端口保持不变这意味着如果两个不同的内部服务恰好用了同一个端口只要它们映射到不同的公网地址就没问题但如果映射到同一个公网地址就会冲突。所以严格意义上说一对一的地址转换不能复用同一个公网 IP 承载多个同端口服务这种情况必须用端口级映射来解决。2.2 动态转换地址池轮转的适用边界动态转换是从一个地址池里动态取一个空闲公网地址分配给内网主机会话结束后释放。这套机制听起来比静态灵活但实际项目里用得并不多原因是它并没有解决地址数量的问题——内网 500 台机器池子里只有 20 个地址第 21 台机器要用的时候就没地址可分了只能排队或者丢弃。它真正适用的场景是内网主机数量少于或接近公网地址数量且需要外部主动访问但又不要求固定入口的情况。比如某个分支机构有 30 台设备申请到了一个 /27 的地址块用动态转换让每台设备出去的时候都有自己的公网地址外部看到的是不同的源地址某些对源地址有要求的业务会比较友好。但要注意动态转换的分配是有生命周期的。设备通常会在会话建立时分配在会话老化后回收回收的时间取决于具体实现和配置的老化时间。如果业务方对我的出口地址一直不变有强需求动态转换是靠不住的必须上静态。2.3 NAPT多对一出口场景的绝对主力NAPT也有地方叫 PAT、地址池复用、端口级转换本质是多个私网地址加端口映射到同一个公网地址的不同端口。这是家用宽带和企业出口最常见的方式一个公网地址能撑起几千甚至几万条并发会话具体上限取决于设备能力和端口分配策略。它的核心机制是端口复用。设备在转发内网主机 A 的报文时不仅把源地址改成公网地址还把源端口改成一个自己选定的、当前未被占用的端口然后在会话表里记下这个映射关系。回程报文到达时设备查表根据目的端口找到对应的内网主机和原始端口还原后转发进去。整个过程对外完全透明内网主机自己毫无感知。这里有个关键参数可用的端口范围。理论上 TCP/UDP 源端口是 16 位范围 1 到 65535但实际可用的远没有这么多。0 到 1023 是知名端口一般不建议用作转换端口某些设备会保留一段给自己使用还有一些端口被特定协议占用。所以一台设备上一个公网地址实际可用的转换端口可能在几万个量级再扣掉每个会话占用的端口数有些协议一个会话要占多个端口并发能力就要打折扣。我做过一个粗略的估算用于容量规划假设单个公网地址可用端口 3 万个平均每用户并发会话 200 条那么一个地址大约能支撑 150 个活跃用户。当然这个数字非常粗糙实际要看业务类型——纯网页浏览的会话数远低于视频、游戏、P2P 类业务。做规划的时候宁可留一倍余量因为端口耗尽引发的故障排查起来非常痛苦现象是部分用户间歇性上不了网没有明确报错。2.4 目的转换与端口映射把外部请求精准送进来目的转换和源转换是一对镜像操作。源转换改的是谁发出的目的转换改的是发给谁的。典型用法是把公网地址的某个端口映射到内网服务器的某个端口外部用户访问公网地址的这个端口设备在转发时把目的地址和端口改写成内网服务器的地址和端口。这里最容易出错的地方是方向判断。很多配置界面上源地址目的地址填的是转换前的原始地址而转换后地址填的是改写后的地址一旦填反规则就完全失效。更麻烦的是有些设备对入方向和出方向的规则分开配置同一台服务器既需要能被外部访问又需要能主动访问外部就要配两条方向相反的规则任何一条漏了都会出现能出去不能进来或者能进来不能出去的半瘫状态。端口映射还有一个安全上的考量映射出去的范围越小越好。我见过有项目为了图省事直接把一台服务器的全部端口映射到公网结果没过多久就被扫描器盯上。正确的做法是只映射必要的端口其余全部拒绝设备上的安全策略和映射规则要配套使用不能只靠映射规则本身做访问控制。2.5 双向转换与两次转换复杂组网的粘合剂有些场景下一条报文需要同时做源转换和目的转换这叫双向转换。最典型的例子是内网用户通过公网地址访问同一内网中的服务器——报文从内网发出目的地址是公网地址设备需要先把目的地址转成服务器私网地址同时把源地址转成公网地址否则服务器回包时会直接回给内网源地址绕过设备导致连接建立失败。这个场景业内叫发夹弯Hairpin后面还会专门讲。两次转换则是报文在路径上经过两台设备各自做一次转换。比如内网经过一台边界设备转换一次再经过运营商侧的设备转换一次。这种结构下任何一台设备的会话表出问题整条链路就断了而且排查时从两端看现象完全不一样非常考验排查思路。我的经验是遇到这种组网一定要在每台设备的进出口都做抓包把每一跳的地址变化记录下来形成一条完整的链路图否则光靠猜会浪费大量时间。3. 报文到底怎么走一次访问的完整链路3.1 会话表才是网络地址转换真正的大脑很多人把网络地址转换理解成改报文头这个理解只对了一半。改报文头是结果真正让它工作的是会话表。表里至少记录了这么几项转换前的源地址和端口、转换后的源地址和端口、目的地址和端口、协议号、会话状态、老化时间。出方向的报文命中规则后创建会话回方向的报文靠查表还原两个方向共用同一条表项。这张表的存在决定了几个重要特性。第一它是单向创建的。通常只有内网主动发起连接才会创建会话外部主动发起的报文如果没有匹配的目的转换规则直接丢弃。这就是为什么内网能出去、外网进不来是默认状态。第二它有老化时间。TCP 有连接状态可以判断FIN 或 RST 之后可以较快老化UDP 没有连接概念只能靠计时器常见的默认值是几十秒到几分钟。第三它是有容量上限的。设备的内存和转发芯片的表项数量决定了最大并发会话数打满了新连接就建不起来。这三点直接对应三类典型故障方向配反导致单向不通、老化时间设置不当导致长连接被中断、会话表打满导致新用户上不了网。排查的时候先看会话表里有没有对应表项再看表项的状态和老化时间很多问题一眼就能定位。3.2 出方向与回方向的转换顺序转换顺序这件事配置的时候不觉得出问题的时候要命。一条报文从内网进设备大致要经过这么几个环节入接口检查、安全策略匹配、目的地址转换如果有、路由查询、源地址转换、出接口发送。注意目的转换在路由之前源转换在路由之后。目的转换在前是因为路由需要根据最终的目的地址来决定从哪个接口发出去。如果先查路由再改目的地址路由结果就是错的。源转换在后是因为源地址的选择往往和出接口绑定——多出口环境下从哪个口出去就用哪个口的地址做转换先确定出接口才能确定转换成什么地址。这个顺序解释了多出口场景下的一个经典问题策略路由把流量导向了 A 出口但源转换规则匹配的是 B 出口的地址结果报文带着 B 的地址从 A 发出去回程自然回不来。解决办法是让源转换规则和出口绑定或者用出接口作为匹配条件而不是写死地址。回方向的顺序刚好相反先根据目的地址和端口查会话表还原还原之后再查路由把报文送回内网。如果会话表里查不到报文直接被丢弃不会再去尝试其他匹配。这一点很重要——回程报文不走目的转换规则只走会话表。所以有时候目的转换规则配得没问题但因为出方向的会话没建起来回程照样不通。3.3 端口分配策略与冲突处理NAPT 的端口分配不是随机的设备通常有一套策略。常见的有两种一种是逐会话分配每建一条新会话就分配一个新端口另一种是端口块分配给每个内网主机一次性分配一段端口后续该主机的会话都在这段端口里取。后者对日志记录和溯源更友好因为日志量小得多——只需要记录某内网地址对应某段端口而不是每条会话记一条。端口冲突的处理也值得说一下。当设备选中的端口已经被占用时会尝试下一个直到找到空闲的。如果可用端口全部耗尽新会话就建不起来。这时候的现象很有意思已经建立的连接不受影响能正常通信但新发起的连接全部失败。用户侧的感受是网页打不开但微信还能发消息因为微信的长连接早就建好了。这种半死不活的状态最容易被误判成网络抖动。提示如果发现老连接正常、新连接失败的现象优先怀疑会话表或端口资源耗尽而不是链路质量。查一下当前会话数和设备规格上限往往能立刻确认。3.4 转换与路由、安全策略的先后关系这三者的顺序是排查问题的地基。报文进来先过安全策略再做目的转换然后查路由再做源转换最后出去。任何一步不通过后面的都不会执行。举一个真实的排查案例。某次内网用户访问外部服务失败检查发现安全策略放行了、路由也正确、源转换规则存在但就是不通报文。最后查出来是目的转换规则里配了一条范围过宽的规则把去往某个网段的流量错误地改写到了内网某台设备导致路由查到了一个不可达的下一跳。规则本身没错错在匹配范围太大把不该拦的流量拦下来了。这类问题只能靠逐条核对规则顺序和匹配范围来解决设备通常按顺序匹配第一条命中就生效所以规则的先后顺序本身就是逻辑的一部分。4. 动手配一个典型企业出口的完整落地4.1 场景与地址规划假设一个典型的中小企业出口场景内网有三个网段办公区 192.168.10.0/24、服务器区 192.168.20.0/24、访客区 192.168.30.0/24出口申请到一个公网地址段 203.0.113.8/29可用地址 6 个。需求是办公区和访客区能上网但不能互访服务器区有一台 Web 服务器需要对外提供 80 和 443 端口内网用户也要能用公网地址访问这台服务器。地址规划如下用途地址说明出口设备外网接口203.0.113.9网关地址不做转换Web 服务器映射203.0.113.10一对一映射到 192.168.20.10办公区 NAPT 池203.0.113.11 - 203.0.113.12两个地址约 6 万端口访客区 NAPT 池203.0.113.13单独一个地址便于限速和审计保留203.0.113.14预留扩展办公区和访客区分开地址池这是个刻意的设计。合并成一个池子当然也能跑但一旦访客区出现异常流量把端口占满办公区会跟着遭殃。分开之后故障域被隔离而且做流量审计的时候看源地址就知道是哪个区域省了很多事。4.2 基础配置步骤以下用通用命令行风格示意不同设备的字段名和语法会有差异重点是理清每一步的意图而不是照抄命令。第一步定义内网地址范围用于匹配需要转换的流量# 定义办公区与访客区的地址对象 object-group network INTERNAL_OFFICE network 192.168.10.0 255.255.255.0 object-group network INTERNAL_GUEST network 192.168.30.0 255.255.255.0 # 定义公网地址池 nat pool POOL_OFFICE 203.0.113.11 203.0.113.12 netmask 255.255.255.248 nat pool POOL_GUEST 203.0.113.13 203.0.113.13 netmask 255.255.255.248第二步配置源转换规则注意绑定出接口避免多出口时地址选错# 办公区出网源地址转换绑定外网出接口 nat source rule 10 match source-address INTERNAL_OFFICE match out-interface WAN0 action source-nat pool POOL_OFFICE # 访客区出网独立地址池 nat source rule 20 match source-address INTERNAL_GUEST match out-interface WAN0 action source-nat pool POOL_GUEST第三步配置目的转换把外部请求送到 Web 服务器# 公网 203.0.113.10:80/443 映射到 192.168.20.10 nat destination rule 100 match destination-address 203.0.113.10 match destination-port 80 443 match protocol tcp action destination-nat 192.168.20.10第四步配置安全策略放行。注意策略要针对转换后的地址写因为策略检查发生在目的转换之后security-policy rule name ALLOW_WEB_INBOUND source-zone untrust destination-zone dmz destination-address 192.168.20.10 destination-port 80 443 action permit第五步处理发夹弯。内网用户用公网地址访问同一内网服务器需要额外一条规则让源地址也被转换nat source rule 200 match source-address 192.168.10.0 255.255.255.0 match destination-address 203.0.113.10 match destination-port 80 443 action source-nat interface WAN0这条规则的意图是当内网用户访问公网映射地址时源地址也转换成出口地址这样服务器回包时会回到出口设备设备再根据会话表把包送回内网用户。如果不加这条服务器看到源地址是内网地址直接回给内网报文绕过了设备连接建立不起来。4.3 验证与抓包配完之后必须验证不能只看配置界面显示已生效。我的验证顺序是这样的先看会话表。从内网发起一次访问然后在设备上查会话确认表项存在且转换前后的地址端口符合预期。这一步能确认规则是否命中。display nat session verbose # 期望看到类似 # protocol tcp src 192.168.10.55:51234 - 203.0.113.11:40001 # dst 198.51.100.20:443 # state: established timeout: 300s再看抓包。在内外网接口各抓一次对比地址字段。出接口应该看到公网源地址内网接口应该看到私网地址。回程方向反过来。这一步能确认转换实际发生在哪个环节尤其适合排查配置看起来对但就是不通的情况。最后做反向验证从外部访问映射地址确认能通同时确认未映射的端口拒绝访问。这一步经常被省略结果留下安全隐患。4.4 双出口与策略路由下的转换协同双出口是网络地址转换最容易翻车的地方。两个运营商链路两个公网地址内网用户按策略分流。问题出在策略路由决定了从哪个口出去但如果源转换规则没跟着走报文就会带着 A 口的地址从 B 口出去。正确的做法是每条源转换规则都显式匹配出接口或者把转换规则和策略路由的匹配条件做成一一对应。更稳妥的方式是用出接口地址做转换source-nat interface这样从哪个口出去就用哪个口的地址天然不会错。还有一个坑是回程路径。如果 A 口出去的流量回程从 B 口进来设备上是能收到但安全策略和会话表可能对不上导致丢弃。这种现象叫非对称路由在双出口环境下很常见。解决办法要么是做严格的策略路由保证来回路径一致要么是在设备上配置允许非对称流量的选项。我个人倾向于前者因为后者会让排查变得更复杂。5. 那些年踩过的坑常见问题排查实录5.1 症状对照速查表症状高概率原因优先排查动作内网全断外网正常源转换规则未命中或地址池为空查会话表是否有转换表项部分用户上不了网会话数或端口耗尽查当前会话数对比上限能出去不能进来目的转换规则方向或地址填反抓外网入口包看目的地址能进来不能出去缺少反向会话或策略未放行查回程报文是否被丢弃内网访问映射地址不通缺少发夹弯规则抓包看服务器回包目的地址长连接每隔几分钟断一次会话老化时间小于业务心跳间隔查会话老化配置语音或文件传输异常但网页正常载荷中携带地址需要协议识别检查是否有对应协议处理双出口随机不通源转换地址与出口不一致核对规则是否绑定出接口5.2 会话老化导致的长连接中断这个问题我遇到过不止一次。某个后台服务每隔三五分钟就报一次连接异常重连后又正常周而复始。业务方一开始怀疑是对方接口不稳定查了半个月没结论。根因是设备上 UDP 会话的默认老化时间短于业务的心跳间隔。业务每 5 分钟发一次心跳但设备上 2 分钟没流量就把表项删了等心跳再来的时候是一个全新的会话服务端那边还留着旧的状态两边对不上握手失败。解决方式有两种把老化时间调长或者让业务把心跳间隔缩短到老化时间以内。前者改配置就行但要评估容量影响——老化时间越长同时存在的表项越多后者要业务方配合改造成本更高。我一般优先用前者同时把老化时间写成明确的注释避免以后被人误改。TCP 相对好一些因为有 FIN/RST 可以判断但某些设备对长时间无数据的 TCP 连接也会强制老化做长连接的业务还是要留意。5.3 端口耗尽引发的半瘫现象前面提过一次这里展开说。端口耗尽的典型表现是所有已经建立的会话正常工作新发起的连接全部失败用户侧感觉是网卡了。这时候 ping 网关通常是通的DNS 也可能通如果 DNS 走的是已建立的会话但打开新网页就是转圈。快速确认方法是看当前会话数。如果接近设备规格上限或者在地址池维度上某个地址的端口占用接近饱和基本可以确认。解决分短期和长期短期加地址池、清理异常会话长期做容量规划把不同业务分到不同地址池避免单点被打满。还有一种更隐蔽的情况某些业务一个连接会占用多个端口比如某些实时通信协议实际端口消耗是会话数的数倍。做规划的时候如果只按会话数算很容易算漏。5.4 载荷中携带地址的协议怎么处理有些协议在应用层载荷里也携带 IP 地址和端口典型的是文件传输的被动模式、会话初始化协议、部分视频会议协议。网络地址转换只改报文头改不了载荷于是载荷里的地址和内网实际情况对不上导致连接建立失败。设备通常提供协议识别功能来处理这类情况自动改写载荷中的地址。但这个功能不是万能的加密的流量改不了非标准端口可能识别不出来某些厂商的实现还有兼容性问题。我的建议是能不用就不用——把这类服务放到转换规则之外或者用专线、代理的方式规避实在要用再开协议识别并且一定要做完整的功能验证别只测登录不测传输。注意开启载荷改写功能后务必测试加密场景。有些设备遇到加密流量会直接丢弃现象是明文能通、加密不通很容易被误判成证书问题。5.5 日志与溯源出问题之后怎么查网络地址转换一旦部署日志就成了必需品。多个内网用户共用一个公网地址外部看到的源地址是一样的出了事要定位到具体是谁只能靠转换日志。日志有两种记法按会话记和按端口块记。前者每条会话一条记录信息最全但量巨大一个中等规模出口一天几千万条很正常后者只在分配端口块时记一条量小很多但要求设备支持端口块分配。选哪种取决于合规要求和存储能力。我的经验是日志的保留周期至少要覆盖问题发现到开始排查的窗口。现实中最尴尬的情况是事件发生两周后才被注意到回头查日志发现只保留了七天什么都查不到。6. 网络地址转换的能力边界6.1 为什么有的点对点连接就是打不通网络地址转换的存在让任意两台主机直接通信这个原始假设失效了。两个都在转换后面的设备互相不知道对方的公网映射关系也不知道对方会用什么端口直连几乎不可能成功。业内有一套打洞的思路双方先通过一个公共的服务器交换各自的公网映射地址然后同时向对方发包试图在各自的转换设备上打出一个洞。成功率高度依赖于转换设备的行为特征。有些设备对同一个内网地址到不同目的的映射保持端口一致打洞容易成功有些设备对每个目的分配不同端口甚至根据目的地址不同做不同的映射打洞就很难。这就是为什么同样的应用在家用宽带上能用在某些企业出口上就不行。从运维角度能做的其实是有限的了解自家出口的行为特征在应用选型时优先选择带中继回退能力的方案而不是死磕直连。中继会增加延迟和带宽成本但至少是确定可用的。6.2 转换设备不是防火墙这一点必须反复强调。网络地址转换顺带带来了外部不能主动访问内网的效果但这只是一种副作用不是设计目标。它不能替代访问控制策略。具体来说转换只处理地址和端口的改写不做应用层检查不做入侵检测不做用户身份认证。而且一旦配置了目的转换那个端口就是敞开的转换规则本身不区分来访者是谁。真正的访问控制要靠独立的安全策略两者是配合关系不是替代关系。我见过有项目因为反正有转换外面进不来就省掉了安全策略结果配了一条范围过宽的目的转换把管理端口暴露了出去后果很难看。6.3 地址共享与责任边界大规模地址复用的场景下一个公网地址后面可能有成千上万个用户。这时候一旦出现异常行为外部只能看到那一个地址追责和处置都会变得困难。这也是为什么在共享地址的场景里日志和溯源机制必须提前设计好而不是出事之后再补。另一个现实问题是黑名单误伤。共享地址里只要有一个用户做了不当行为整个地址可能被外部服务拉黑导致同地址下的所有用户受影响。这个问题没有技术上的完美解法只能靠精细化的日志和快速的处置流程来缓解。6.4 下一代协议普及之后还需要转换吗IPv6 的设计初衷就是端到端可寻址理论上不再需要地址转换。但现实是大量存量系统和应用仍然假设 IPv4 存在过渡期内两种协议共存是常态。过渡阶段出现了若干种转换与共存的技术方案有的做协议翻译有的做隧道封装各自适用不同场景。即便在纯 IPv6 环境里地址转换的某些思路也没有完全消失。比如出于隐私保护考虑的地址临时变化机制比如内网地址对外隐藏的部署习惯这些需求在 IPv6 下依然存在只是实现方式变了。所以把网络地址转换当成一个过渡期技术来看待是合理的但要说它马上会消失我觉得还早得很。我个人的判断是这套东西在未来相当长一段时间里还会继续存在于现网中尤其是企业出口和运营商侧。把它学透不是为了应付某一章的内容而是因为它是理解报文在边界上到底发生了什么的最佳入口。真正把会话表、转换顺序、方向判断这三件事想清楚了再看其他网络技术很多概念会突然变得顺理成章。最后分享一个我自己一直在用的小习惯每次配完转换规则不要急着看界面上的已启用先发一个包抓一次看一遍会话表把转换前后的五元组写下来。写不出来说明还没真正搞清楚这条规则在干什么。这个动作花不了两分钟但能省掉后面几个小时的排查。