Stun详解与作用

来源:互联网 发布:软件在线授权系统 编辑:程序博客网 时间:2024/04/29 15:06
STUN是RFC3489规定的一种NAT穿透方式,它采用辅助的方法探测NAT的IP和端口。毫无疑问的,它对穿越早期的NAT起了巨大的作用,并且还将继续在NAT穿透中占有一席之地。

 

STUN的探测过程需要有一个公网IP的STUN server,在NAT后面的UAC必须和此server配合,互相之间发送若干个UDP数据包。UDP包中包含有UAC需要了解的信息,比如NAT外网IP,PORT等等。UAC通过是否得到这个UDP包和包中的数据判断自己的NAT类型。


假设有如下UAC(B),NAT(A),SERVER(C),UAC的IP为IPB,NAT的IP为 IPA ,SERVER的 IP为IPC1 、IPC2。请注意,服务器C有两个IP,后面你会理解为什么需要两个IP。 

(1)NAT的探测过程
STEP1:B向C的IPC1的port1端口发送一个UDP包。C收到这个包后,会把它收到包的源IP和port写到UDP包中,然后把此包通过IP1C和port1发还给B。这个IP和port也就是NAT的外网IP和port,也就是说你在STEP1中就得到了NAT的外网IP。

熟悉NAT工作原理的朋友可以知道,C返回给B的这个UDP包B一定收到(如果你不知道,去读下我的其它文章)。如果在你的应用中,向一个STUN服务器发送数据包后,你没有收到STUN的任何回应包,那只有两种可能:1、STUN服务器不存在,或者你弄错了port。2、你的NAT设备拒绝一切UDP包从外部向内部通过(不支持cone NAT)。

当B收到此UDP后,把此UDP中的IP和自己的IP做比较,如果是一样的,就说明自己是在公网,下步NAT将去探测防火墙类型,我不想多说。如果不一样,说明有NAT的存在,系统进行STEP2的操作。

STEP2:B向C的IPC1发送一个UDP包,请求C通过另外一个IPC2和PORT(不同与SETP1的IP1)向B返回一个UDP数据包(现在知道为什么C要有两个IP了吧,为了检测cone NAT的类型)。

我们来分析一下,如果B收到了这个数据包,那说明什么?说明NAT来着不拒,不对数据包进行任何过滤,这也就是STUN标准中的full cone NAT。遗憾的是,full cone nat太少了,这也意味着你能收到这个数据包的可能性不大。如果没收到,那么系统进行STEP3的操作。

STEP3:B向C的IPC2的port2发送一个数据包,C收到数据包后,把它收到包的源IP和port写到UDP包中,然后通过自己的IPC2和port2把此包发还给B。

和step1一样,B肯定能收到这个回应UDP包。此包中的port是我们最关心的数据,下面我们来分析:

如果这个port和step1中的port一样,那么可以肯定这个NAT是个CONE NAT,否则是对称NAT。道理很简单:根据对称NAT的规则,当目的地址的IP和port有任何一个改变,那么NAT都会重新分配一个port使用,而在step3中,和step1对应,我们改变了IP和port。因此,如果是对称NAT,那这两个port肯定是不同的。

如果在你的应用中,到此步的时候PORT是不同的,恭喜你,你的STUN已经死了。如果不同,那么只剩下了restrict cone 和port restrict cone。系统用step4探测是是那一种。

STEP4:B向C的IP2的一个端口PD发送一个数据请求包,要求C用IP2和不同于PD的port返回一个数据包给B。

我们来分析结果:如果B收到了,那也就意味着只要IP相同,即使port不同,NAT也允许UDP包通过。显然这是restrict cone NAT。如果没收到,没别的好说,port restrict  NAT.


(2)SIP怎么使用STUN

个人认为这是个很不值得提的问题,不过有许多人问我,还是简要提一下。其实这是个很简单的问题,SIP通过STUN得到NAT的外网IP和SIP的信令监听端口的外网port,替换SIP注册包中的contact头中的IP和port,然后注册。这样就可以确保当有人呼叫你的的时候注册服务器能找到你。需要提醒你的是,NAT发现一个连接超过一段时间后没有活动,它就会关闭这个影射,因此你必须间隔一端时间发送一个数据包出去以keep alive。

另外,当你要和别人建立RTP通讯的时候,不要忘记把你的SDP中的IP和PORT改成公网IP和PORT。

-----------------------------------------------------------------------------------------------------------------------------------------------------------

stun协议的作用

STUN协议的全称是Simple Traversal of User Datagram Protocol Through Network Address Translators,主要功能是检测是否位于NAT后面,如果位于NAT后面,经过NAT转换后的地址和端口是什么,另外可以检测NAT的类型。

基本思想

