SIP協議的傳輸層原理&報文解析(解讀rfc3581)(待排版) && opensips



關於rfc3581/rport參數的闡述

一:簡述

一般情況下,服務器在接收到request后,應答發向哪里呢?服務器在計算回應應答的算法是一種混合模式,具體說來是這樣的:

1,IP:從哪里接收到的就會給哪里,即ip包上記錄的源地址

2,port:根據sip報文的頭解析出來,

對於處理被NAT包裹的環境中的客戶端,請求是可以發出去的,但是應答卻無法穿透NAT,就要借助rport這個位於via 類型header的param來處理了

  附:目前還借助了“received”這個param in topmost via header,原理是這樣的

 

         服務器會將自己實際從哪個ip上接收到的請求記錄在“received”,通過他可以有助於讓應答穿越NAT。但是沒有指定port,那怎么半呢?

 

二,客戶端

可以在其聲稱的請求中,包含"rport" 這個參數in the top  via header,但是不能有值,這個只是表示我支持該擴展屬性。

當客戶端使用udp將請求發送出去后,他必須在其發送請求的那個ip:port上准備好接收回來的應答,

同時,他還需要在“sent-by”中指定的端口上准備接收。

 

一旦在客戶端和服務器之間有一個NAT存在,那么當請求經過NAT的時候會在nat上創建一條綁定,這個綁定記錄還要保有一個超時時間,保證在這個時間內能夠接收到服務器端的應答。

大部分的udp NAT,這個超時時間設置的是1min,這個遠遠超過了non-invite傳輸的時間。所以,對於non-invite請求,接收到應答是沒問題的。

而,INVITE傳輸則可以是任意的超時時長,所以為了不讓nat把我關掉,客戶端應該每20s就傳一次,這種重傳必須一直延續着,盡管接收到臨時應答了

 

三,服務端

服務器(這里的服務器包括proxy 或者 UAS)在接收到請求之后,會檢查topmost via的頭域,如果頭域中包含“rport”參數 with no value,則把該值設置成接收到請求的源端口號

這個原理等同於服務端在向topmost via中insert “reseived”一樣。實際上,服務端必須要insert一個包含接收請求的源地值的 “reseived”到via中,即使這個源地值域sent-by是一樣的。

注:以上處理域傳輸層協議無關

當一個服務器想要發送應答的時候,他會檢查應答中的topmost via ,如果“sent-protocol”組件指示要使用不可靠傳輸協議比如udp,那么時不可以有“maddr”這個參數的,但是有 “reseived”和“rport”參數,

這個應答必須發送給“reseived”中列出的所有ip,對應的端口為“rport”中指定的,而這個應答必須經由接收請求的那個ip:port發送出去,這么做是為了穿越對稱NAT

當一個server監聽在多interface或者多port上時,他需要記住從哪一個上接收到了請求。對於有狀態proxy,在傳輸期間存儲這些信息也不是什么難題。然而對於無狀態proxy,不會存儲請求和應答的關系,所以不能記住從哪里接收到的請求。

所以,為了實現上述的要求,一個無狀態的proxy就需要把請求中的目的地址和端口號編碼進via 頭域中,一旦這個應答來了,他就可以提取這個信息用於指導如何轉發應答。

 

四,例子

1,A client sends an INVITE to a proxy server which looks like, in part:

   INVITE sip:user@example.com SIP/2.0
   Via: SIP/2.0/UDP 10.1.1.1:4540;rport;branch=z9hG4bKkjshdyff

這個INVITE 請求從源地址:10.1.1.1:4540這個客戶端發出來的,想要到達的目的地是user@example.com
服務proxy的地址為192.0.2.2即proxy.example.com,他會在5060和5070端口上。
於是,請求會發向proxy的5060端口
這個過程會經過nat,所以ip包上的源地值會變成192.0.2.1,而端口號變成9988
proxy接收請求再轉發,但是轉發之前要把
"rport"參數insert到via中,於是頭變成了這樣:
INVITE sip:user@example.com SIP/2.0
   Via: SIP/2.0/UDP proxy.example.com;branch=z9hG4bKkjsh77   ---因為經過了一個proxy嘛,所以肯定要加一個via
   Via: SIP/2.0/UDP 10.1.1.1:4540;received=192.0.2.1;rport=9988
    ;branch=z9hG4bKkjshdyff      ---因為發現接收request的源ip和via中指定的ip不同,所以這里要加上received和rport

   This request generates a response which arrives at the proxy:
(wxy:針對這個請求,proxy會生成一個應答,是如下這個樣子的:) SIP/2.0 200 OK Via: SIP/2.0/UDP proxy.example.com;branch=z9hG4bKkjsh77 Via: SIP/2.0/UDP 10.1.1.1:4540;received=192.0.2.1;rport=9988 ;branch=z9hG4bKkjshdyff

The proxy strips its top Via header field value, and then examines the next one. It contains both a "received" parameter and an "rport" parameter. The server follows the rules specified in Section 4 and sends the response to IP address 192.0.2.1, port 9988, and sends it from port 5060 on 192.0.2.2:
   proxy首先找到top via header,然后檢查他的下一個,他既包含了received也包含了rport參數
於是這個服務器就會根據之前說的原則,將應答發給192.0.2.1:9988,並且是從192.0.2.2:5060上發出去的
   SIP/2.0 200 OK
   Via: SIP/2.0/UDP 10.1.1.1:4540;received=192.0.2.1;rport=9988
    ;branch=z9hG4bKkjshdyff

   This packet matches the binding created by the initial request.
   Therefore, the NAT rewrites the destination address of this packet
   back to 10.1.1.1, and the destination port back to 4540.  It forwards
   this response to the client, which is listening for the response on
   that address and port.  The client properly receives the response.

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

啟動命令:

 /usr/local/opensips/sbin/opensipsctl start

日志:

/opt/opensips/logs


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM