WebRTC:網絡架構與NAT工作原理
2023年下旬,OpenAI與Livekit的合作[1]在科技圈引起了不小的轟動。這兩家公司聯手,通過WebRTC技術和大型語言模型(LLM)的結合,使AI模型具有了看、聽和說話的能力[2]。這一舉動不僅彰顯了WebRTC在現代通信技術中的重要地位,也為我們揭示了AI與實時通信融合的無限可能。WebRTC技術在大流行后再一次進入技術人的視野,恰好在我們今年打造的產品中,WebRTC也是技術棧的核心。
WebRTC端到端實時通信的效果主要取決于兩個重要因素,一個通信質量,一個是音視頻編解碼質量。對于入門類文章來說,改進通信質量或音視頻編解碼質量還為時尚早,我們亟需了解的是其背后的原理。
在這篇文章以及后續的幾篇文章中,我們先來關注一下“WebRTC網絡通信”。我們會先了解一下WebRTC網絡架構,然后對WebRTC中的難點,諸如NAT打洞、基于信令與ICE的建連等做深入分析。
在這篇文章中,我們先來學習NAT的工作原理,探討不同類型的NAT網絡行為是如何影響點對點通信的,為后續理解WebRTC的NAT打洞(也稱為NAT穿透)和端到端建連做準備。
1. WebRTC網絡架構
我們知道WebRTC(Web Real-Time Communication)是一種支持網頁瀏覽器/應用進行端到端實時語音對話或視頻對話的技術,其中支持端到端建立連接和后續數據傳輸的網絡架構是十分重要的,這也是理解WebRTC技術棧的一個重點。下面是WebRTC網絡架構圖的示意圖:
圖片
這個架構包含以下主要組件:
- 瀏覽器/App:這是進行WebRTC的端(Peer),可以是瀏覽器,也可以是App。WebRTC API在瀏覽器中實現,使得web應用能夠直接訪問媒體設備和建立點對點連接。App也可以利用WebRTC的實現(比如Pion[4])與對端進行RTC通信。
- 信令服務器(Signaling Server):雖然不是WebRTC標準的一部分,但對于WebRTC建立連接至關重要,任何non-trivial的基于WebRTC的系統都會有專屬的信令服務器,它會幫助通信雙方交換會話描述協議(SDP)信息和ICE候選地址。這個在使用Go和WebRTC data channel實現端到端實時通信[5]一文中介紹過,在后續的文章中還會有系統說明。
- STUN服務器(Session Traversal Utilities for NAT):該服務器可以幫助客戶端發現自己的公網IP地址和端口,這個服務器是NAT打洞時所必須的。
- TURN服務器(Traversal Using Relays around NAT):當通過常規方式點對點連接失敗時(通常是NAT打洞失敗),可以使用TURN服務器作為媒體數據的中繼服務器使用。兩端發送的數據都會要通過TURN的中繼才能轉發給對端。
- ICE框架(Interactive Connectivity Establishment):綜合使用各種NAT打洞技術來協助兩端建立連接,這個我們會在后面文章中系統說明。
我們看到這個架構略有些復雜,但該架構允許WebRTC應用在復雜的網絡環境中建立直接的點對點連接,即使客戶端位于NAT或防火墻后面。
2. 網絡世界的真相:我們都在NAT后面
在理想的網絡世界中,每個設備都有一個唯一的公網IP地址,可以直接相互連接和通信。這種理想狀態下,網絡是完全開放和對等的,沒有任何障礙阻止設備之間的直接交互。
但現實情況卻很骨感,出于IPv4地址空間的限制(IPv4地址的數量不夠了)、網絡管理以及網絡安全的考慮,大多數設備都隱藏在NAT(網絡地址轉換)后面。
NAT(網絡地址轉換)技術于1994年由Egevang等人在RFC 1631[6]中提出,旨在作為緩解IPv4地址不足問題的臨時技術方案。通過將私有IP地址和端口映射到公共IP地址和端口,NAT使得在私有網絡中的設備可以使用公共地址(共享一個或多個)訪問互聯網。
NAT轉換示意圖(來自維基百科)
這種技術的出現大大緩解了IPv4地址的緊張狀況,并成為當時乃至現在(IPv6的推廣與使用未及預期)網絡地址管理的重要手段。不過,NAT技術的廣泛應用也意味著大部分設備只有私網IP,無法從外網直接訪問,這一定程度上限制了端到端的直接通信。另外,由于不同類型的NAT行為有所不同,進一步增加了端到端網絡連接的復雜性。
注:私網IP地址是指在局域網(LAN)中使用的IP地址,這些地址不能在公共互聯網(公網)中被路由。私網IP地址主要用于內部網絡中設備之間的通信,通常用于家庭、企業或組織的網絡。根據IETF的標準,私網IP地址的范圍包括(以CIDR(無類域間路由)格式表示):10.0.0.0/8、172.16.0.0/12和192.168.0.0/16。
于是便有了NAT打洞技術(NAT hole punching)。NAT打洞技術為在NAT環境中實現設備間直接通信提供了一種有效的解決方案,它允許位于不同NAT后面的設備建立直接的點對點(P2P)連接,而無需手工配置端口轉發。在P2P文件共享、VoIP通信、在線游戲、即時通信以及視頻會議系統等領域,NAT打洞都有著廣泛的應用。
不過,要理解NAT打洞,我們需要要先得弄清楚NAT的工作原理、主要的NAT類型以及它們的行為差異。
3. NAT的工作原理與主要類型的行為差異
我們先來看看NAT工作原理。
3.1 NAT的工作原理
網絡地址轉換(NAT)的核心工作原理還是比較好理解的,就是在請求數據包通過NAT設備時修改其源IP和源端口信息。以下圖為例,即將內網主機通過X1:x1發往外網主機Y1:y1的網絡請求中的源IP和源端口從X1:x1修改為X1':x1'后,再發給目的端點(Y1:y1)。NAT設備會維護一個映射表(也叫會話表),記錄X1:x1與X1':x1'的映射關系。當請求的應答包回來時(Y1:y1 -> X1':x1'),NAT設備將根據映射表將X1':x1'再替換回X1:x1,這樣應答包就可以正?;氐絏1:x1了。
圖片
為了管理資源(每個NAT的對外端口數量有限),NAT設備會內置超時機制,它會為每個會話/映射設置一個生存時間(TTL)。如果在TTL內沒有新的數據包,這個映射會被刪除。
隨著NAT技術的演進,同時考慮到網絡管理和網絡安全因素,NAT設備出現了不同的映射表管理方式,與之相對應的就出現了不同的NAT類型與行為特征。接下來,我們就來看看NAT的主要類型、映射表的管理方式以及它們的行為差異。
注:NAT打洞的主流方式是通過UDP包,因此下面的關于NAT類型和行為的描述都是基于UDP的。UDP是面向數據報的傳輸層協議,相對于面向連接的TCP,它更加靈活,延遲更低,在實時性要求更高的場景,比如視頻會議、語音通信等。
3.2 NAT的主要類型
根據2003年RFC 3489[7]中對市面上NAT實現類型的歸納,NAT可以分為完全錐形(Full Cone)、受限錐形(Restricted Cone)、端口受限錐形(Port Restricted Cone)和對稱型(Symmetric)四種主要類型。下面我們分別來說一下這四種類型的NAT映射表構成以及行為特征。
3.2.1 完全錐型NAT
完全錐型是最寬松的NAT類型,它在NAT映射表中只存儲了一個四元組:(內網ip(internal_ip), 內網端口(internal_port), 映射ip(external_ip), 映射端口(external_port))。我們看下圖中的完全錐形類型的NAT::
圖片
在上圖中,內部地址X1:x1被映射到了外部地址E:x1',所有從X1:x1發到外部的數據都由E:x1'向外發送。相應的外部應答(比如: Y1:y1 -> E:x1')的流量會在NAT設備上被轉換回到X1:x1的流量。
那么為什么這個類型的NAT會被稱為完全錐形呢?這就要從NAT設備對外部流量的限制來說了。對于NAT設備來說,一旦建立了X1:x1->E:x1'的映射規則,就好比X1在該NAT設備上“打了一個洞”,內部來自X1:x1的流量可以從該洞發送出去,但NAT設備是否允許外部流量從該洞回到X1:x1以及允許哪些流量從該洞返回到X1:x1就決定了該NAT的類型。
如果任何外部主機都可以通過上面的洞E:x1'向內部主機X1:x1發送數據包,那么這個NAT就是完全錐形。我們再用一副示意圖來說明一下完全錐形NAT的行為特點:
圖片
這里故意將右側的外部主機排列成像圓錐的形狀,位于錐子范圍內的所有主機都能通過圖中的“洞”將數據包發到內部主機X1:x1上。
很顯然完全錐形NAT雖然管理簡單,也具有很好的開放性,但它在安全性上較弱,外部很容易利用NAT上的洞向內部主機上的服務發起攻擊。
為此,后面的幾種NAT都是為了增強NAT安全性的,而且一個比一個更嚴格,我們先來看受限錐形NAT。
3.2.2 受限錐型NAT
受限錐形NAT又被稱為IP受限錐型NAT,它在完全錐形NAT的映射表的基礎上,增加了“IP白名單(如下圖中的allowed_external_ips)”,下面是受限錐形NAT的示意圖:
圖片
我們看到:X1主機通過X1:x1在向Y1:y1和Y2:y2分別發起請求后,NAT設備上便有了一條映射規則(一個洞):X1:x1被映射到了外部地址E:x1',但映射表也記錄了兩個請求的目標主機的IP,記錄在規則的allowed_external_ips中。
規則中的這個allowed_external_ips對后續外部主機通過E:x1'向X1:x1發送數據包會做出限制,如下圖:
圖片
我們看到:只有在“白名單”中的IP對應的主機(如Y1、Y2)才可以在“洞”建立后,通過E:x1'向內部主機X1:x1成功發送數據包,其它主機發送的數據包都會被攔截和丟棄。
我們看到上述的限制是限制是基于IP地址的,而位于Y1和Y2上的服務,可以使用任意端口向E:x1'成功發送數據包,這顯然也是一個安全隱患。于是便有了下面限制更為嚴格的端口受限錐形NAT。
3.2.3 端口受限錐型NAT
端口受限錐型NAT在受限錐形NAT映射表的基礎上,又進一步限制了端口,通過allowed_external_endpoints實現對外部端點的限制,如面示意圖:
注:IP:port合在一起稱為一個端點(endpoint)。
圖片
我們看到:X1主機通過X1:x1在向Y1:y1和Y2:y2分別發起請求后,NAT設備上便有了一條映射規則(一個洞):X1:x1被映射到了外部地址E:x1',映射表同時記錄了兩個請求的目標主機的端點(ip:port),記錄在規則的allowed_external_endpoints中。
規則中的這個allowed_external_pointss對后續外部主機通過E:x1'向X1:x1發送數據包會做出更嚴格的限制,如下圖:
圖片
我們看到:只有在“allowed_external_endpoints”中的端點(如Y1:y1、Y2:y2)發起的請求才可以在“洞”建立后,通過E:x1'向內部主機X1:x1成功發送數據包,其它主機或Y1、Y2上其他端口發送的數據包都會被攔截和丟棄。
下面我們再來看看最嚴格的NAT類型:對稱型NAT。
3.2.4 對稱型NAT
和上面由X1:x1發出的數據包(無論目的端點是什么)在NAT上只建立一條映射規則不同,在對稱型NAT中,由X1:x1向不同端點發送數據會在NAT上建立多條映射規則,如下圖所示:
圖片
我們看到每條規則中還包含了目的端點的信息(dest_ip和dest_port),也正因為如此,對稱型NAT對外部請求的限制也是最嚴格的,如下圖所示:
圖片
我們看到:只有來自規則中dest_ip和dest_port組成的端點的數據包才能進入內部,即只有那些收到數據的外部主機才能夠“順原路返回”地回送數據。
3.3 新的分類
上面提到的四種NAT類型是stun的RFC在早期對NAT實現的分類(基于UDP傳輸),一直沿用至今,也是目前使用最多的一種分類方法。不過這種分類方法將NAT的兩個正交的行為混在一起說了,即分配行為Assignment Behavior和過濾行為Filtering Behavior。其實我們更多關注的使其過濾行為的特征。
在較新的RFC 4787[8]中,NAT的行為被細分為兩個獨立的維度:分配行為(Assignment Behavior)和過濾行為(Filtering Behavior)。這兩種行為的各自分類描述了NAT在處理映射和過濾時的不同方式。以下是這兩種行為的分類及其對應的早期NAT類型的對照。
3.3.1 分配行為(Assignment Behavior)
分配行為定義了NAT設備如何為內網設備的流量分配外部端口和地址。RFC 4787將其分為三類:
- Endpoint-Independent Mapping(端點獨立映射)
不管內網設備與哪個外部設備通信,只要內網設備使用同一個源IP和源端口,NAT都會為其分配相同的外部IP和端口。這意味著內網設備的源IP和源端口在外部網絡上呈現為固定的外部IP和端口組合,獨立于目標設備的地址和端口,即獨立于目標設備的端點。
端點獨立映射這種類別對應的早期NAT類型是完全錐形NAT(Full Cone NAT),前面我們講過,在完全錐形NAT中,無論內網設備的通信目標是什么,NAT設備都會使用相同的外部端口映射,因此完全符合端點獨立映射的定義。
- Address-Dependent Mapping(地址依賴映射)
在地址依賴映射中,內網設備的外部端口是根據其通信的目標IP地址來分配的。如果內網設備改變了目標IP地址,即使源IP和源端口不變,NAT設備也會為其分配一個新的外部端口。
在分配行為上,我們似乎無法找到與早期分類一模一樣的類型,它有些類似于對稱NAT,但對稱NAT不僅考慮目標IP,還考慮目標端口。
- Address and Port-Dependent Mapping(地址和端口依賴映射)
在這種映射行為中,內網設備的外部端口是根據其通信的目標IP地址和目標端口組合來分配的。如果內網設備改變了目標IP或端口,即使源IP和源端口不變,NAT設備仍會分配一個新的外部端口。該類型對應的是早期NAT類型中的對稱NAT(Symmetric NAT)。對稱NAT的行為正是基于目標IP和端口的組合來分配外部端口,因此它完全符合地址和端口依賴映射的定義。
3.3.2 過濾行為(Filtering Behavior)
過濾行為描述了NAT設備如何決定是否允許外部設備通過NAT與內網設備通信。RFC 4787將其分為三類:
- Endpoint-Independent Filtering(端點獨立過濾)
這種類型的NAT設備不考慮外部設備的地址或端口,只要內網設備先發起了一個會話,任何外部設備都可以通過NAT設備與內網設備的相同源IP和源端口通信。這和早期NAT類型中的完全錐形NAT完全契合。
- Address-Dependent Filtering(地址依賴過濾)
這種類型的NAT設備只允許內網設備已經與之通信的外部IP地址與其通信。換句話說,只有內網設備先與某個特定的外部IP地址通信后,該外部IP地址的設備才能通過NAT與內網設備通信。這和早期NAT類型中的限制錐形NAT(Restricted Cone NAT)在過濾行為的特征上是一致的。
- Address and Port-Dependent Filtering(地址和端口依賴過濾)
這種類型的NAT設備要求外部設備的IP地址和端口都與內網設備已經建立連接的目標IP地址和端口匹配,才能允許通信。這意味著,只有內網設備先與某個特定的外部IP和端口組合通信后,該組合才能與內網設備通信。這與早期NAT類型中的端口限制錐形NAT(Port Restricted Cone NAT)以及對稱NAT的行為特征是一致的。
可以看出,RFC 4787中的分類方法更為細致地將NAT的分配行為和過濾行為分開討論,使得對NAT的行為理解更加明確。這種分類不僅幫助理解了不同NAT類型的工作機制,也為更精確地描述NAT行為提供了標準化的術語。
當然對于NAT打洞來說,我們更關心的顯然是過濾行為。
4. 小結
好了,這篇文章到這里就告一段落了。
在這篇文章中,我們探討了WebRTC網絡架構和NAT的工作原理。
我們首先了解了WebRTC的網絡架構,包括信令服務器、STUN服務器、TURN服務器和ICE框架等組件和其作用。
然后,我們討論了為什么需要NAT,包括解決IPv4地址短缺、提高安全性和簡化網絡管理等原因。
接著,我們詳細解釋了NAT的工作原理,以及完全圓錐型、受限圓錐型、端口受限圓錐型和對稱型這四種主要的早期NAT類型。
最后,我們介紹了RFC 4787中對NAT行為的新分類方法,將NAT行為分為分配行為和過濾行為兩個維度。
了解WebRTC網絡架構以及NAT工作原理是理解NAT打洞機制以及WebRTC端到端建立連接過程的前提,在后續文章中,我們會繼續WebRTC網絡部分的內容,比如NAT打洞以及端到端建連過程。
5. 參考資料
- How NAT traversal works[9] - https://tailscale.com/blog/how-nat-traversal-works
- Implementing NAT Hole Punching with QUIC[10] - https://arxiv.org/abs/2408.01791
- Network Address Translation (NAT) Behavioral Requirements for Unicast UDP[11] - https://tools.ietf.org/html/rfc4787
- WebRTC 1.0: Real-time Communication Between Browsers[12] - https://www.w3.org/TR/webrtc/
- Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal[13] - https://tools.ietf.org/html/rfc8445
- Session Traversal Utilities for NAT (STUN)[14] - https://datatracker.ietf.org/doc/html/rfc5389
- Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)[15] - https://datatracker.ietf.org/doc/html/rfc5766
- Traditional IP Network Address Translator (Traditional NAT)[16] - https://datatracker.ietf.org/doc/html/rfc3022
- IP Network Address Translator (NAT) Terminology and Considerations[17] - https://datatracker.ietf.org/doc/html/rfc2663
參考資料
[1] OpenAI與Livekit的合作: https://blog.livekit.io/open-source-realtime-multimodal-ai/
[2] 使AI模型具有了看、聽和說話的能力: https://openai.com/index/chatgpt-can-now-see-hear-and-speak/
[3] 使用Go和WebRTC data channel實現端到端實時通信: https://tonybai.com/2023/09/23/p2p-rtc-implementation-with-go-and-webrtc-data-channel
[4] Pion: https://github.com/pion/webrtc
[5] 使用Go和WebRTC data channel實現端到端實時通信: https://tonybai.com/2023/09/23/p2p-rtc-implementation-with-go-and-webrtc-data-channel
[6] RFC 1631: https://datatracker.ietf.org/doc/html/rfc1631
[7] RFC 3489: https://datatracker.ietf.org/doc/html/rfc3489
[8] RFC 4787: https://datatracker.ietf.org/doc/html/rfc4787
[9] How NAT traversal works: https://tailscale.com/blog/how-nat-traversal-works
[10] Implementing NAT Hole Punching with QUIC: https://arxiv.org/abs/2408.01791
[11] Network Address Translation (NAT) Behavioral Requirements for Unicast UDP: https://tools.ietf.org/html/rfc4787
[12] WebRTC 1.0: Real-time Communication Between Browsers: https://www.w3.org/TR/webrtc/
[13] Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal: https://datatracker.ietf.org/doc/html/rfc8445
[14] Session Traversal Utilities for NAT (STUN): https://datatracker.ietf.org/doc/html/rfc5389
[15] Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN): https://datatracker.ietf.org/doc/html/rfc5766
[16] Traditional IP Network Address Translator (Traditional NAT): https://datatracker.ietf.org/doc/html/rfc3022
[17] IP Network Address Translator (NAT) Terminology and Considerations: https://datatracker.ietf.org/doc/html/rfc2663