修复《Kamailio实战》中的一个大Bug

有读者在《Kamailio实战》第19页发现一个大Bug。

原文内容如下:

Record-Route

当一个Proxy收到一个SIP消息时,它可以决定是否留在SIP传输的路径上,即后续的SIP消息是否还要经过它。比如在A呼叫B的通信上,如果Proxy只起到“找到B”的作用,则它可以将第一个消息原样传送,B回送的消息将可以不经过Proxy而直接回到A上,如图1-14所示。

图 1-14

如果Proxy想保留在SIP路径上,则它在将消息转发到下一跳之前要把它自己的地址加到Record-Route头域中。那么,当B在回复响应消息的时候,就会将消息回到Record-Route指定的地址上,如图1-15所示。

图 1-15

↓↓↓修改以后的内容如下(改得比较多):


Record-Route

当一个代理服务器转发一个SIP消息时,它可以决定是否留在SIP传输的路径上,即后续的SIP事务是否还要经过它。比如在A呼叫B的通信上,如果代理服务器只起到“找到B”的作用,则它可以将第一个事务相关消息(包括INVITE和200 OK)进行转发,而后续的事务(ACK以及BYE和200 OK)可以不经过代理服务器而直接回到A上,如图1-14所示。

图 1-14

如果代理服务器想保留在SIP路径上,则它在进行消息转发时把它自己的地址加到Record-Route头域中。那么,在后续的事务请求都会发到Record-Route指定的地址上,如图1-15所示。

图 1-15

注意: SIP消息是以事务为单位的,所以Record-Route头域会影响后续的事务。在同一个事务中,回复消息会回到请求消息Via头域中的地址上(如果有rport则会回到接收到的消息的来源地址上1)。不同的事务,如果有Record-Route头域,则后域的事务请求消息(如ACK或BYE)会发到Record-Route头域指定的地址上,否则,会发到Contact头域指定的地址上。在实际应用中,有时会遇到呼叫(INVITE-200 OK)能接通,但ACK或BYE收不到的情况,这时候就需要检查第一个事务中的Record-Route或Contact头域是否正确。这种情况经常会出现,尤其是在网络中有NAT的情况下。

有了上面这些基础知识,下面我们可以看看Kamailio的应用了。事实上,这些基础知识略枯燥,也不是那么容易懂,也可以先学习后面的内容,再回过来复习这部分,或许更有助于理解。


↑↑↑以上是修改后的内容,勘误到此结束。


其实,Record-Route跟转发是否有状态是两个不同的概念,这个概念在SIP中是有用的,但是在SIP Proxy中是没有用的。在SIP中,Record-Route是用来保留SIP路径的,而转发是否有状态是用来保留SIP事务的。在SIP Proxy中,Record-Route是没有用的,因为Proxy不会保留SIP路径,而转发是否有状态是有用的,因为Proxy需要保留SIP事务(比如收到一个200 OK回复消息是否能找到先前对应的请求消息,如果找不到,就是无状态的;如果能找到,就是有状态的,就能进行更多的出错处理,如进行失败处理、继续走备用路由等)。

出现这个Bug的原因是我对SIP的研究不够深入,没有做足够的验证,弄混了Record-Route与转发是否有状态的区别。接受大家批评。

唯一值得欣慰的是很多读者都对出现这个错误表示理解,并说由于这个错误加深了对这些概念的认识,更有用。

感谢大家的理解与支持。退一万步讲,治学还是应该严谨的。书中还有其它印刷错误,我会在后续的版本中一并修正。

完整的勘误信息在这里:/correction.html

Footnotes

  1. 关于rport参见后面3.1.7节(19)。这个说法也不是绝对的。有些UAS实现中,为了防止被恶意攻击,会忽略rport,而是严格使用Via头域中的地址;而有的UAS实现中,即使没有rport,也会当作有rport来处理,这样更便于NAT穿越。