我們知道WebRTC要解決的是兩個瀏覽器之間如何進行實時音視頻互動的問題。從底層來看,就是要解決兩個點之間如何進行高效的網絡傳輸。這就涉及要很多重要的傳輸協議,下面我們針對涉及到的協議進行梳理和說明。
一、NAT(Network Address Translator)
NAT主要做的事情就是地址映射,其作用就是將內網的主機經過NAT的映射生成外網的ip地址和端口,如下圖所示:
NAT產生的原因如下:
- IPV4的地址不夠。
- 處於安全考慮,保證某局域網下的設備的安全。
NAT的種類有以下幾種:
- 完全錐型NAT:所有從同一個內網IP和端口號發送過來的請求都會被映射成同一個外網IP和端口號,並且任何一個外網主機都可以通過這個映射的外網IP和端口號向這台內網主機發送包。
- 地址限制錐型NAT:它也是所有從同一個內網IP和端口號發送過來的請求都會被映射成同一個外網IP和端口號。與完全錐形不同的是,外網主機只能夠向先前已經向它發送過數據包的內網主機發送包。
- 端口限制錐型NAT:端口限制錐形NAT與限制錐形NAT很相似,只不過它包括端口號。也就是說,一台IP地址X和端口P的外網主機想給內網主機發送包,必須是這台內網主機先前已經給這個IP地址X和端口P發送過數據包。
- 對稱型NAT:所有從同一個內網IP和端口號發送到一個特定的目的IP和端口號的請求,都會被映射到同一個IP和端口號。如果同一台主機使用相同的源地址和端口號發送包,但是發往不同的目的地,NAT將會使用不同的映射。此外,只有收到數據的外網主機才可以反過來向內網主機發送包。
二、STUN(Session Traversal Utilities for NAT)
STUN即NAT會話穿透實用工具[RFC5389],用於進行UAT穿透,采用的是典型的客戶端/服務端模式。客戶端發送請求,服務端進行響應。
STUN是一個C/S架構的協議,支持兩種傳輸類型。一種是請求/響應類型,由客戶端給服務端發送請求並等待服務端響應;另一種是指示類型,由服務器或者客戶端發送指示,另一方不產生響應。兩種類型的傳輸都包含一個96位的隨機數作為事務ID(transaction ID),對於請求/響應類型,事務ID允許客戶端將響應和產生響應的請求連接起來;對於指示類型,事務ID通常作為debugging aid使用。
STUN報文和大多數網絡類型的格式一樣,是以大端編碼(big-endian)的,即最高有效位在左邊。所有的STUN報文都以20字節(160位)的頭部開始,后面跟着若干個屬性。
2.1 STUN報文頭部
STUN頭部包含了STUN消息類型,magic cookie,事務ID和消息長度,如下:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0| STUN Message Type | Message Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Magic Cookie | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | Transaction ID (96 bits) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
下面來說明一下報文頭部的各個數據的意義:
- 前兩位必須設置為00,這樣可以在當STUN和其他協議復用的時候,用來區分STUN包和其他數據包,如RTP數據的報頭前兩位為01。
- Message Length 字段存儲了信息的長度,以字節為單位,不包括20字節的STUN頭部。由於所有的STUN屬性都是都是4字節對齊(填充)的,因此這個字段最后兩位應該恆等於零,這也是辨別STUN包的一個方法之一。
- STUN Message Type 是14位是消息類型,其中包括消息類型和消息主方法。
- Magic Cookie 字段包含固定值0x2112A442,這是為了前向兼容RFC3489,因為在classic STUN中,這一區域是事務ID的一部分。另外選擇固定數值也是為了服務器判斷客戶端是否能識別特定的屬性。還有一個作用就是在協議多路復用時候也可以將其作為判斷標志之一。
- Transaction ID 字段是個96位的標識符,用來區分不同的STUN傳輸事務。對於request/response傳輸,事務ID由客戶端選擇, 服務器收到后以同樣的事務ID返回response;對於indication則由發送方自行選擇。事務ID的主要功能是把request和response聯系起來,同時也在防止攻擊方面有一定作用。服務端也把事務ID當作一個Key來識別不同的STUN客戶端,因此必須格式化且隨機在0~2^(96-1)之間。重發同樣的request請求時可以重用相同的事務ID,但是客戶端進行新的傳輸時,必須選擇一個新的事務ID。
2.2 STUN 屬性
在STUN報文頭部之后,通常跟着0個或者多個屬性,每個屬性必須是TLV編碼的(Type-Length-Value)。其中Type字段和Length字段都是16位,如下:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Value (variable) .... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.3 STUN 通信過程
1. 產生一個Request或Indication
當產生一個Request或者Indication報文時,終端必須根據上文提到的規則來生成頭部,class字段必須是Request或者Indication,而method字段為Binding或者其他用戶拓展的方法。屬性部分選擇該方法所需要的對應屬性。
2. 發送Requst或Indication
目前,STUN報文可以通過UDP,TCP以及TLS-over-TCP的方法發送,其他方法在以后也會添加進來。STUN的使用者必須指定其使用的傳輸協議,以及終端確定接收端IP地址和端口的方式。
下面說明一下使用不同方式發送報文的通信機制:
- 通過UDP發送:當使用UDP協議運行STUN時,STUN的報文可能會由於網絡問題而丟失。可靠的STUN請求/響應傳輸是通過客戶端重發request請求來實現的,因此,在UDP運行時,Indication報文是不可靠的。STUN客戶端通過RTO(Retransmission TimeOut)來決定是否重傳Requst,並且在每次重傳后將RTO翻倍。具體重傳時間的選取可以參考相關文章,如RFC2988。重傳直到接收到Response才停止,或者重傳次數到達指定次數Rc,Rc應該是可配置的,且默認值為7。
- 通過TCP或者TCP-over-TLS發送:對於這種情景,客戶端打開對服務器的連接。在某些情況下,此TCP鏈接只傳輸STUN報文,而在其他拓展中,在一個TCP鏈接里可能STUN報文和其他協議的報文會進行多路復用(Multiplexed)。數據傳輸的可靠性由TCP協議本身來保證。值得一提的是,在一次TCP連接中,STUN客戶端可能發起多個傳輸,有可能在前一個Request的Response還沒收到時就再次發送了一個新的Request,因此客戶端應該在確認所有STUN事務都已完成之前保持TCP鏈接打開。
3. 接受STUN消息
當STUN終端接收到一個STUN報文時,首先檢查報文的規則是否合法,即前兩位是否為0,magic cookie是否為0x2112A442,報文長度是否正確以及對應的方法是否支持。
如果消息類別為Success/Error Response,終端會檢測其事務ID是否與當前正在處理的事務ID相同。如果使用了FINGERPRINT拓展的話還會檢查FINGERPRINT屬性是否正確。
完成身份認證檢查之后,STUN終端會接着檢查其余未知屬性。
3.1 處理Request
如果請求包含一個或者多個強制理解的未知屬性,接收端會返回error response,錯誤代碼420(ERROR-CODE屬性),
而且包含一個UNKNOWN-ATTRIBUTES屬性來告知發送方哪些強制理解的屬性是未知的。服務端接着檢查方法和其他指定要求,如果所有檢查都成功,
則會產生一個Success Response給客戶端。
-
3.1.1 生成Success Response或Error Response
- 如果服務器通過某種
驗證方法(authentication mechanism)
通過了請求方的驗證,那么在響應報文里最好也加上對應的驗證屬性。 - 服務器端也應該加上指定方法所需要的屬性信息,另外協議建議服務器返回時也加上SOFTWARE屬性。
- 對於Binding方法,除非特別指明,一般不要求進行額外的檢查。當生成Success Response時,服務器在響應里加上XOR-MAPPED-ADDRESS屬性。
對於UDP,這是其源IP和端口信息,對於TCP或TLS-over-TCP,這就是服務器端所看見的此次TCP連接的源IP和端口。
- 如果服務器通過某種
-
3.1.2 發送Success Response或Error Response
- 發送響應時候如果是用UDP協議,則發往其源IP和端口,如果是TCP則直接用相同的TCP鏈接回發即可。
3.2 處理Indication
如果Indication報文包含未知的強制理解屬性,則此報文會被接收端忽略並丟棄。如果對Indication報文的檢查都沒有錯誤,則服務端會進行相應的處理,
但是不會返回Response。對於Binding方法,一般不需要額外的檢查或處理。收到信息的服務端僅需要刷新對應NAT的端口綁定。
由於Indication報文在用UDP協議傳輸時不會進行重傳,因此發送方也不需要處理重傳的情況。
3.3 處理Success Response
如果Success Response包含了未知的強制理解屬性,則響應會被忽略並且認為此次傳輸失敗。客戶端對報文進行檢查通過之后,就可以開始處理此次報文。
以Binding方法為例,客戶端會檢查報文中是否包含XOR-MAPPED-ADDRESS屬性,然后是地址類型,如果是不支持的地址類型,則這個屬性會被忽略掉。
3.4 處理Error Response
如果Error Response包含了未知的強制理解屬性,或者沒有包含ERROR-CODE屬性,則響應會被忽略並且認為此次傳輸失敗。
隨后客戶端會對驗證方法進行處理,這有可能會產生新的傳輸。
-
到目前為止,對錯誤響應的處理主要基於ERROR-CODE屬性的值,並遵循如下規則:
- 如果error code在300到399之間,客戶端被建議認為此次傳輸失敗,除非用了ALTERNATE-SERVER拓展;
- 如果error code在400到499之間,客戶端認為此次傳輸失敗;
- 如果error code在500到599之間,客戶端可能會需要重傳請求,並且必須限制重傳的次數。
任何其他的error code值都會導致客戶端認為此次傳輸失敗。
三、TURN(Traversal Using Replays around NAT)
TURN的全稱為Traversal Using Relays around NAT,是STUN/RFC5389的一個拓展,主要添加了Relay功能。如果終端在NAT之后,那么在特定的情景下,有可能使得終端無法和其對等端(peer)進行直接的通信,這時就需要公網的服務器作為一個中繼,對來往的數據進行轉發。這個轉發的協議就被定義為TURN。TURN和其他中繼協議的不同之處在於,它允許客戶端使用同一個中繼地址(relay address)與多個不同的peer進行通信。
如果TURN使用於ICE協議中,relay地址會作為一個候選,由ICE在多個候選中進行評估,選取最合適的通訊地址。一般來說中繼的優先級都是最低的。TURN協議被設計為ICE協議(Interactive Connectivity Establishment)的一部分,而且也強烈建議用戶在他們的程序里使用ICE,但是也可以獨立於ICE的運行。值得一提的是,TURN協議本身是STUN的一個拓展,因此絕大部分TURN報文都是STUN類型的,作為STUN的一個拓展,TURN增加了新的方法(method)和屬性(attribute)。
操作概述
在典型的情況下,TURN客戶端連接到內網中,並且通過一個或者多個NAT到達公網,TURN服務器架設在公網中,不同的客戶端以TURN服務器為中繼和其他peer進行通信,如下圖所示:
Peer A Server-Reflexive +---------+ Transport Address | | 192.0.2.150:32102 | | | /| | TURN | / ^| Peer A | Client’s Server | / || | Host Transport Transport | // || | Address Address | // |+---------+ 10.1.1.2:49721 192.0.2.15:3478 |+-+ // Peer A | | ||N| / Host Transport | +-+ | ||A|/ Address | | | | v|T| 192.168.100.2:49582 | | | | /+-+ +---------+| | | |+---------+ / +---------+ | || |N| || | // | | | TURN |v | | v| TURN |/ | | | Client |----|A|----------| Server |------------------| Peer B | | | | |^ | |^ ^| | | | |T|| | || || | +---------+ | || +---------+| |+---------+ | || | | | || | | +-+| | | | | | | | | Client’s | Peer B Server-Reflexive Relayed Transport Transport Address Transport Address Address 192.0.2.1:7000 192.0.2.15:50000 192.0.2.210:49191
在上圖中,左邊的TURN Client是位於NAT后面的一個客戶端(內網地址是10.1.1.2:49721),連接公網的TURN服務器(默認端口3478)后,服務器會得到一個Client的反射地址
(Reflexive Transport Address, 即NAT分配的公網IP和端口)192.0.2.1:7000,此時Client會通過TURN命令創建或管理ALLOCATION
,allocation是服務器上的一個數據結構,包含了中繼地址的信息。服務器隨后會給Client分配一個中繼地址,即圖中的192.0.2.15:50000,另外兩個對等端若要通過TURN協議和Client進行通信,可以直接往中繼地址收發數據即可,TURN服務器會把發往指定中繼地址的數據轉發到對應的Client,這里是其反射地址。
Server上的每一個allocation都唯一對應一個client,並且只有一個中繼地址,因此當數據包到達某個中繼地址時,服務器總是知道應該將其轉發到什么地方。但值得一提的是,一個Client可能在同一時間在一個Server上會有多個allocation,這和上述規則是並不矛盾的。
傳輸
在協議中,TURN服務器與peer之間的連接都是基於UDP的,但是服務器和客戶端之間可以通過其他各種連接來傳輸STUN報文,比如TCP/UDP/TLS-over-TCP. 客戶端之間通過中繼傳輸數據時候,如果用了TCP,也會在服務端轉換為UDP,因此建議客戶端使用UDP來進行傳輸. 至於為什么要支持TCP,那是因為一部分防火牆會完全阻擋UDP數據,而對於三次握手的TCP數據則不做隔離.
分配(Allocations)
要在服務器端獲得一個中繼分配,客戶端須使用分配事務. 客戶端發送分配請求(Allocate request)到服務器,然后服務器返回分配成功響應,並包含了分配的地址.客戶端可以在屬性字段描述其想要的分配類型(比如生命周期).由於中繼數據實現了安全傳輸,服務器會要求對客戶端進行驗證,主要使用STUN的 long-term credentail mechanism.
發送機制(Send Mechanism)
client和peer之間有兩種方法通過TURN server交換應用信息,第一種是使用Send
和Data
方法(method),第二種是使用通道(channels),兩種方法都通過某種方式告知服務器哪個peer應該接收數據,以及服務器告知client數據來自哪個peer.
Send Mechanism使用了Send和Data指令(Indication).其中Send指令用來把數據從client發送到server,而Data指令用來把數據從server發送到client.
四、ICE(Interactive Connectivity Establishment)
ICE跟STUN和TURN不一樣,ICE不是一種協議,而是一個框架(Framework),它整合了STUN和TURN。
其模型如下:
如上圖所示,如果A想與B通信,那么其過程如下:
1). A收集所有的IP地址,並找出其中可以從STUN服務器和TURN服務器收到流量的地址;
2). A向STUN服務器發送一份地址列表,然后按照排序的地址列表向B發送啟動信息,目的是實現節點間的通信;
3). B向啟動信息中的每一個地址發送一條STUN請求;
4). A將第一條接收到的STUN請求的回復信息發送給B;
5). B接到STUN回復后,從中找出那些可在A和B之間實現通信的地址;
6). 利用列表中的排序列最高的地址進一步的設備間通信。
由於該技術是建立在多種NAT穿透協議的基礎之上,並且提供了一個統一的框架,所以ICE具備了所有這些技術的優點,同時還避免了任何單個協議可能存在的缺陷。因此,ICE可以實現在未知網絡拓撲結構中實現的設備互連,而且不需要進行對手配置。另外,由於該技術不需要為VoIP流量手動打開防火牆,所以也不會產生潛在的安全隱患。
五、參考文章:
1). P2P通信標准協議(一)之STUN:https://www.cnblogs.com/pannengzhi/p/5041546.html
2). STUN和TURN技術淺析:https://blog.csdn.net/dxpqxb/article/details/75003701
3). P2P技術詳解(四):P2P技術之STUN、TURN、ICE詳解:http://www.52im.net/forum.php?mod=viewthread&tid=557&highlight=ICE