在私网内部安装一个STUN client,在公网上安装一个STUN Server,STUN协议定义了一些消息格式,大体上分成Request/Response,client向server发送request,server发送response给client。如何检测STUN client是否在NAT后面呢?原理很简单,Server在收到client的UDP包以后,Server将接收到该包的地址和端口利用udp传回来给client,client把这些地址和端口与本机的ip地址和端口进行比较,如果不同,说明在NAT后面,否则就位于NAT后面。为了检测不同类型的NAT,STUN协议定义了一些消息属性,要求Server有不同的动作,比如发送响应的时候使用不同的IP地址和端口,或者改变端口等等。STUN协议对NAT可能有效,但是对防火墙就无能为力了,因为防火墙可能不会打开UDP端口。

NAT分类

STUN协议将NAT粗略分为4种类型,即Full Cone、Restricted Cone、Port Restricted Cone和Symmetric。举个实际例子来说明这四种NAT的区别:

A机器在私网(192.168.0.4)

NAT服务器(210.21.12.140)

B机器在公网(210.15.27.166)

C机器在公网(210.15.27.140)

现在,A机器连接过B机器,假设是 A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:8000)-> B(210.15.27.166:2000)。

同时A从来没有和C通信过。

则对于不同类型的NAT,有下列不同的结果:

Full Cone NAT:C发数据到210.21.12.140:8000,NAT会将数据包送到A(192.168.0.4:5000)。因为NAT上已经有了192.168.0.4:5000到210.21.12.140:8000的映射。

Restricted Cone:C无法和A通信,因为A从来没有和C通信过,NAT将拒绝C试图与A连接的动作。但B可以通过210.21.12.140:8000与A的 192.168.0.4:5000通信,且这里B可以使用任何端口与A通信。如:210.15.27.166:2001 -> 210.21.12.140:8000,NAT会送到A的5000端口上。

Port Restricted Cone:C无法与A通信,因为A从来没有和C通信过。而B也只能用它的210.15.27.166:2000与A的192.168.0.4:5000通信,因为A也从来没有和B的其他端口通信过。该类型NAT是端口受限的。

Symmetric NAT:上面3种类型,统称为Cone NAT,有一个共同点:只要是从同一个内部地址和端口出来的包,NAT都将它转换成同一个外部地址和端口。但是Symmetric有点不同,具体表现在:只要是从同一个内部地址和端口出来,且到同一个外部目标地址和端口,则NAT也都将它转换成同一个外部地址和端口。但如果从同一个内部地址和端口出来,是到另一个外部目标地址和端口,则NAT将使用不同的映射,转换成不同的端口(外部地址只有一个,故不变)。而且和Port Restricted Cone一样,只有曾经收到过内部地址发来包的外部地址,才能通过NAT映射后的地址向该内部地址发包。

现针对Symmetric NAT举例说明:

A机器连接过B机器,假使是 A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:8000)-> B(210.15.27.166:2000)

如果此时A机器(192.168.0.4:5000)还想连接C机器(210.15.27.140:2000),则NAT上产生一个新的映射,对应的转换可能为A(192.168.0.4:5000)-> NAT(转换后210.21.12.140:8001)-> C(210.15.27.140:2000)。此时,B只能用它的210.15.27.166:2000通过NAT的210.21.12.140: 8000与A的192.168.0.4:5000通信, C也只能用它的210.15.27.140:2000通过NAT的210.21.12.140:8001与A的192.168.0.4:5000通信,而 B或者C的其他端口则均不能和A的192.168.0.4:5000通信。



下面对SIP协议产生NAT穿透问题,作一些解释;及提出解决的办法。 
1、大致有4种类型的NAT
a) Full Cone 完全圆锥体
b) restricted cone 受限制的圆锥体
c) port restricted 端口受限制的圆锥体
d) symmetric 对称的
其中a,b,c 也称作非对称的NAT

2、SIP终端在NAT后面,其工作有可能出现问题。原因是SIP信令走的路径,和媒体流走的路径不一样。

3、Full Cone 完全圆锥体NAT
因特网上的任何PC,可以发送数据包到IP:port对;而NAT将这个IP:port对(公网 上的)映射到内网的IP:port对(私有网络的)。

4、restricted cone 受限制的圆锥体NAT
NAT
外面的PC,只有那些内网中已有PC与之联系过的PC,才能通过这个映射 进来。例如,我通过内网的一台机器,IP 地址是10.1.1.1:123,与PC(a)联系,则PC(a)也可以通过这个NAT的映射,联系到我。而PC(b)则不行。
10.1.1.1:123 —NAT —> 202.70.65.78:10000 ——pc(a)
如果pc(b)也发送数据到 202.70.65.78:10000,则不会有数据送到10.1.1.1:123。

