一、bug 现场:摄像头在内网「贴贴」,到公网却「装死」
先讲个魔幻现实的故事:
我用若依框架 + WVPPRO+ZLM 搭了个国标视频平台,在内网测试时,摄像头像乖巧的小学生,注册 - 鉴权 - 心跳一气呵成。结果部署到京东云服务器后,自家摄像头突然「失忆」:
-
平台日志显示:设备发了注册请求,平台回了 401 鉴权(相当于「请出示密码」),但设备从此消失,再也不发带密码的二次请求;
-
海康摄像头却「反骨」:同样的公网地址,秒级注册成功,画面流畅得让我怀疑人生。
核心矛盾 :为啥同样的公网环境,有的设备能通,有的不行?答案藏在 SIP 协议的一个小字段里 ------Via 头域。
二、Wireshark 抓包:发现「神秘 IP」篡改了我的信令
祭出抓包神器tcpdump
(命令记好:sudo tcpdump -i eth0 -w capture.pcap -C 10
,自动分割 10MB 小文件,防卡死!),发现诡异现象:
-
平台回复的 401 消息里,Via 头域的 IP 是
100.64.38.134
,但这既不是设备公网 IP(113.132.64.61
),也不是设备内网 IP(192.168.1.142
),而是个陌生的内网 IP! -
模拟设备改 UDP 通讯后报错:
plaintext
csharp[ERROR] sip_check_response_via:Via头的IP(100.64.38.134)和本地IP对不上!
翻译:设备收到平台的 401 后,检查「导航日志」(Via 头)发现地址不对,直接拒绝「交密码」,导致注册流程卡死。
三、科普时间:SIP 协议的「导航日志」------Via 头域
1. Via 头域是啥?相当于快递的「物流轨迹」
SIP 协议(GB28181 的信令核心)靠 Via 头域记录消息经过的每一跳地址,确保响应能按原路返回。比如你点外卖:
- 请求消息(设备→平台):Via 头记「小区门卫(NAT)→外卖站(平台)」;
- 响应消息(平台→设备):Via 头记「外卖站→小区门卫」,门卫再转给你。
关键参数(划重点!):
plaintext
css
Via: SIP/2.0/UDP [当前节点IP:端口];received=[真实公网IP];rport=[真实公网端口]
- 当前节点 IP :理论上是设备 IP,但可能被 NAT 篡改(如变成
100.64.38.134
); - received/rport:NAT 告诉设备「我真实的公网地址是这个」,但有些设备「死脑筋」,只信当前节点 IP。
2. 注册流程中的「鉴权卡死」
正常流程应该是:
- 设备发注册请求(带 Via 头:设备内网 IP:5060)→经 NAT 转成公网 IP:6272→平台;
- 平台回 401(Via 头应写平台公网 IP:5060)→但被神秘力量改成
100.64.38.134:61300
; - 设备收到后检查 Via 头 IP,发现和自己记录的平台公网 IP 对不上,直接摆烂,不发带密码的二次请求。
四、罪魁祸首:NAT 网关的「热心肠」搞砸了一切
1. NAT 是啥?内网设备的「公网伪装者」
你家路由器就是个 NAT 设备,作用是让多个内网设备(192.168.1.x)共享一个公网 IP。比如你手机发消息给服务器:
- 发送时:NAT 把你的内网 IP: 端口(192.168.1.100:5060)换成自己的公网 IP: 随机端口(113.132.64.61:6272);
- 接收时:NAT 看端口 6272 对应你手机,再转发给你。
2. 为什么 Via 头会被篡改?因为 NAT 的「过度热心」!
很多 NAT 网关自带 ALG(应用层网关),会主动解析 SIP 协议的消息内容,试图「修正」地址。但它搞错了一件事:
- 当平台用5060 端口(SIP 默认端口)回复 401 时,ALG 认为「这个端口是 SIP 专用,得帮设备改回内网地址」,于是把 Via 头的 IP 改成自己的内网地址(100.64.38.134),不管服务器实际公网 IP 是多少;
- 而用5061 端口时,ALG 觉得「这不是标准 SIP 端口,别瞎改」,Via 头保留正确的公网 IP,设备校验通过。
3. 四种 NAT 类型,哪种最坑?
NAT 类型 | 特点 | 对 SIP 的友好度 |
---|---|---|
对称 NAT | 每次访问不同目标,NAT 都会分配新的公网端口,还可能篡改 Via 头(坑王!) | ★☆☆☆☆ |
完全圆锥 NAT | 固定公网 IP: 端口,最友好 | ★★★★★ |
受限圆锥 NAT | 允许指定 IP 回连,中等友好 | ★★★☆☆ |
端口受限圆锥 NAT | 允许指定 IP: 端口回连,较友好 | ★★★☆☆ |
我们遇到的大概率是「对称 NAT+ALG」,专门针对 5060 端口搞事情。
五、为什么海康设备能通?大厂的「NAT 防坑指南」
海康等大厂设备做了这些适配:
-
自动探测 NAT 类型:通过 STUN 协议获取真实公网地址,不依赖 Via 头;
-
宽松校验策略:优先信任 received/rport 参数,即使 Via 头被改也能继续交互;
-
支持端口自定义:允许手动设置公网 IP: 端口,绕过 NAT 的自动篡改。
而小众设备可能「轴」到只校验 Via 头的第一个 IP,导致一被篡改就罢工。
六、破案过程:从「玄学换端口」到协议层原理
1. 关键转折点:换端口为什么能解决?
- 5060 是 SIP 的「知名端口」,容易被 NAT 的 ALG 识别并篡改 Via 头;
- 换成 5061、5070 等「冷门端口」后,ALG 认为这不是 SIP 流量,不再篡改,Via 头恢复正确的公网 IP,设备校验通过。
2. 深挖 Via 头的「三层地址」
一个 SIP 消息可能包含三个地址,必须全部一致才能通:
- IP 层源地址:服务器回复 401 的真实源 IP(应是公网 IP);
- Via 头当前节点 IP:被 NAT 篡改后变成内网 IP(如 100.64.38.134);
- Contact 头地址 :设备注册时记录的平台地址(应包含公网 IP: 端口)。
设备卡死的原因:只校验 Via 头的当前节点 IP,不管 IP 层源地址和 Contact 头。
七、终极避坑指南:从入门到入土的 NAT/SIP 知识
1. 新手必懂的 NAT 术语
- NAT 地址转换:内网 IP→公网 IP,解决 IP 不够用的问题;
- ALG 应用层网关:NAT 的「协议解析器」,可能好心办坏事;
- STUN 协议:设备主动向服务器发送请求,获取自己的公网地址(防 NAT 篡改的利器)。
2. 抓包时必查的三个点
- 用 Wireshark 对比「IP 层源地址」和「Via 头当前节点 IP」是否一致;
- 查看 Contact 头是否包含正确的公网端口(如 5061 而非 5060);
- 检查设备日志是否有「Via 头校验失败」的报错(如
sip_check_response_via
)。
3. 进阶解决方案(换端口不管用怎么办?)
- 关闭 NAT 的 ALG 功能:登录路由器后台,找到「SIP ALG」选项,手动关闭(部分设备支持);
- 使用 STUN/TURN 协议:让设备主动获取公网地址,或通过中转服务器转发数据(适合复杂网络环境);
- 手动配置端口映射:在路由器中固定映射服务器的 5060 端口到公网 IP(需管理员权限)。
八、总结:网络世界没有玄学,只有没吃透的规则
这个 bug 教会我们:
-
SIP 协议的 Via 头很「轴」:部分设备严格校验 Via 头的第一个 IP,哪怕 received 参数是对的也没用;
-
知名端口是坑点:5060、80 等端口容易被网络设备特殊处理,换个端口可能「一键通关」;
-
抓包是救命稻草:所有玄学问题,最终都能通过对比协议字段找到答案(记得开 Wireshark!)。
最后想对设备厂商说:下次甩锅前,能不能先告诉我设备严格校验 Via 头?不过也好,现在我也算半个「NAT+SIP」专家了(叉腰)。
遇到类似问题的小伙伴,记住口诀:「Via 头不对别慌,先换端口再抓包,设备日志仔细瞧,NAT ALG 关掉!」 祝大家再也不踩 NAT 坑~ 😉