无论从哪些方面,OpenSIPS和Kamailio似乎都可以相互替代。
但是,有几个特殊的地方,你可能要提前考虑,而不要走到死路再回头。
1. 拓扑隐藏
1.1. 最简单的场景:不做拓扑隐藏
假设一个典型架构:
UAC → SIP Proxy → Media Server
例如:
Alice (10.1.1.10)
|
Proxy
|
FreeSWITCH (10.1.2.20)
Alice 呼叫 Bob,发送 INVITE。
原始 SIP 请求:
INVITE sip:bob@example.com SIP/2.0
Via: SIP/2.0/UDP 10.1.1.10:5060
From: <sip:alice@example.com>
To: <sip:bob@example.com>
Call-ID: 123456@10.1.1.10
Contact: <sip:alice@10.1.1.10>
经过 Proxy 转发后:
INVITE sip:bob@10.1.2.20 SIP/2.0
Via: SIP/2.0/UDP proxy.example.com
Via: SIP/2.0/UDP 10.1.1.10
From: <sip:alice@example.com>
To: <sip:bob@example.com>
Call-ID: 123456@10.1.1.10
Contact: <sip:alice@10.1.1.10>
FreeSWITCH 现在可以看到:
- UAC IP:
10.1.1.10 - 内部网络结构
- Proxy 地址
整个网络拓扑完全暴露。
1.2. 使用拓扑隐藏
加入拓扑隐藏后:
UAC → OpenSIPS → FreeSWITCH
代理会 重写关键 SIP 头部。
Alice 发出:
INVITE sip:bob@example.com SIP/2.0
Via: SIP/2.0/UDP 10.1.1.10
Call-ID: 123456@10.1.1.10
Contact: <sip:alice@10.1.1.10>
经过拓扑隐藏:
INVITE sip:bob@10.1.2.20 SIP/2.0
Via: SIP/2.0/UDP proxy.example.com
Call-ID: th-98asdj21
Contact: <sip:hidden@proxy.example.com>
FreeSWITCH 看到的只有:
proxy.example.com
看不到:
- Alice IP
- 内部地址
- 原始 Call-ID
这就是 Topology Hiding。
- 只保留一个Via头
- 删除所有的Record-Route头
- 删除所有的Route头
- 改写Call-ID
- 改写Contact
1.3. 运营商之间的拓扑隐藏
在 VoIP 运营网络里更常见:
Carrier A
|
OpenSIPS (Topology Hiding)
|
Carrier B
如果没有隐藏:
Carrier B 会看到:
Via: SIP/2.0/UDP carrierA-gw1
Via: SIP/2.0/UDP carrierA-switch
Via: SIP/2.0/UDP opensips
可以推断:
- Carrier A 的网关
- SBC
- 内部路由
这是非常敏感的信息。
做了拓扑隐藏后:
Carrier B 只会看到:
Via: SIP/2.0/UDP edge-proxy.example.com
Call-ID: TH-k2j3k23
Contact: <sip:proxy@example.com>
Carrier B 完全不知道:
Carrier A 的网络结构
1.4. 呼叫结束时的拓扑恢复
例如:
BYE sip:hidden@proxy.example.com
代理内部保存了映射:
hidden@proxy → alice@10.1.1.10
于是恢复并发送:
BYE sip:alice@10.1.1.10
对外:
Proxy
对内:
真实地址
1.5. 一个更复杂的真实运营场景
实际上,在真实 VoIP 网络中,如果没有 SIP 拓扑隐藏,一个 INVITE 报文往往可以暴露整个运营网络的结构。很多做安全审计的人只需要抓一个包,就能推断出你的架构。
下面我们用一个真实风格的 SIP 报文来说明。
假设某 VoIP 运营商没有启用拓扑隐藏,对方运营商收到的 INVITE 可能是这样的:
INVITE sip:441234567890@carrierB.net SIP/2.0
Via: SIP/2.0/UDP gw3.carrierA.net:5060;branch=z9hG4bK-342343
Via: SIP/2.0/UDP core-switch1.internal.local:5060;branch=z9hG4bK-983423
Via: SIP/2.0/UDP edge1.carrierA.net:5060;branch=z9hG4bK-238472
From: <sip:+12065550123@carrierA.net>;tag=98324
To: <sip:+441234567890@carrierB.net>
Call-ID: a98sdasdh23@10.12.0.15
Contact: <sip:fs1.internal.local:5060>
Record-Route: <sip:edge1.carrierA.net;lr>
Record-Route: <sip:core-switch1.internal.local;lr>
User-Agent: FreeSWITCH-mod_sofia/1.10
看起来只是普通 SIP 报文,但实际上信息量非常巨大。
从一个 SIP 包能推断什么?
1.5.1. 网络拓扑结构
Via 头会暴露所有经过的节点
gw3.carrierA.net
core-switch1.internal.local
edge1.carrierA.net
攻击者可以推断:
Carrier A Network
edge1.carrierA.net (edge SBC)
|
core-switch1 (routing proxy)
|
gw3.carrierA.net (termination gateway)
只靠一个包就能画出你的 SIP 网络图。
1.5.2. 内网地址
Call-ID: a98sdasdh23@10.12.0.15
暴露:
10.12.0.0/16
攻击者可以判断:
- 内网网段
- 服务器结构
很多 SIP flood 攻击就是这么来的。
1.5.3. 你的软交换类型
User-Agent: FreeSWITCH-mod_sofia/1.10
这直接暴露:
软件版本:
FreeSWITCH 1.10
攻击者会马上去查:
- CVE
- exploit
- SIP fuzzing
1.5.4. 服务器命名规则
fs1.internal.local
core-switch1.internal.local
可以推断:
服务器命名规范:
fs1
fs2
fs3
攻击者甚至可以猜出:
fs2.internal.local
fs3.internal.local
1.5.5. 路由逻辑
通过 Record-Route:
Record-Route: edge1
Record-Route: core-switch1
可以知道:
SIP dialog 会经过哪些节点。
1.5.6. 运营规模
例如:
gw3.carrierA.net
意味着至少:
gw1
gw2
gw3
攻击者知道:
至少三个网关。
1.5.7. 真实攻击案例
很多 VoIP 平台被攻击其实是因为:
SIP header 泄露架构。
攻击流程通常是:
1️⃣ 抓 SIP 包
2️⃣ 提取:
Via
Contact
Call-ID
User-Agent
3️⃣ 建立网络图
Edge Proxy
Core Proxy
Media Server
Gateway
4️⃣ 针对弱点攻击:
- SIP flood
- REGISTER attack
- RTP injection
- SIP scanning
1.5.8. 启用拓扑隐藏后
如果使用 OpenSIPS 或 Kamailio
做 topology hiding,对方看到的包可能变成:
INVITE sip:441234567890@carrierB.net SIP/2.0
Via: SIP/2.0/UDP sip.carrierA.net;branch=z9hG4bK-239423
From: <sip:+12065550123@carrierA.net>;tag=98324
To: <sip:+441234567890@carrierB.net>
Call-ID: TH-23hjk23kjh23
Contact: <sip:hidden@sip.carrierA.net>
Record-Route: <sip:sip.carrierA.net;lr>
User-Agent: SIP Proxy
对方只能看到:
sip.carrierA.net
内部结构完全隐藏。
1.5.9. 一个有意思的事实
很多 Tier-1 VoIP 运营商有一个安全规则:
任何外部 SIP 包不得包含 internal hostname。
例如:
禁止:
*.internal.local
*.lan
10.x.x.x
192.168.x.x
否则就算:
安全事故。
1.6. 拓扑隐藏到底隐藏什么
通常会处理这些头:
Via
Route
Record-Route
Contact
Call-ID
From tag
To tag
目的只有一个:
不让对方看到你的网络结构。
1.7. 一个直观类比
拓扑隐藏就像:
电话转接总机
真实情况:
你 → 总机 → 某个部门
但你看到的始终只有:
公司总机号码
你永远不知道:
- 部门号码
- 内部线路
SIP 拓扑隐藏就是这个作用。
1.8. 拓扑隐藏的实现
上面所有论述,只是说明,在某些领域拓扑隐藏是必须的,虽然kamailio 和 opensips 都提供了拓扑隐藏功能。
但是两者实现差异很大。
- Kamailio
- 拓扑隐藏必须依赖数据库,例如mysql或者redis
- 拓扑隐藏只能把内网地址换成一个假的虚拟地址,无法做多余SIP头的删除
- OpenSIPS
- 基本上能移除所有涉及到网络拓扑的SIP头
- 无需数据库依赖,拓扑映射直接在内存中实现。当然也有缺点,挂了服务就很难恢复。
综上:在拓扑隐藏这个场景下,优先选择OpenSIPS
2. 注册信息集群同步
- kamailio的多节点注册信息同步,依赖DMQ模块,该模块的逻辑就是把注册信息当作SIP消息再分发出去。
- opensips使用cluster模块来同步注册信息
虽然两者似乎都能在多节点同步注册信息, 但是kamailio的节点必须在数据库配置好,无法动态加入节点。
但是OpenSIPS,是可以动态添加节点的,并且节点之间可以进行通信。
综上: 在注册信息同步领域,优先选择OpenSIPS
3. 动态添加端口
kamailio无法在运行过程中新增SIP端口,只能重启。
OpenSIPS在3.x 版本中支持动态添加端口,无需重启。
综上:对于需要动态添加端口的场景,优先选择OpenSIPS
