为什么 SIP 通话能通过 VPN 注册却不发送音频
注册和音频走的是不同路径。沿着一条通话穿过隧道,看清 PBX 能用哪些地址,以及 RTP 究竟停在哪里。
注册成功几乎说明不了音频的情况。软电话可以与办公室 PBX 保持有效绑定数小时,却仍然只有沉默。隧道只承载有人主动送进去的数据包,而一通电话会走三条独立路径:绑定、对话建立和 RTP 流。把它们分开之后,故障就落在某一条路径上,而不是落在 VPN 这个词上。
设想一台家用 Wi-Fi 上的笔记本电脑,通过一条已批准的隧道拨打办公室分机。PBX 认证了用户,接受了 REGISTER,分机显示为可用,但通话接通后一个方向完全没有声音。
注册绑定的是联系人,而不是媒体路径
REGISTER 请求要求注册服务器保存一条从记录地址到一个或多个联系 URI 的映射。这条映射只回答一个很窄的问题:新的对话现在应该发往哪里。它对媒体应该发往哪里只字不提,注册被接受也不能证明后续的 INVITE 会携带可达的媒体地址。注册还会按计时器过期,因此停止刷新的电话会失去来电,而它的隧道看起来仍然健康。要盯住联系人的过期时间,而不是隧道状态。
当软电话位于隧道之后时,联系人头域可能携带私有地址。如果 PBX 把它转发给另一个端点,就会建立一个指向被叫无法到达的网络的对话。在 PJSIP 端点上设置 rewrite_contact=yes 会让 PBX 用它观察到的源地址进行替换,这往往就是响铃与超时之间的差别。
INVITE 提供什么,以及谁能使用它
带有 SDP 正文的 INVITE 会提出主叫希望在哪里接收媒体:一个地址、一个端口以及一份编解码列表。被叫用自己的地址和端口作答,随后双方各自把 RTP 发往对方提出的位置。如果主叫提出的是只存在于自家网络的 192.168.x.x 地址,那么无论信令多么干净,被叫都没有地方可以发送音频。伪装会改写在离开路由器时的 IP 头,但从不改写 SDP 正文内部的文本。
这个缺口解释了经典的单向通话:信令能工作,是因为两端都能到达 PBX;音频失败,是因为有一端被告知要发往一个只存在于另一个 NAT 之后的地址。
| Path | Who picks the address | Typical failure |
|---|---|---|
| REGISTER | Softphone, rewritten by the registrar if configured | Binding expires or points at a private address |
| INVITE and SDP | Each endpoint in its own offer or answer | Offer names a media address nobody can route to |
| RTP | PBX relay policy or the two endpoints | Port range blocked, or no return path |
由谁承载音频是配置选择
信令和媒体是两种不同的角色。代理可以整通电话都留在信令路径上,而完全不碰任何一个 RTP 包。PBX 是否成为媒体中继取决于配置,而不是隧道是否存在。
在直接媒体模式下,两端自己交换 RTP,这在一个局域网里工作良好,而当一侧位于很窄的端口范围之后时就会很糟。
设置 direct_media=no 会把 PBX 拉入媒体路径,使两条腿都终止在它控制的地址上,用带宽和处理器换取可预测的寻址。中继时 PBX 仍然必须通告一个可达地址。在多宿主主机上,pjsip.conf 中的 external_media_address 和 external_signaling_address 决定 SDP 和 Via 头里出现什么。如果不设置它们,PBX 可能把自己的局域网地址提供给唯一路径是隧道另一端的呼叫者。
在动设置之前先追踪每个方向
通话进行时,先从 PBX 的套接字表看起:ss -uanp | grep -E '5060|10000' 会显示 RTP 端口是否已绑定,以及使用的是哪个本地地址。如果媒体范围内没有任何绑定,说明中继没有启用,两端在直接对话。然后在软电话一侧用 tcpdump -ni any -s0 udp portrange 10000-20000 -w rtp.pcap 抓包。只有出包没有入包,就把问题缩小到回程路径,或缩小到被要求使用的那个地址;抓包为空则说明媒体根本没有到达隧道接口。用 sngrep 抓信令,可以看到实际发出的 SDP 连接行,从而回答另一半问题。
把连接行里的地址,与远端真正能够路由到的地址作比较。仅这一项比较,就能比任何配置审查更快地解决大多数单向音频报告。
加密止于隧道边缘
TLS 上的 SIP 保护它所配置的那一跳信令,SRTP 在两端协商后保护媒体,隧道保护其自身端点之间的流量。这些保护彼此不能替代。在隧道内加密的通话,仍可能在出网关后以明文形式走向 PBX,这是设计决策而不是缺陷。
在关闭工单之前,按顺序确认三件事:注册是新鲜的,SDP 携带远端可达的地址,数据包在媒体端口上双向流动。只要有一项不成立,隧道就不是问题所在。修好失败的那条路径,然后重跑同样的抓包来确认变化。保留改动前后的抓包,下一次单向报告就会变成五分钟的检查,而不是一整个下午。