SIP 严格路由和松散路由以及RFC3261例子分析

一、请求路由

1、参考IP中的概念:严格路由是must,松弛路由是preferred.

严格路由:

     实际指发送者指明了必须经过的路由,如果下一跳路由找不到就返回错误;

松弛路由:

    只是指出一个routelist,但并不要求消息必须严格经过任意两个相邻路由记录,可以经过其他路由器后再到下一跳指定地点。

Eg:如路由指定A-B
     严格路由要求到了A后下一跳必须是B
    松弛路由要求到了A后可以先到C再到B,只要B即可。

2、SIP中的路由:严格路由和松散路由
我们经常可以看到在Router字段中设置的SIP URI经常有一个lr的属性,例如,这就是表示这个地址所在的ProxyServer是一个Loose Router,如果没有lr属性,它就是一个StrictRouter。


严格路由(Strict Routing):可以理解为比较“死板”的理由机制,这种路由机制在SIP协议的前身RFC 2534中定义,其机制非常简单。

处理步骤:

S_1、接收到的消息的request-URI必须是自己的URI

S_2、把第一个Route头域“弹”出来,并把其中的URI作为新的request-RUI.

S_3、然后把该消息路由到新的request-URI。

松散路由(Loose Routing,lr):该路由机制较为灵活,也是SIP路由机制的灵魂所在,在SIP根本大典RFC 3261中定义。

处理步骤:

L_1、Proxy首先会检查消息的request-URI是不是自己属于自己所负责的域。如果是,它就会通过定位服务将该地址“翻译”成具体的联系地址

          并以此替换掉原来的request-URI;否则,它不会动request-URI。

L_2、Proxy检查路由表中的第一个地址是否为自己,如果是则从表中删除。

L_3、Loose Router首先会检查Request URI是否为自己插入到路由表中的地址, 如果不是,则不作处理;如果是,则取出Route字段的最后

          一个地址作为Request URI地址,并从Route字段中删去最后一个地址。

L_4、Loose Router检查下一跳是否为Strict Router。如果不是,不处理;否则,将Request URI插入到路由表表尾,并用下一跳地址

       (Strict Router的地址)更新Request URI。

L_5、如果路由表为空,则路由给Request URI(如果路由表非空,且request-uri不是自身,那么应该路由到最上面的路由表去???)。

总结:Route的优先级高于request-URI的

        可以看到步骤L_3、L_4其实是Loose Router为了兼容Strict Router而做的额外工作.

(如:步骤L_4中如果下一跳为Strict Router,那么必须将下一跳的Strict Router地址更新request-URI,这样这样下一条在受到消息时,检查request-URI时才会和自己匹配,不至于发生错误,因为StrictRouter要求request-URI必须是自己的URI)。

3、SIP中Route和Record-Route头域。

SIP中的Via头域是为了给一个请求消息的响应消息留后路,而Record-Route就是为了给该请求消息之后的请求消息留后路。

【说明】

一个SIP消息每经过一个Proxy(包括主叫),都会被加上一个Via头域,当消息到达被叫后,Via头域就记录了请求消息经过的完整路径。被叫将这些Via头域原样copy到响应消息中(包括各Via的参数,以及各Via的顺序),然后下发给第一个Via中的URI,每个Proxy转发响应消息前都会把第一个Via(也就是它自己添加的Via)删除,然后将消息转发给新的第一个Via中的URI,直到消息到达主叫。

而在一个请求消息的传输过程中,Proxy也可能(纯粹自愿,如果它希望还能接收到本次会话的后续请求消息的话)会添加一个Record-Route头域,这样当消息到达被叫后里面就有会有0个或若干个Record-Route头域。被叫会将这些Record-Route头域并入路由集,并并入自己的路由集,随后被叫在发送请求(和Record-Route属于同一个dialog里面)消息时就会使用该路由集构造一系列Route头域,以便对消息进行路由。

然后,被叫会像上面对待Via头域一样,将Record-Route头域全部原样copy到响应消息中返回给主叫。

主叫收到响应消息后也会将这些Record-Route头域并入路由集,只是它会将其反序。该会话中的后续请求(和Record-Route属于同一个dialog里面)消息的Route头域就会通过路由集构造。

【注意】

Record-Route头域不用来路由,而只是起到传递信息的作用

Record-Route头域不是路由集的唯一来源,路由集还可以通过手工配置等方式得到。

二:应答消息路由
SIP应答消息的路由机制,相对请求来说,比较简单,基本思想就是,请求从哪里来,应答回哪里去。那是如何实现的呢?很简单,Via头域就是完成这个差事的。Via头域表说明了SIP请求实际的路由过程,用于应答消息的回程路由。

三:RFC3261例子解析:

下面就以RFC 3261中的两个实例解释,包括每个步骤的解析。

路由示例1:

场景:

两个UE间有两个Proxy,U1 -> P1 -> P2 -> U2,并且两个Proxy都乐意添加Record-Route头域。

消息流:

