SIP穿越NAT&FireWall解决方案
 
SIP 从私网到公网会遇到什么样的问题呢?<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

1. 包的地址转换。
2. SIP
消息里面的 SIP 地址转换。
3. SIP
消息里面的 SDP 中的 RTP 地址转换。

网络现存结构复杂, SIP 服务提供商并不一定是 NETWORK 提供商,很难要求客户只能使用某种方式的 NAT&FireWall 。如何找出一种可以满足各种网络的 SIP 应用解决方案呢?

NAT
Firewall 的基本原理

首先, NAT 的几种方式:
Full Cone
:当一台私网内的主机向公网发一个包,其本地地址和端口是 {A:B} NAT 会将其私有地址 {A:B} 转换成公网地址 {X:Y} 并绑定。任何包都可以通过地址 {X:Y} 送到该主机的 {A:B} 地址上, NAT 会将任何发送到 {X:Y} incoming 包的地址 {X:Y} 转换成 {A:B}

Partial/Restricted Cone
:当一台私网内的主机向公网发一个包,其本地地址和断口是 {A:B} NAT 会将其私有地址 {A:B} 转换成公网地址 {X:Y} 并绑定。任何包都可以通过地址 {X:Y} 送到该主机的 {A:B} 地址上,但是, NAT 只为第一个发往 {X:Y} 的包绑定成 {A:B}|{X:Y}<->{C:D}, 其中 {C:D} 是那个包的源地址和端口。也就是说,只有来自 {C:D} 的包才能于主机 {A:B} 通信。
Partial
Restricted Cone 的区别是 Partial 只绑定 incoming packet IP 地址,而 Restricted Cone 会绑定 incoming packet IP 地址和端口。也就是上面描述的那种情况。

Symmetric Cone
:当一台私网内的主机向公网某台主机发送一个包, {A:B}à{C:D} NAT 会将其地址 {A:B} 转换成 {X:Y} ,并为其绑定成 {A:B}|{X:Y}<->{C:D} NAT 只接受来自 {C:D} incoming packet ,将它转给 {A:B} 。也就是说,如果私网内的主机要向外面发送一个包,它必须要知道对方的公网 IP 和端口。但如果对方也是处于一个私网内,它就很难获知对方的公网 IP 和端口。
由此可见, Symmetric Cone 条件最严格, Partial/Restricted Cone 次之, Full Cone 条件最不严格。

下面再看看 Firewall 的基本策略:
Firewall
会判断所有的包是来自内部( Inside )还是外部 (Outside)

一般,允许所有来自 inside 的包发出去。

一般,允许来自 Outside 的包发进来,但这个连接必须是由 Inside 发起的。

一般,禁止所有连接由 Outside 发起的包发进来。

一般, firewall 会允许几个信任的 outside 主机,他们可以发起建立连接,并发包进来。

    
所有 NAT Firewall 都是对于 TCP/IP 层以下进行处理和过滤的,而 SIP 应用的地址是在应用层。所以必须采用其他的途径来解决这一问题。
针对不同的 NAT 类型,可以有不同的解决方案。
1. UPnP
2. External Query
3. STUN
4. ALG

   
其中前 3 种都是由 SIP Client( 包括 UA Proxy) 通过某种手段或协议在 INVITE 之前获取自己的公网地址和端口。需要 SIP Client 提供额外支持,并且也不适应所有的 NAT 方式。
    ALG(Application Layer Gateway)
适应所有 NAT 方式,并不需要 SIP Client 做任何额外的支持。它对 Application 层的 SIP 信令进行处理和修改,从而做到透明转换地址。
下面针对一个案例详细描述 ALG 的解决方案。

SIP ALG 解决方案
    ALG
修改 SIP 消息里面的 SIP 地址和端口和 SDP 消息里面的 RTP 地址和端口 , 其中 RTP 地址和端口要向 RTP Proxy 请求获得, RTP Proxy 分配自己的一个空闲的地址和端口,并和这个 Call 保持映射关系。并为分配给呼叫双方的地址和端口进行绑定,这样,呼叫双方的 RTP 连接地址都是 RTP Proxy, RTP Proxy 经过中转,发至真正的目的地。假设,有两个 SIP Client 要进行通信, Ada Bob ,他们分别位于自己的 Nat Server 后面:

其中两台 NAT Server 都是 Symmetric Cone 方式。
其信令流程如下:
1.         Ada
发起信令, Invite Bob
IP Packet IP Address:
From: 192.168.1.10:5060
To: 128.97.41.56:5060 (SIP ALG)
SIP Msg IP Address:
From: 192.168.1.10:5060
To: 128.97.41.56:5060
SDP Body IP Address for RTP:
192.168.1.10:10024