补充说明:
如果我也联系过pc(b),则pc(b)也可以进来了。
10.1.1.1:123 —NAT —> 202.70.65.78:10000 ——pc(b)
如果pc(b)也发送数据到202.70.65.78:10000,则数据送到 10.1.1.1:123。

5、port restricted 端口受限制的圆锥体NAT
除了4的条件外,即不但要检测pc(a)的源IP地址,还要检测其端口是否 与前面也一样。
10.1.1.1:123 —>NAT—->202.70.65.78:10000 —–> pc(a)[213.123.324.34:8000]

这个NAT只会接收从IP地址 213.123.324.34 且端口为 8000来的数据,让进入到10.1.1.1:123。

6、对称的NAT 这是关系描述最简单的一个
10.1.1.1:1000 —-NAT —–> 200.123.123.34:1234 —-pc(a)
10.1.1.1:1000 —-NAT —–> 200.123.123.34:2222—-pc(b)
这种NAT的IP:port对,对每个外部的程序,都是不同的。因而每一个外部的程 序,都有自己的映射(NAT分配的IP:port对)。而前面的三种,多个外部程序,可能共用一个NAT的IP:port对。

7、RTP的问题
在RTP的消息正文内,有UA能够成功通信所需要的一些信息。这种消息正文,就叫做SDP消息。

问题在于,SIP终端(UA)可能对NAT一无所知。因而在SDP中包含的IP地址,通常使用内部的IP地址,也就是SIP终端知道的IP。这样, 当通信的对方想与SIP终端通信时,就查看SDP消息中的IP地址,但是什么也没有得到,因为这里使用的是内部IP地址。

下面举个例子说明:

INVITE sip:040600@192.168.20.2:5060 SIP/2.0.
Record-Route: <sip:143.248.130.35;ftag=3a7ceb24a6ac50c4;lr=on>.
Via: SIP/2.0/UDP 143.248.130.35;branch=z9hG4bK758e.976609c7.0.
Via: SIP/2.0/UDP
192.168.20.3;rport=1024;received=223.178.140.109;branch=z9hG4bK34efcab2403aa20d.
From: "Iqbal" <sip:040618@sip.dom.com>;tag=3a7ceb24a6ac50c4.
To: <sip:040600@sip.dom.com>.
Contact: <sip:040618@223.178.140.109:1024>.
Supported: replaces.
Call-ID: 7f2c327896a5b0e1@192.168.20.3.
CSeq: 8717 INVITE.
User-Agent: Grandstream HT487 1.0.5.18.
Max-Forwards: 16.
Allow: IN
VITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE.
Content-Type: application/sdp.
Content-Length: 343.
.
v=0.
o=040618 8000 1 IN IP4 192.168.20.3.
s=SIP Call.
c=IN IP4 192.168.20.3.
t=0 0.
m=audio 38660 RTP/AVP 0 8 4 18 2 15 99.
a=sendrecv.
a=rtpmap:0 PCMU/8000/3.
a=rtpmap:8 PCMA/8000/3.

SIP消息的标题头,类似于邮件的标题头。从后往前看,从From行开始,看到第一个Via行,这是SIP终端自己认为的IP地址,例如 192.168.20.3。但是SIP代理服务器是聪明的,它知道这个消息是从哪里发过来的,它添加了rport和接收到的标志:
Via: SIP/2.0/UDP
192.168.20.3;rport=1024;received=223.178.140.109;branch=z9hG4bK34efcab2403aa20d.

也就是说,SIP代理服务器,知道发消息的SIP终端的公网地址是223.178.140.109:1024。
这样,SIP代理服务器是可 以与SIP终端通信的,因为它知道SIP终端的公网地址。

但是,可怜的老式的RTP被阻塞了,因为它的标题头如下:
v=0.
o=040618 8000 1 IN IP4 192.168.20.3.
s=SIP Call.
c=IN IP4 192.168.20.3.
t=0 0.
m=audio 38660 RTP/AVP 0 8 4 18 2 15 99.
a=sendrecv.
a=rtpmap:0 PCMU/8000/3.
a=rtpmap:8 PCMA/8000/3.

SIP终端期望从端口 port m=38660 且IP地址IP c= 192.168.20.3来接收RTP数据,而这个192.168.20.3:38660,就是通信的对方试图发RTP数据的目的地址。

这就是SIP电话振铃总是能够听到,而接起来却没有声音的原因。

8 解决办法 告诉SIP终端,不要如此傻地工作,而要想办法知道NAT分配给自己的端口映射。

并将公网的IP地址:端口放到SDP消息中。这样,SIP终端就问NAT….。或者是问公网的某个服务器,NAT分配给自己的映射是什么。

