SIP 在实验环境里通常不难跑通,但一旦进入真实网络,尤其是终端位于家庭宽带、企业内网、云上私网、运营商 NAT 或多层代理之后,问题就会明显增多。很多人第一次碰到 SIP 故障,看到的现象都很像:
- 能注册但打不通
- 能振铃但接通后无声
- 单通
- 呼叫过几秒自动断开
- 对端收不到 BYE 或 re-INVITE
这类问题如果只从“是不是服务器坏了”去看,往往很难定位。根本原因通常不在 SIP 本身,而在于:SIP 是一个会在消息体、头域和媒体描述里携带地址信息的协议,而 NAT 恰恰会改变地址与端口映射关系。
所以,SIP 遇到 NAT 难,不是因为它天生不稳定,而是因为它的设计理念与 NAT 的工作方式天然存在冲突。
一、为什么 SIP 在 NAT 环境下容易出问题
先看 NAT 的基本行为。终端在内网时,通常使用私网地址,例如:
- 192.168.x.x
- 10.x.x.x
- 172.16.x.x – 172.31.x.x
这些地址不能直接在公网路由。于是终端发包时,出口设备会把:
- 源 IP 改成公网地址
- 源端口改成映射后的公网端口
对一般 TCP/UDP 应用来说,这件事通常是透明的。但 SIP 不一样,它不仅有“网络层里的源地址”,还有很多“应用层显式携带的地址信息”,例如:
- Via
- Contact
- Record-Route / Route
- SDP 里的 c= 和 m= 信息
于是就出现一个经典矛盾:
网络层已经被 NAT 改成公网可达地址,但 SIP 报文内部仍然可能写着私网地址。
如果对端按照这些“写在 SIP 里的地址”来回消息或发媒体流,就很容易失败。
二、SIP 在 NAT 下为什么比很多协议更脆弱
SIP 的脆弱点主要体现在两个层面:
1. 信令层地址问题
信令报文的后续返回路径,可能依赖:
- 源 IP / 源端口
- Via
- Contact
- Route 集合
如果这些字段中混入了私网地址,而对端或代理又直接照单全收,就可能出现:
- 注册成功但后续请求发不回终端
- INVITE 到达不了实际终端
- BYE / ACK / re-INVITE 路径错误
2. 媒体层地址问题
媒体通常用 RTP/RTCP,地址信息写在 SDP 里。如果 SDP 中声明的是内网地址,例如:
c=IN IP4 192.168.1.10
m=audio 4000 RTP/AVP 0 8 96
而对端又真的向 192.168.1.10:4000 发 RTP,那么公网对端当然无法把媒体送达内网终端。结果就是:
- 无声
- 单通
- 双向都无声
这也是为什么很多人第一次做 SIP 测试会发现:信令看上去没问题,真正坏的是媒体路径。
三、先区分两类问题:信令问题与媒体问题
排障时第一步不要急着改配置,先区分问题出在哪一层。
1. 信令问题的典型表现
- REGISTER 失败
- 注册成功但来电送不到终端
- INVITE 发出后收不到响应
- 200 OK 发出后对端 ACK 回不来
- 通话建立后 BYE 收不到
2. 媒体问题的典型表现
- 能振铃、能接通,但没声音
- 一方有声,一方无声
- 前几秒正常,随后断流
- 早期媒体失败,例如 183 场景听不到回铃音
这一步很关键,因为很多时候 SIP 消息本身交互完整,真正失败的是 RTP 路径;如果误把媒体问题当成纯信令问题,就会一直在错误方向排查。
四、NAT 下最常见的几个典型问题
1. Contact 写成私网地址,导致后续请求送不回去
终端注册时可能发送:
Contact: <sip:1001@192.168.1.10:5060>
如果服务端直接把这个 Contact 存下来,后面来电时就可能尝试把 INVITE 发到 192.168.1.10:5060。对公网侧或远端服务来说,这个地址显然不可达。
结果:
- 注册看似成功
- 但被叫无法收到来电
2. Via 中的返回地址不可达
一些响应路径会参考 Via 信息。如果 Via 没有正确反映终端真实可回达地址,或者代理没有启用对称响应处理,响应可能被发往错误位置。
结果:
- 请求已到达服务端
- 但响应回不到客户端
- 抓包会看到客户端一直重传请求
3. SDP 中 c= 地址是私网地址,导致无声或单通
这是最常见的媒体问题。如果终端把内网地址写进 SDP,对端就会向错误地址发 RTP。
结果:
- 呼叫建立正常
- 媒体完全不通或单通
4. NAT 映射超时,导致注册掉线或通话中断
NAT 设备不会永久保存映射。对于 UDP,映射老化往往更快。如果终端长时间没有发包,NAT 表项被清理:
- 后续 SIP 消息找不到原端口映射
- 服务端发来的请求可能进不来
- 媒体流也可能在空闲后断掉
结果:
- 注册一开始正常,过一会儿失效
- 通话中某些方向突然静音
- 需要重新注册才能恢复
5. 多层 NAT 导致路径更加复杂
如果终端位于家庭路由器之后,而家庭路由器上游又是运营商 CGNAT,或者云上容器 / 虚拟机又嵌套 NAT,那么问题会更加棘手:
- 公网地址并不真正属于终端出口设备
- 端口映射不可预测
- 外部打回来的路径更难稳定建立
此时单纯依赖手工端口映射往往效果有限。
五、最典型的故障现象应该怎么理解
1. 能注册,但打电话打不通
这说明至少有一部分信令是通的。常见根因包括:
- 注册时服务端记录了错误的 Contact
- 后续 INVITE 的目标地址不可达
- NAT 表项超时,导致服务端回推请求失败
2. 能振铃,接通后无声
优先怀疑 SDP 地址、RTP 端口映射或媒体回程路径问题。信令通常已经跑通,问题多半出在媒体层。
3. 单通
单通往往比双向无声更有排障价值,因为它说明至少有一条 RTP 路是通的。通常应考虑:
- 一侧 SDP 地址错误
- 一侧 NAT 出口映射没建立成功
- 一侧防火墙只放行了单方向或部分端口
4. 过几秒自动挂断
这可能和 ACK、re-INVITE、Session Timer、RTP 不通后的业务判定有关,也可能与 NAT 映射很快失效有关。不要一上来就只看“谁发了 BYE”,还要看之前是否有消息没有成功往返。
六、为什么 ALG 经常“越帮越忙”
很多路由器、防火墙会提供所谓的 SIP ALG(Application Layer Gateway),号称可以自动识别 SIP,并帮你修改报文里的地址和端口。
理论上它是为了帮助 NAT 环境下的 SIP 通过,但现实中它经常带来更多问题,原因包括:
- 对 SIP 语法解析不完整
- 对某些厂商私有头域兼容差
- 对 TCP/TLS、SRTP 等场景支持不好
- 错误改写 Contact、Via、SDP
- 对多代理、Record-Route、分叉场景处理混乱
所以在很多工程实践中,一个很常见的经验反而是:
如果网络设备启用了 SIP ALG,且出现了莫名其妙的 SIP/NAT 问题,优先考虑先把 ALG 关掉再看。
七、SIP 处理 NAT 的几种常见思路
SIP 生态并不是没有应对 NAT 的办法,真正的关键是:不同办法解决的是不同层面的问题。
1. 对称响应(rport / received)
服务端不要盲目信任报文里声明的返回地址,而是根据实际收到请求的源 IP/源端口来发响应。这可以缓解 Via 不可达导致的响应回不去问题。
它主要解决的是:信令返回路径。
2. 注册保活 / keepalive
通过定期 REGISTER、CRLF keepalive、OPTIONS、双向 ping 等方式维持 NAT 映射不失效。
它主要解决的是:NAT 表项老化。
3. 公网地址发现(STUN)
终端通过 STUN 发现自己在公网侧看到的地址和端口,再把这些信息用于 SIP/SDP 生成。
它适合一定范围内的 NAT 场景,但不是所有 NAT 类型都能完全搞定。特别是复杂或对称型 NAT 下,单靠 STUN 往往不够。
4. 中继转发(TURN / 媒体中继)
如果双方都很难建立稳定直连,就让媒体先走中继。这样终端不必直接暴露可达媒体地址,而是统一和中继服务器交互。
它主要解决的是:RTP 媒体不可达。
5. SBC / Session Border Controller
SBC 是工程上非常常见的一种方案。它不只是做 NAT 穿越,还会承担:
- 信令拓扑隐藏
- 报文归一化
- 地址改写
- 媒体锚定
- 安全策略
- 互通兼容
如果是运营级、企业级或多网络复杂互通场景,SBC 往往比简单的“端口映射 + 参数修补”更可靠。
6. 让 SIP 走 TCP / TLS
这不能从根本上解决所有 NAT 问题,但对信令层通常更友好,因为:
- 连接状态明确
- 传输可靠
- 某些 NAT 设备对 TCP 映射维持更稳定
但要注意:信令走 TCP/TLS,并不自动等于 RTP 媒体也解决了。
八、排障时最重要的思路:先看地址,再看方向
面对 SIP NAT 问题,最怕一上来就改一堆配置。更有效的方法是按下面顺序排查:
第一步:看信令里写了什么地址
- Via
- Contact
- Record-Route
- Route
- SDP 的 c= / m=
只要看到私网地址出现在一个本应对公网可达的方向上,就要高度警惕。
第二步:看对端实际上往哪里发
有时报文里写的是私网地址,但中间设备做了修正;有时报文看似正常,但对端还是按旧地址发。一定要确认“对端真正发包的目标地址与端口”。
第三步:区分是回不来,还是根本没发出去
例如:
- 客户端一直重传 REGISTER:可能是响应回不来
- 200 OK 重复出现:可能是 ACK 回不去
- 接通后单通:可能是某一方向 RTP 根本没到达
第四步:确认 NAT 映射是否保持住了
如果刚开始正常,过一会儿出问题,就要重点看 keepalive、注册周期、媒体保活和 NAT 老化时间。
九、原理层面可以记住的几个判断口诀
如果不想每次都从头分析,可以记住这几个非常实用的判断逻辑:
- 注册成功不代表来电可达 —— Contact 可能仍然错
- 振铃成功不代表媒体正常 —— SDP / RTP 可能有问题
- 单通通常比双向无声更容易定位 —— 至少说明有一侧 RTP 路径是通的
- ACK / BYE / re-INVITE 丢失,也可能是 NAT 问题 —— 不只是初始 INVITE 会受影响
- 看到私网地址,不一定必然失败;但在公网互通场景下,必须高度怀疑
十、工程上更稳的解决方向
如果从纯原理走向工程实践,一般更稳定的方向通常是:
- 尽量让服务端具备 NAT 感知能力
- 优先启用对称响应和保活机制
- 谨慎使用 SIP ALG,必要时直接关闭
- 复杂网络优先考虑媒体中继或 SBC
- 不要只修信令,不处理媒体路径
很多部署失败的根源就在于:只解决了 REGISTER,没解决 INVITE;只解决了 INVITE,没解决 RTP;只解决了初始呼叫,没解决通话中的后续请求。
十一、总结
SIP 在 NAT 环境下的问题之所以常见,不是因为协议本身“脆弱”,而是因为它天然依赖地址信息,而 NAT 又天然会修改地址映射。两者叠加后,问题会在信令层和媒体层同时出现。
真正理解这类问题,可以抓住下面几条主线:
- 信令问题关注 Via、Contact、响应路径、后续请求可达性
- 媒体问题关注 SDP 地址、RTP 端口、单通/无声现象
- 时序问题关注 NAT 映射老化、保活机制、长时间空闲后的可达性
- 工程方案关注 rport、keepalive、STUN、TURN、SBC、媒体锚定等机制
只要把“报文里写的地址”和“网络里真实可达的地址”分开看,SIP NAT 问题就会清晰很多。
如果继续往下深入,最适合接着看的主题通常是:
- SIP 重传机制与 Timer 全解析
- 一次完整 SIP 呼叫流程抓包分析
- SIP 常见无声、单通问题的排障思路