2.        
经过 NAT Server NAT 将其私有地址转换成公网地址,并绑定,由于是采用 Symmetric Cone 方式,所以还绑定目的的 IP 地址。
{192.168.1.10:5060}|{128.96.41.1:5678}<->{128.97.41.56:5060}
IP Packet IP Address:
From: 128.96.41.1:5678
To: 128.97.41.56:5060 (SIP ALG)
SIP Msg IP Address:
From: 192.168.1.10:5060
To: 128.97.41.56:5060
SDP Body IP Address for RTP:
192.168.1.10:10024

3.         SIP ALG
接受到该 INVITE ,发现其包的 IP 地址和 SIP IP 地址不同,就判断其是经过 NAT ,于是就将其相关的 SIP IP 地址修改。
并检查它的 Body 中是否是包含 SDP 信息,如果是,且有 RTP 地址, SIP ALG 就会去向 RTP Proxy 请求一个公网 RTP 地址来代替原有的 RTP 地址。
IP Packet IP Address:
From: 128.97.41.56:5060
To: 128.96.63.25:5566
SIP Msg IP Address:
From: 128.96.41.1:5678
To: 128.96.63.25:5566
(下一跳的地址)
SDP Body IP Address for RTP:
128.97.44.5:3000

4.        
因为 Bob 不断的向 SIP ALG 发送注册包,所以,它的 NAT Server 始终为它保留着这么个绑定, {<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />10.0.0.12:5060}|{128.96.63.25:5566}<->{128.97.41.56:5060} 。所以,由 SIP ALG 发出的 INVITE Bob 能收到。
Bob
返回 200 OK ,包含 SDP 信息。
IP Packet IP Address:
From: 10.0.0.12:5060
To: 128.97.41.56:5060
SIP Msg IP Address:
From: 10.0.0.12:5060
To: 128.97.41.56:5060
(下一跳的地址)
SDP Body IP Address for RTP:
10.0.0.12:10002

5.         NAT Server
将其包的 IP 地址修改。发往 SIP ALG

6.         SIP ALG
接受到该 200 OK ,发现其包的 IP 地址和 SIP IP 地址不同,就判断其是经过 NAT ,于是就将其相关的 SIP IP 地址修改。
并检查它的 Body 中是否是包含 SDP 信息,如果是,且有 RTP 地址, SIP ALG 就会去向 RTP Proxy 请求一个公网 RTP 地址来代替原有的 RTP 地址。
IP Packet IP Address:
From: 128.96.63.25:5566
To: 128.96.41.1:5678
SIP Msg IP Address:
From: 128.96.63.25:5566
To: 128.96.41.1:5678
(下一跳的地址)
SDP Body IP Address for RTP:
128.97.44.5:3002

7.        
此时, RTP Proxy 为这个 Session 保持着这么个连接绑定
{128.97.44.5:3000|128.97.44.5:3002}

8.         Ada
收到 200 OK ,它认为对方的 RTP 地址是 128.97.44.5:3002 。将与其建立连接。
Bob 认为对方的 RTP 地址是 128.97.44.5:3000 。将与其建立连接。

9.        
RTP Proxy 3002 端口收到包,它可以从包地址获得 Ada RTP 公网 IP
RTP Proxy 3000 端口收到包,它可以从包地址获得 Bob RTP 公网 IP
从而, RTP Proxy 会将 3002 端口收到的包转发到 Bob RTP 公网 IP
同样, RTP Proxy 会将 3000 端口收到的包转发到 Ada RTP 公网 IP

这样,一个通话的连接就成功建立。
    SIP ALG
的部署因为无论如何,都需要所有 RTP 包经过 RTP Proxy ,所以所有的 MS 都要有修改 SDP 的能力,而只有 SIP ALG 需要有修改 SIP 消息的能力。让用户配置自己的 Proxy 是什么,避免公网的 SIP Client 也经过 SIP ALG ,造成没必要的消耗。
补充如果 SIP ALG 发现 INVITE 包的地址和 SIP 地址是一致的话,它将不对这个包进行修改,它认为这个包是来自公网,或者 SIP Client 具备了穿越 NAT 的能力。但它会修改其 SDP IP 地址。
ISSUE:

1.       如果 SDP 描述的是单工工作的话, RTP 连接无法建立,因为 RTP proxy 始终无法知道沉默方的 RTP 公网 IP
2.      
每次建立 RTP 连接,某一方的 RTP 包可能会丢掉若干个,直到 RTP proxy 获知另一方的 RTP 公网 IP
3.      
是否应该强制任何 RTP 包都要经过 RTP Proxy ,无论它们都是来自公网,可以直接连接。我想是的,因为主叫方是不知道被叫方的网络环境的。
4.      
如果多个 RTP Proxy 进行均衡,如何保证为主叫方分配 IP Proxy 和为被叫方分配 IP Proxy 是一致的呢?(它们必须是同一台 Proxy
可以增加一个 header ,比如 RTP proxy ,这个 header 只有 SIP ALG 认识。
5.      
如果 SIP 消息加密,就无法修改其 SIP IP 地址。