9 问NAT。 这种办法就是使用UPnP协议,另外去参见UPnP的资料。

10 问公网上的某个服务器。 如STUN服务器。
SIP终端发送一个探测数据包,到公网上的服务器。公网上的服务器会发回数据包,会包含 有关NAT的详细信息。有了这些信息,SIP终端就会知道它是否在NAT后面。这种探测方法,可以用于上面4种NAT,都有效。例如SIP终端从 10.1.1.1:1000发送一个数据包,则SDP消息中包含的是m=1000 and c=10.1.1.1。但是,如果SIP终端先进行NAT探测,则会知道NAT会分配公网的IP:端口是212.134.123.23:12345。则 SIP终端直接在SDP消息写m=12345,c=212.134.123.23。

产生的问题 因为NAT的端口分配是动态的,因而有可能会改变。这样,在发送了NAT探测消息后,要很快地发送出SIP消息。而且,SIP终端发送数据的端口和接收数 据的端口要是一样的。

注意受限制的圆锥体(包括端口受限制的圆锥体)NAT,它不让回来的消息进来,除非SIP终端先发了一个数据包给它。因而,SIP终端需要先发一个 数据包给对方。这样以后对方来的数据,就可以进入NAT内部了(不过,不需要为这个操作担心,有办法的)。

上面的办法在对称的NAT后面,不能够工作。因为,对称的NAT,它在分配给SIP终端外部的IP:port时,每次都变化(不同的对方不一样)。 也就是SIP终端在探测NAT时,得到的IP:port,与它后来发SIP消息时,分配的IP:port不一样。这样,对方来的语音数据就进不来,因为对 方得不到正确的IP:port。

11、上面描述的过程,其实就是采用STUN协议时,解决问题的过程。就是SIP终端向STUN服务器发探测NAT的数据包。

12、对称的NAT 解决办法 就是在公网上放一个中转语音流的服务器。这个中转语音流的服务器有时就是一个Out Bound proxy。注意,这个中转语音流的服务器,可能会成为瓶颈。由于语音要经过中转语音流的服务器,所以路径增长了,音质会变差。所以,对称的NAT,要 SIP能够工作,总之是个麻烦。

不过,目前大多数的NAT,都可以做“虚拟服务器的端口转发”,即将SIP工作需要的端口转发到SIP终端上去。如果在NAT设备上,做了“虚拟服 务器的端口转发”,则NAT会保留SIP工作需要的端口,专用于SIP终端,这样SIP终端就相当于是在一个Full Cone完全圆锥体的NAT后面,SIP用STUN工作没有问题。SIP终端需要的端口数是这样确定的,一个端口用于SIP信令,比如5060。RTP端 口的数量,取决于通话的路数。一路通话需要2个RTP端口。每增加一路通话,则需要多2个端口。
只支持一路通话的SIP话机,需要NAT映射3个 端口。
前面三种的NAT,可统称为非对称的NAT。非对称的NAT,都可以用STUN协议穿过NAT

将对称的NAT,通过端口转发的方式,变为完全圆锥体的NAT,是解决NAT问题的最好办法。首先应当用这种办法来解决。没有办法映射端口,再想其 它的办法。当然,建议大家不要买那种不能够映射端口的宽带路由器,那样的路由器太差了。

===================================================================================

2. 案例

2.1. asterisk作为服务器,在nat之外,voip电话在nat之内。

      2.1.1. 呼叫来自nat后面的电话终端,asterisk把媒体发到私网ip

  

如果voip电话没有使用stun或其他机制来获取它的公网地址(并把公网地址写入invite消息),asterisk就把媒体发到私网地址,被路由器丢弃导致单通。

这种情况发生在sip.conf中主叫用户配置了nat=never,或nat=no,或nat=rfc3581。与nat的类型无关。

那就只有nat=route可以了,即主叫发送媒体到asterisk后,asterisk再按原路返回rtp.(asterisk如何获得rtp的路由?)
 

    2.1.2. 呼叫来自nat后面的电话,asterisk发送媒体到错误端口


voip电话能检测到自己的公网ip并写入invite头,asterisk知道rtp的ip地址。

如果nat类型是Cone(full cone,restricted cone),nat转发rtp到asterisk的端口不是原来voip电话的媒体端口,asterisk按照原端口发送rtp。这时nat就不知道把从asterisk收到的rtp包转给谁(cone是内网ip:port对应外网ip:port,一一对应)。

 nat=route或nat=yes可以解决这个问题。

 如果只有一个电话在nat后面,可以做端口映射,把该电话使用的rtp端口都做内外网映射。

如果有多个电话在nat后面,则可以把rtp端口范围不重叠的分派给每个电话,然后分别做端口映射。(?)

 

使用symmetric nat或stun服务器也可以解决这个问题