【说明】由于我们在此只关心SIP路由机制,因此下面消息中跟路由机制无关的头域都省略了。

U1发出一个INVITE请求给P1(P1是U1的外拨代理服务器):

INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]

P1不负责域domain.com,消息中也没有Route头域,因此通过DNS查询得到负责该域的Proxy的地址并且把消息转发过去。这里P1在转发前就添加了一个Record-Route头域,里面有一个lr参数,说明P1是一个松散路由器,遵循RFC3261中的路由机制。


INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: sip:p1.example.com;lr

P2负责域domain.com,因此它通过定位服务得到[email protected] 对应的设备地址是[email protected],因此用新的URI重写request-URI。消息中没有Route头域,因此它就把该消息转发给request-URI中的URI,转发前它也增加了一个Record-Route头域,并且也有lr参数。

INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route:
Record-Route:

位于u2.domain.com的被叫收到了该INVITE消息,并且返回一个200 OK响应。其中就包括了INVITE中的Record-Route头域。

SIP/2.0 200 OK
Contact: sip:[email protected]
Record-Route:
Record-Route: sip:p1.example.com;lr

被叫此时也就有了自己的路由集:

(,)

并且它本次会话的远端目的地址设置为INVITE中Contact中的URI:

[email protected]

此后被叫在该会话中的请求消息就发到这个URI。同样,被叫在200OK响应中也携带了自己的联系地址,主叫收到该响应消息后也会把本次会话的远端目的地址设置为:

[email protected]

此后主机在该会话中的请求消息就发到这个URI。

同样,主叫也有了自己的路由集,只是跟被叫的是反序的:

(,)

通话完毕后,我们假设主叫先挂机,则主叫发出BYE请求:

BYEsip:[email protected] SIP/2.0
Route: ,sip:p2.domain.com;lr


可以看到,BYE的Route头域正是主机的路由集构造来的。

由于p1在第一个Route中,因此BYE首先发给P1。

P1收到该消息后,发现request-URI中的URI不属于自己负责的域,而消息有Route头域,并且第一个Route头域中的URI正是自己,因此删除之(步骤L_2),并且把消息转发给新的第一个Route头域中的URI,也就是P2:

BYEsip:[email protected] SIP/2.0
Route: sip:p2.domain.com;lr

P2收到该消息后,发现request-URI中的URI不属于自己负责的域(P2负责的是domain.com,而不是u2.domain.com),第一个Route头域中的URI正是自己,因此删除之,此时已经没有Route头域了,因此就转发给了request-URI中的URI(步骤L_5)。

被叫就会收到BYE消息:

BYEsip:[email protected] SIP/2.0

路由示例2:

如果说上面的示例主要关注的是路由流程,那么本示例关注的则是严格路由与松散路由的区别。

场景:

U1->P1->P2->P3->P4->U2

其中,P3是严格路由的,其余Proxy都是松散路由的,并且4个Proxy都很乐意增加Record-Route头域。

消息流:

我们直接给出了到达被叫的INVITE消息:

INVITEsip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route:
Record-Route: Record-Route:
Record-Route:

这中间的其他消息我们就不过问了,直接看一下被叫最后发出的BYE消息大概是什么样子:

BYEsip:[email protected] SIP/2.0
Route:
Route:
Route:
Route: sip:p1.example.com;lr

因为P4在第一个Route里,因此被叫将BYE消息发给了P4(route 优先级大于request-uri)。

P4收到该消息后,发现自己不负责域u1.example.com,但是第一个Route头域中的URI正是自己,因此删除之(步骤L_2)。

P4还发现新的第一个Route头域中的URI是一个严格路由器,因此它把request-URI中的URI添加到最后一个Route的位置,并且将第一个Route“弹出”并且覆盖原来的request-URI(步骤_4)。

然后将消息转发给当前的request-URI,也就是P3。

BYE sip:p3.middle.com SIP/2.0
Route:
Route:
Route: sip:[email protected]

P3收到该消息后,直接把消息作出如下变换并且发给P2:(步骤S_1 S_2 S_3严格路由操作,因为P3是严格路由)

BYE sip:p2.example.com;lr SIP/2.0
Route:
Route: sip:[email protected]

P2收到该消息后,发现消息中的request-URI是自己的,因此在进一步处理先首先对消息做如下变换(步骤L_3):

BYEsip:[email protected] SIP/2.0
Route: sip:p1.example.com;lr


然后,P2发现自己不负责域u1.example.com,第一个Route中的URI也不是自己的,因此将消息转发给该Route去,也就是P1。

P1收到该消息后,发现自己不负责域u1.example.com,但是第一个Route头域中的URI正是自己,因此删除之。消息变成下面的样子:

BYEsip:[email protected] SIP/2.0


既然Route头域已经是空,因此P1把消息发给u1.example.com。

四:备注:

      Loose Routing为了实现对Strict Routing的兼容,做了很多额外的工作.

注:本文在网上收集资料以及RFC3261的进程进行整理和修改,转载请标明出处.

你可能感兴趣的:(协议)