您当前的位置是:  首页 > 资讯 > 文章精选 >
 首页 > 资讯 > 文章精选 >

关于SIP Proxy处理中的八大疑问讨论

2019-03-25 14:00:46   作者:james.zhu   来源:CTI论坛   评论:0  点击:


  在SIP呼叫过程中,SIP代理服务器具有非常重要的作用。呼叫双方通过SIP代理对呼叫定位管理,在通过代理时,代理服务器可能删减一些必要的字段,也可能修改一些请求的字段,满足完成呼叫的必要条件,达成一个完整的呼叫流程。那么,为什么SIP代理服务器会修改这些需求?笔者归纳了八个非常核心的问题,理解了这基本的八个问题会帮助读者彻底了解代理的角色和修改的原因。
  前面我们很多文章是从比较大的宽泛的角度来讨论SIP呼叫。关于proxy代理的定义,我们需要从官方的定义做寻找答案。根据RFC3261的定义,SIP proxy是:
  SIP proxies are elements that route SIP requests to user agent . servers and SIP responses to user agent clients.  A request may traverse several proxies on its way to a UAS.  Each will make routing decisions, modifying the request before forwarding it to the next element.
  https://tools.ietf.org/html/rfc3261#section-16
  为了回答这几个核心的问题,今天,我们从比较细节的流程来分析呼叫处理流程的创建。首先,结合上面的图例,我们需要了解proxy在对下游UA继续发送INVITE之前,它需要做哪些方面的处理?事实上,proxy在对下游发起INVITE之前,它需要做一些预处理工作。因为需要做这些工作,所以会导致我们对proxy产生的六大疑问,这也是比较重要的关于SIP创建呼叫所经常面对的终极问题。这八个终极问题涉及了Route header,Request URL,MAX-Forwards,Via header,100 Trying,ACK直接互发。下面,我们逐一针对这些常见的问题进行比较细致的分析。
  1、为什么移除Route header
  在讨论Route功能之前,我们首先说明一下Route的基本概念。在RFC3261中规定,此头是用来强制request路由多个proxy,很多环境环境可能经过多个proxy来处理呼叫。
  The Route header field is used to force routing for a request through  the listed set of proxies.
  https://tools.ietf.org/html/rfc3261#section-20.34
  如果用户需要了解具体的测试场景,用户可以下载任意一个开源平台的测试环境来进行测试。
  在前面的文章中我们已经介绍过,如果UAC需要发起一个呼叫的话,可以通过INVITE的地址request URL来查询定位服务器和注册服务器,然后进行呼叫。实际上,我们这里忽略了一个非常核心的header-Route。大家现在看看这个基本的示例:
  在实际发起请求的过程中,如果Route存在的话,request其实首先根据Route对代理服务器发起请求,然后再发送INVITE中的具体账号信息。这里,Route可以是FQDN格式,此头则通过DNS查询来获得IP地址。
  这个请求抵达下一个proxy以前,此Route地址会在proxy中移除。因为,这个Route的任务已经完成。另外,从双方的INVITE消息中可以看出,针对这个INVITE的请求中,UAS端的消息中已经移除了Route header。
  因此,笔者提醒读者必须理解以下“黄金定律”:
  1. Route 头决定proxy下一跳的路由地址
  2. 继续下一跳之前,移除Route header
  3. Route头比request URL具有更高优先级
  4. 如果Route不存在,则使用request URL
  5. Route header支持FQDN查询处理,解析为IP地址
  6. 路由总是使用最顶端Route header地址(后面介绍)
  在以前的介绍中,我们已经介绍了Route header, request URL,Contact address和Via 地址。现在,笔者简单总结几个路由地址的区别:
  • Route header是针对下一跳的路由,如果有此头,则request会根据此header被路由到下游
  • Request URL:如果Route header不存在的话,则请求根据此header路由。
  • Contact header:终端IP地址,为其他终端提供subsequent requests返回路由,例如ACK或者BYE消息发送。
  • Via header: 支持UAC地址或者proxy地址,为下游设备提供返回响应的路由,总是从Via 顶部地址优先路由,proxy在转发到下游前移除自己的地址。
  这里我们可以看到,经过proxy到达UAS时,Route需要移除,然后根据request URL来对UAS做呼叫路由。所以,必须移除Route header,否则,协议处理的流程会发生冲突。
  2、为什么需要替换Request URL
  在以前的很多讨论中,我们讨论了如何通过AOR查询对应的Contact地址,然后进行呼叫的多个示例。现在,让我们再回顾一次呼叫的流程处理:
  首先,呼叫方发起INVITE以后,定位服务器会一步步查询所属domain地址,然后查询注册表,如果有注册的数据内容,进行AOR和Contact的地址解析,然后proxy替换这个request URL,对Contact进行INVITE请求。当然,处理过程中也涉及了如果不在正常处理流程中的其他处理方式,我们这里不做进一步讨论。
  根据以上处理流程我们可以看出,首先,定位服务器需要查询此呼叫的AOR是否存在或者属于此定位服务器支持的domain。如果此domain存在的话,则进行AOR解析,然后替换成Contact地址,proxy最后呼叫这个具体的Contact地址或request URL。但是,这里读者一定要注意,proxy做了两个主要的工作。为了满足前面我们提到的Route 头优先路由和无Route header情况下的处理原则,proxy在对对端发送INVITE之前,proxy需要移除Route header,只有这样,INVITE请求才能根据Request URL进行路由。在以下示例消息中,当proxy再次对被呼叫方发起INVITE之前,已经移除了Route header,终端路由根据请求地址来路由。
  因此,proxy对下游UAC发送INVITE之前,替换了AOR地址,使用了请求地址,而且移除了Route header,替换为request URL,这样可以保证请求时通过请求URL地址路由。
  3、为什么MAX-Forwards需要递减
  在比较复杂的SIP呼叫环境中,一个呼叫可能经过多个domain和定位服务。如果其中一个proxy设置错误的话,可能导致一个定位查询的回环,这样UAC就会收到482 Rejected 的消息。为了防止回环的发送,在定位查询过程中,每成功通过一个proxy,Max-Forwards的计数器就会自动减一,直到抵达最终UAC。
  在SIP消息中,如果出现了大量的Via header的话,读者一定要注意,这可能发生了回环。导致这样错误可能是某些地址设置问题。读者需要检查具体的配置文件。
  以下是一个检测到回环的流程,经过多个接点的检查以后,Max-Forwards可能最后递减成了0,这样说明检测到了loop。经过一点时间检查,最后对UAC发送482 消息。
  4、为什么proxy增加一个Via header
  为了让下游UA获悉自己的返回地址,每经过一个proxy,proxy必须自己主动添加自己的地址作为一个新的Via header。如果呼叫请求经过了多个proxy以后,那么这个Via 记录就会不断增加,并且,Via 头根据顺序来进行增加,最新的Via header会出现在Via 头最顶端。所有的Via 添加类似于一个队列处理。在增加了一个新的Via以后,proxy必须对最顶端(Via header)返回一个100 Trying? 为什么呢? 因为,proxy必须对上游proxy说明自己的状态,通知上游proxy已经收到了proxy的请求。
  如果双方呼叫通过了多个跳转以后,每经过一个proxy会增加一个自己的Via header,直到抵达最后的UAC地址。最后的UAC地址则包含了多个Via header。底部是最起始的地址,最顶部是最近地址。
  当UAC接听呼叫后,返回响应消息时,则按照请求路径的相反的处理流程依次进行处理。首先,通过顶部第一个Via地址返回到 proxy 3, proxy 然后从Via header 移除自己的地址,按照Via 地址,返回到proxy 2。最终返回到发起呼叫的UAC地址。每经过一跳就移除自己本身的Via地址。
  5、为什么100 Trying没有返回
  在前面的章节中,我们通过一封信的方式解释了INVITE请求中几个主要的头字段的功能说明。Via header就是其中之一,其主要作用下游终端知道通过这个地址返回进一步的响应消息,负责返回响应的路由路径管理。根据RFC3261的规定,Via 头的定义是:
  The Via header field indicates the transport used for the transaction and identifies the location where the response is to be sent.
  https://www.ietf.org/rfc/rfc3261.txt
  根据RFC3261的定义和我们以前的介绍,本身100 Trying就是一个可靠性传输的响应机制,其主要目的就是让保证上下游之间的可靠性传输,没有承担其他的功能角色。
  如果经过多个proxy处理时,怎么能够保证双方之间的通信是可靠的? 100 Trying是一个高效的方式来实现这个简单的功能。如果proxy对下游proxy发送一个INVITE以后,对端对自己上游发送一个100 Trying,说明自己已经接收到了这个请求,proxy就知道对端的状态。因此,proxy此刻的任务已经完成。因此,proxy也不会对上游UAC发起方发送100 Trying,避免了资源浪费。另外,回顾我们以前的讨论,100 Trying不能再次重复转发,不像其他响应,例如180 ring。proxy仍然需要对上游UAC发送180 ring消息,保证会话的完整性。
  6、为什么使用Route set路由
  前面我们介绍过Route set和Via的区别,读者可以回顾前面的讨论来了解Via的作用。Proxy通过Via获得了最终地址,双方已经确认了地址消息,proxy完成了其工作。双方确认了状态以后,UAC会保存对端的Contact地址作为响应的直接地址。下来,UA1 可以根据这个Contact地址,直接对UA2发送ACK确认。
  但是,读者一定要注意,当UAC2收到UAC1 的地址后,在返回200 OK时,UAC2会把自己的地址添加到Contact中作为Contact地址,这样做的目的是通知UAC1,UAC2的地址就是200 OK中的这个Contact地址。UAC双方最终的通信是通过Route set来进行,双方保存了Contact地址以后,双方可以直接通过Contact地址发送ACK或者BYE消息。
  因此,这里UAC之间的直接通信是通过Route set来实现,而不是Via 地址。
  7、为什么UAC之间直接发送ACK
  首先,我们需要理解proxy的角色,proxy的主要功能就是定位被呼叫方的Contact地址和进行下一跳代理功能。为了协助UAC进行通信,Proxy经过多个定位和路由最终找到UAC,UAC已经对proxy发送了100 Trying,其主要任务已经完成。为了降低系统资源的负载,proxy不再参与其流程处理,双方通过route set的地址可以直接发送ACK确认消息,因此不再需要通过proxy继续处理ACK或BYE消息。
  注意,我们这里没有涉及有状态代理和无状态代理的内容,那是另外一个话题,不在我们这里讨论的范围。读者不要对这里的讨论产生疑惑,我们仅讨论UAC之间ACK的发送问题。
  8、不同域名之间的呼叫处理
  两个不同域名用户之间的呼叫中,proxy需要进行地址查询或定位查询,找到相应的domain定位服务器。如果被呼叫方用户不属于自己domain的用户,则根据domain来查询DNS,通过DNS获得domain地址以后,再继续查询确认好的定位服务器。定位服务器最终找到相应的用户帐户。那么,现在的问题来了,上游proxy如何处理这个AOR地址和路由呢?下面,我们看看具体的处理流程。首先,第一个proxy需要添加自己的地址,然后发送到下游定位服务器。
  这里比较关键的服务是在第二个定位服务器和代理的处理上。第二个定位服务器在对自己终端发送INVITE之前,必须先移除Route地址,proxy使用request URL地址来做呼叫路由。为什么需要这样处理?因为,根据前面讲到的route header的使用原则,在最后的INVITE中如果没有Route header,则使用request URL。因此,第二个proxy在发送INVITE之前,必须移除Route header,使用requerst URL做呼叫路由。这样就完成了不同domain之间的呼叫。
  9、总结
  我们今天通过八个问题的讨论,基本上回答了很多SIP用户的关于Proxy处理的疑惑。这八个终极问题涉及了Route header,Request URL,MAX-Forwards,Via header,100 Trying,ACK直接互发,和不同域名之间的呼叫流程。另外,笔者也针对几个主要的路由地址归纳了几个不同,方便读者进一步清晰地了解SIP路由的概念。最后,笔者需要读者重点掌握SIP头路由的几个黄金定律,它们是决定如何路由的前提条件。
  参考资料:
  https://www.tutorialspoint.com/session_initiation_protocol/session_initiation_protocol_proxies_and_routing.htm
  https://www.slideshare.net/JonasBorjesson/aboutsip-routing
  https://tools.ietf.org/html/draft-byerly-sip-hide-route-00
   
  关注微信公众号:asterisk-cn,获得有价值的Asterisk行业分享
  Asterisk freepbx 中文官方论坛:http://bbs.freepbx.cn/forum.php
  Asterisk freepbx技术文档: www.freepbx.org.cn
  融合通信商业解决方案,协同解决方案首选产品:www.hiastar.com
  Asterisk/FreePBX中国合作伙伴,官方qq技术分享群(3000千人):589995817
 

【免责声明】本文仅代表作者本人观点,与CTI论坛无关。CTI论坛对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。请读者仅作参考,并请自行承担全部责任。

专题

CTI论坛会员企业