NAT穿越 TCP打洞

2021-07-04 17:25:08 字數 2408 閱讀 7178

在處於nat之後的兩台主機之間建立p2p tcp連線比建立相應的udp要稍微複雜,但在協議層次,tcp打洞非常類似與udp打洞。然而tcp協議本身比較複雜,因此支援的nat比較少。然而,在nat支援tcp打洞的情況下,tcp打洞像upd打洞那樣快並且可靠。穿透「行為良好」的nat的tcp p2p連線事實上比udp連線更健壯,因為,tcp協議的狀態機給路徑上的nat提供了一種決定特定tcp連線確切生存週期的標準方式,而維持udp連線的時間是不確定的。

對於想實現tcp打洞的應用程式來說,實際面臨主要的挑戰不是協議問題,而是api的問題。因為標準的berkeley sockets api是圍繞c/s程式設計而設計的。這個api通過connect()允許乙個tcp流套接字初始化乙個向外的連線,通過listen()和 accept()監聽乙個外入的連線,乙個套接字不能既用來監聽又用來初始化向外的連線。更進一步講, tcp套接字通常與本地主機上的tcp埠一一對應:乙個套接字繫結到本地主機機上的某個埠後,另乙個套接字就不能再繫結到該埠。

然而tcp打洞要成功,需要乙個本地的tcp埠既可以監聽外入的連線,同時又可以發起多個向外的連線。幸運的是,所有主流的作業系統都支援乙個特殊的socket選項,通常叫做so_reuseaddr,它執行應用程式繫結多個設定了該選項的套接字到同一埠。bsd系統引入了so_reuseport選項來控制埠重用,從而把埠重用和位址重用相分離。在這樣的系統中,兩個選項都需要被設定。

假定client a想要同client b建立乙個tcp連線。我們假設client a和 client b都與乙個雙方都知道的集結伺服器s保持著乙個活動的tcp連線。這個伺服器記錄了每乙個註冊客戶端的公有和私有位址,這類似於udp打洞的情況。在協議層,tcp打洞幾乎和udp一樣:

client a利用與s的連線請求s幫助它連線到b

s把b的公有和私有位址告訴a,同時把a的公有和私有位址告訴b。

a和b都通過相同的本地tcp埠向s返回給它們的位址(公有和私有位址都發)發起乙個向外的連線嘗試,同時在它們各自的本地埠上監聽外入的連線。

a和b等待向外的連線嘗試成功,或者乙個外入的連線出現。如果由於」connection reset」或」host unreachable」這樣的網路錯誤引起乙個向外的連線嘗試失敗,主機就簡單的延遲一段時間(比如1秒)之後再嘗試連線,直到出現乙個應用程式定義的最大超時。

當乙個tcp連線建立之後,主機通過驗證彼此以確定它們連線到了目的主機。如果驗證失敗,客戶端就關閉連線等待另乙個連線。一旦找到乙個驗證成功的tcp流連線,這一過程就終止。

不像udp,這裡每個客戶端只需要維持乙個與s的連線,而不管同時有多少個對端。tcp方案中,每乙個客戶端應用程式必須管理多個繫結到同乙個本地埠的sockets。如下圖所示。

每個客戶端需要乙個流套接字來與s連線,乙個套接字來監聽來自對端的外入連線,至少兩個另外的流套接字用來發起到對端公有位址和私有位址的向外的tcp連線。如下圖所示,考慮到通常的情況都是,a和b位於不同的nat之後,a和b發起的到對端私有位址的連線嘗

試可能失敗或連線到錯誤的主機。類似於udp的情況,tcp應用程式驗證它們的端到端會話也是很重要的,因為可能發生這樣的情況:連線到乙個本地網路中與想要連線的遠端主機具有同乙個私有位址的主機上。

這些客戶端發起的到對端公網位址的連線嘗試,促使它們各自的nat開啟乙個新的「洞」,這個「洞」允許a和b可以直接進行tcp通訊。如果它們之間的nat是「行為良好」,就會自動在它們直接形成一條p2p tcp流。如果a發到b的第乙個syn包在b發到a的第乙個syn包到底b的nat之前到達該nat,那麼b的nat會把a的syn包當做未授權的外入連線嘗試而把該syn包丟棄。隨後b的第乙個syn包應該能順利通過,因為a的nat把它當做a的第乙個syn包已經發起的向外連線的一部分。

客戶端應用程式在它們的sockets上觀察到的行為依賴於時機和tcp實現。假定a外發到b的公共端的第乙個syn包被b的nat丟棄,但是隨後的b傳送到a的公共端的第乙個syn包在a重新傳送syn包之前穿過網路到達了a,依賴於涉及到的作業系統,將發生下述行為之一:

上述的第一行為通常出現在bsd系統中,第二種行為通常出現在linux和windows系統中。

假定我們解決了打洞過程中的各種各樣連線嘗試的時機問題,以便來自兩個客戶端的外發syn包穿過了它們各自的本地nat,在到達遠端對端的nat之前在每個nat上開啟了向外的tcp會話。在這種「幸運」的情況下,nat沒有阻擋這兩個初始syn包,這兩個syn包在兩個客戶端各自的nat之間的線路上交叉通過。在這種情況下,客戶端觀察到了被稱為同步tcp開放的事件:每乙個對端在等待syn-ack的時候收到了乙個「raw」syn。每乙個對端的tcp回應對方乙個syn-ack,其中的syn部分是初始外發syn的重複,ack是對各自收到的syn的確認。

原文:

UDP TCP穿越NAT打洞

假定a要發起對b的直接連線,打洞 過程如下所示 endpoint指ip位址和埠的配對 1 a最初不知道如何向b發起連線,於是a向伺服器s傳送訊息,請求s幫助建立與b的udp連線。2 s將含有b的公網和內網的endpoint發給a,同時,s將含有a的公網和內網的endpoint的用於請求連線的訊息也發...

NAT打洞原理

具體例子 nat211.133.和nat211.134.之間需要進行通訊,但開始不能直接就發資料報,我們需要乙個中間人,這個就是外部索引伺服器 我們假設是211.135.7000 當nat211.133.向211.135.7000傳送資料報,211.135.7000是可以正常接收到資料,因為它是屬於...

Tcp and Udp NAT 穿越穿透打洞

所用屬於和代號。a 私網中的主機,設私網ip為192.168.1.2 b 另一私網中的主機,設私網ip為192.168.245.10 s 公網中的主機,在此做中間伺服器,設ip為223.11.11.11 nat net address transmission,在此可以理解為路由器 nat a a所...