NAT打洞(udp打洞和tcp打洞)

UDP打洞技術:

對於兩個peer,A和B。
1、若A和B位於同一個nat之後。如果nat支持迴環轉換,A和B之間打洞時使用彼此的外網地址是可以連通的。但是最好是優先嚐試內網連接。
2、若A和B位於不同的nat之後。若兩個nat都是公網地址,則屬於“典型”連接過程,連接相對簡單可靠。
3、若A和B位於多級nat之後。
a)A和B有相同的出口nat。則使用內網地址連接,可能會存在明顯錯誤(需要鑑別)。若頂級nat不支持迴環轉換,則連接會失敗。
b)A和B在不同的出口nat後。則過程類似情況2。

4、若A和B只有一方在nat之後。利用反向連接的方法完成。(也可以採用tcp協議連接)。


連接過程:

依據stun協議鑑別出的nat類型,採取合適的連接過程。

兩個nat4之後的peer仍然無法直接完成連接,有需要時可採用TURN協議建立“連接”(通過中繼完成的通信)。


重要問題:
1、udp會經常收到非預期的數據包,所以需要做過濾和鑑別。比如,雙方連接時,需要從服務器拿到相同的令牌,數據包提交了這個令牌才認爲是有效的。


---------------------------------------------------------------------------------------------------------------------

TCP打洞技術:
tcp打洞也需要NAT設備支持纔行。
tcp的打洞流程和udp的基本一樣,但tcp的api決定了tcp打洞的實現過程和udp不一樣。
tcp按cs方式工作,一個端口只能用來connect或listen,所以需要使用端口重用,才能利用本地nat的端口映射關係。(設置SO_REUSEADDR,在支持SO_REUSEPORT的系統上,要設置這兩個參數。)

連接過程:(以udp打洞的第2種情況爲例(典型情況))
nat後的兩個peer,A和B,A和B都bind自己listen的端口,向對方發起連接(connect),即使用相同的端口同時連接和等待連接。因爲A和B發出連接的順序有時間差,假設A的syn包到達B的nat時,B的syn包還沒有發出,那麼B的nat映射還沒有建立,會導致A的連接請求失敗(連接失敗或無法連接,如果nat返回RST或者icmp差錯,api上可能表現爲被RST;有些nat不返回信息直接丟棄syn包(反而更好)),(應用程序發現失敗時,不能關閉socket,closesocket()可能會導致NAT刪除端口映射;隔一段時間(1-2s)後未連接還要繼續嘗試);但後發B的syn包在到達A的nat時,由於A的nat已經建立的映射關係,B的syn包會通過A的nat,被nat轉給A的listen端口,從而進去三次握手,完成tcp連接。

從應用程序角度看,連接成功的過程可能有兩種不同表現:(以上述假設過程爲例)
1、連接建立成功表現爲A的connect返回成功。即A端以TCP的同時打開流程完成連接。
2、A端通過listen的端口完成和B的握手,而connect嘗試持續失敗,應用程序通過accept獲取到連接,最終放棄connect(這時可closesocket(conn_fd))。
多數Linux和Windows的協議棧表現爲第2種。

但有一個問題是,建立連接的client端,其connect綁定的端口號就是主機listen的端口號,或許這個peer後續還會有更多的這種socket。雖然理論上說,socket是一個五元組,端口號是一個邏輯數字,傳輸層能夠因爲五元組的不同而區分開這些socket,但是是否存在實際上的異常,還有待更多觀察。

另外的問題:
1、Windows XP SP2操作系統之前的主機,這些主機不能正確處理TCP同時開啓,或者TCP套接字不支持SO_REUSEADDR的參數。需要讓AB有序的發起連接纔可能完成。

上述tcp連接過程,僅對NAT1、2、3有效,對NAT4(對稱型)無效。
由於對稱型nat通常採用規律的外部端口分配方法,對於nat4的打洞,可以採用端口預測的方式進行嘗試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章