<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>RTP on Zero Day Notes</title>
        <link>https://blog.5772447.xyz/tags/rtp/</link>
        <description>Recent content in RTP on Zero Day Notes</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <lastBuildDate>Fri, 13 Nov 2026 09:00:00 +0800</lastBuildDate><atom:link href="https://blog.5772447.xyz/tags/rtp/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>SIP ALG 改写报文：通话只有单向声音</title>
            <link>https://blog.5772447.xyz/posts/a3224613/</link>
            <pubDate>Fri, 13 Nov 2026 09:00:00 +0800</pubDate>
            <guid>https://blog.5772447.xyz/posts/a3224613/</guid>
            <description>&lt;h2 id=&#34;问题背景&#34;&gt;&lt;a href=&#34;#%e9%97%ae%e9%a2%98%e8%83%8c%e6%99%af&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;问题背景&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;公司新办公室有 60 多人，电话系统用的是本地 IP PBX（Asterisk/FreePBX），外线通过运营商的 SIP 中继接入。PBX 放在内网 &lt;code&gt;192.168.10.20&lt;/code&gt;，出口是一台企业路由器做 NAT，宽带拨号上网。内部分机互打一直正常，外线电话由运营商 SIP 中继落地。&lt;/p&gt;&#xA;&lt;p&gt;搬进新办公室后，外线通话开始出问题：电话能接通，但经常只有一方能听到声音；有些通话在 30 秒左右自动断掉。运营商说中继侧日志正常，PBX 厂商说配置没问题，问题卡在中间的网络设备上。&lt;/p&gt;&#xA;&lt;h2 id=&#34;故障现象&#34;&gt;&lt;a href=&#34;#%e6%95%85%e9%9a%9c%e7%8e%b0%e8%b1%a1&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;故障现象&#xD;&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;外呼和外呼接入都能建立通话，但大约一半的通话只有单向语音：主叫能听到对方，对方听不到主叫，或者反过来。&lt;/li&gt;&#xA;&lt;li&gt;部分通话在 30 秒左右自动断开，像是有一方没有收到后续的 SIP 消息。&lt;/li&gt;&#xA;&lt;li&gt;内部分机互打、内部会议完全正常，问题只出现在经过外网 SIP 中继的通话上。&lt;/li&gt;&#xA;&lt;li&gt;换用软电话、桌面话机、手机 SIP 客户端，现象一致，排除终端问题。&lt;/li&gt;&#xA;&lt;li&gt;PBX 抓包里能看到 RTP 发出去，但对端没有回包，或者回包发到了错误的地址/端口。&lt;/li&gt;&#xA;&lt;li&gt;路由器上 SIP ALG 是默认开启的，之前的老办公室用的是另一台路由器，没有这个问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;排查过程&#34;&gt;&lt;a href=&#34;#%e6%8e%92%e6%9f%a5%e8%bf%87%e7%a8%8b&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;排查过程&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;第一步确认是信令还是媒体。在 PBX 上抓包，SIP 的 INVITE、200 OK、ACK 都能正常收发，说明信令链路是通的；但 RTP 只有单向，问题在媒体地址协商。再看 SDP 里的 &lt;code&gt;c=&lt;/code&gt; 和 &lt;code&gt;m=&lt;/code&gt; 字段，PBX 宣告的是内网地址 &lt;code&gt;192.168.10.20&lt;/code&gt; 和 RTP 端口段，这本身没问题，NAT 设备应该负责把它转换成公网可达的地址。&lt;/p&gt;&#xA;&lt;p&gt;第二步在路由器 WAN 侧抓包对比。经过路由器后，SDP 里的地址确实被改成了公网 IP，但端口和 Contact 头被改得前后不一致：INVITE 里的媒体端口被 ALG 换成了一个临时端口，而后续 200 OK 里的 Contact 又指向另一个地址。对端按其中一处地址发 RTP，结果发到了一个没人监听的端口，媒体自然只有单向。&lt;/p&gt;&#xA;&lt;p&gt;第三步查路由器配置。登录路由器，发现“SIP ALG”默认开启，NAT 里也没有为 PBX 做任何端口映射。SIP ALG 的本意是帮 SIP 协议穿越 NAT：它会解析 SIP 报文，改写 Via、Contact、SDP 里的地址和端口，并在防火墙上开临时 pinhole。但这台路由器的 ALG 实现不完整，改写了 SDP 却没同步改 Contact，或者 pinhole 只开了一个方向，结果比不改还糟。&lt;/p&gt;&#xA;&lt;p&gt;第四步解释 30 秒断线。SIP 会话定时器（session timer）会在通话中途发 re-INVITE 刷新会话；re-INVITE 的 Contact 地址被 ALG 改错，对端回不到正确地址，刷新失败，双方按超时策略挂断。30 秒正好是不少运营商中继的会话刷新周期。&lt;/p&gt;&#xA;&lt;p&gt;第五步做对照实验。先在路由器上关闭 SIP ALG，再为 PBX 配置静态端口映射：UDP 5060 映射到 &lt;code&gt;192.168.10.20:5060&lt;/code&gt;，RTP 端口段 10000–20000 整段映射到 PBX；同时在 PBX 的 NAT 设置里填好公网 IP、本地网段和 RTP 范围。改完后外呼测试：双向语音正常，连续通话 30 分钟不断，抓包里 SDP 保持 PBX 自己的地址，由 NAT 做一对一转换，不再被中间设备改写。&lt;/p&gt;&#xA;&lt;p&gt;第六步验证不同运营商。公司有两条 SIP 中继，一条对 NAT 友好，一条要求走 outbound proxy；在 PBX 上给后者配置代理后，两条中继都稳定。说明 ALG 不是必需的，正确的方式是让 PBX/SBC 自己处理 NAT 穿越。&lt;/p&gt;&#xA;&lt;h2 id=&#34;解决方案&#34;&gt;&lt;a href=&#34;#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;解决方案&#xD;&#xA;&lt;/h2&gt;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;关闭 SIP ALG&lt;/strong&gt;：在路由器上找到 SIP ALG / SIP Helper 选项并关闭。大多数场景下，ALG 带来的问题多于它解决的问题；NAT 穿越应该由 PBX 或 SBC 负责。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;做静态端口映射&lt;/strong&gt;：把 SIP 信令端口（UDP/TCP 5060，若用 TLS 则 5061）和 RTP 端口段（例如 UDP 10000–20000）固定映射到 PBX；不要依赖 ALG 动态开 pinhole。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;配置 PBX 的 NAT 参数&lt;/strong&gt;：在 Asterisk/FreePBX 里填写公网 IP、本地网段、RTP 起止端口，启用 &lt;code&gt;force_rport&lt;/code&gt;、&lt;code&gt;rewrite_contact&lt;/code&gt; 等选项，让 PBX 在信令里使用正确的可达地址。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;按运营商要求走代理&lt;/strong&gt;：部分 SIP 中继要求 outbound proxy 或注册到指定 SBC，按运营商文档配置；不要在路由器上靠 ALG 硬穿。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;保持会话与端口一致&lt;/strong&gt;：RTP 端口段在 PBX、防火墙、路由器三处保持一致；开启 keep-alive 或 OPTIONS 探测，避免 NAT 绑定提前老化。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;验证&lt;/strong&gt;：外呼、被叫、转接、会议各测一遍，确认双向语音；连续通话 30 分钟以上不断；抓包确认 SDP 未被中间设备改写，RTP 双向收发。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;根因分析&#34;&gt;&lt;a href=&#34;#%e6%a0%b9%e5%9b%a0%e5%88%86%e6%9e%90&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;根因分析&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;直接根因是 &lt;strong&gt;路由器的 SIP ALG 对 SIP 报文做了不完整的改写：SDP 中的媒体地址/端口与 Contact 头不一致，对端把 RTP 发到了错误地址，造成单向语音；会话定时器的 re-INVITE 也因 Contact 错误失败，通话在 30 秒左右被挂断&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;更深一层，是把 NAT 穿越的责任交给了路由器的 ALG。SIP 是一个把地址写在报文里的协议，NAT 会破坏这些地址；正确的做法是由最了解自身拓扑的 PBX/SBC 来做地址转换和代理，而不是让一个通用路由器去猜。ALG 的实现质量参差不齐，遇到加密信令、非标准端口、多网卡场景更容易出错。&lt;/p&gt;&#xA;&lt;p&gt;还有一层是“默认开启”的隐形配置。路由器出厂默认打开 SIP ALG，安装时没人注意；旧办公室的路由器恰好 ALG 实现正常或默认关闭，搬家换设备后问题才暴露。VoIP 上线验收只测了“能打通”，没有测“双向语音”和“长通话”，所以问题在上线后才被用户发现。&lt;/p&gt;&#xA;&lt;h2 id=&#34;预防措施&#34;&gt;&lt;a href=&#34;#%e9%a2%84%e9%98%b2%e6%8e%aa%e6%96%bd&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;预防措施&#xD;&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;路由器基线配置默认关闭 SIP ALG/SIP Helper，VoIP 场景明确记录；更换出口设备时按基线复核。&lt;/li&gt;&#xA;&lt;li&gt;VoIP 上线验收包含四项：双向语音、长通话（30 分钟以上）、转接/会议、抓包确认 SDP 未被改写。&lt;/li&gt;&#xA;&lt;li&gt;SIP 与 RTP 端口映射写成文档，PBX、防火墙、路由器三处保持一致；RTP 段变更时同步更新。&lt;/li&gt;&#xA;&lt;li&gt;优先使用运营商 SBC/outbound proxy 或企业 SBC 处理 NAT 穿越，不依赖路由器 ALG。&lt;/li&gt;&#xA;&lt;li&gt;监控通话质量与断线率，按中继和方向聚合；单向语音、30 秒断线这类特征出现时先查 ALG 和端口映射。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;&lt;a href=&#34;#%e6%80%bb%e7%bb%93&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;总结&#xD;&#xA;&lt;/h2&gt;&lt;p&gt;SIP ALG 看起来是在“帮 NAT 的忙”，实际上是在一个它并不了解完整拓扑的位置上改写信令；改对了是运气，改错了就是单向语音和 30 秒断线。VoIP 的 NAT 穿越应该由 PBX/SBC 自己做，路由器只需要关掉 ALG、把端口映射做对。把“能打通”升级成“双向、能久聊、抓包干净”，电话系统才算真正上线。&lt;/p&gt;&#xA;&lt;h2 id=&#34;延伸阅读&#34;&gt;&lt;a href=&#34;#%e5%bb%b6%e4%bc%b8%e9%98%85%e8%af%bb&#34; class=&#34;header-anchor&#34;&gt;&lt;/a&gt;延伸阅读&#xD;&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://blog.5772447.xyz/posts/1a1330a9/&#34; &gt;NAT 回环缺失：内网访问公网域名超时&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://blog.5772447.xyz/posts/66ccc411/&#34; &gt;OpenWrt 升级 firewall4 后旁路由专线全断&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
        </item></channel>
</rss>
