由於Internet的快速發展 IPV4(網際協定版本4)地址不夠用,不能每個主機分到一個公網IP 所以使用NAT地址轉換
一般來說都是由私網內主機主動發起連線,數據包經過NAT地址轉換後送給公網上的伺服器,連線建立以後可雙向傳送數據,NAT裝置允許私網內主機主動向公網內主機發送數據,但卻禁止反方向的主動傳遞,但在一些特殊的場合需要不同私網內的主機進行互聯(例如P2P軟體、網路會議、視訊傳輸等),TCP穿越NAT的問題必須解決。
現在基本使用這種,又分爲對稱和錐型NAT。
錐型NAT,有完全錐型、受限制錐型、埠受限制錐型三種:
對稱NAT:
對於這種NAT。連線不同的外部Server,NAT開啓的埠會變化。也就是內部機器A連線外網機器B時,NAT會開啓一個埠,連線外網機器C時又會開啓另外一個埠。
對於雙方都是Port Restricted Cone NAT的時候,則需要利用UDP打洞原理進行「先打洞,然後才能 纔能直接通訊」。
如果A和B想要進行UDP通訊,則必須穿透雙方的NAT路由。假設爲NAT-A和NAT-B。
A發送數據包到公網S,B發送數據包到公網S,則S分別得到了A和B的公網IP,
S也和A B 分別建立了對談,由S發到NAT-A的數據包會被NAT-A直接轉發給A,
由S發到NAT-B的數據包會被NAT-B直接轉發給B,除了S發出的數據包之外的則會被丟棄。
所以:現在A B 都能分別和S進行全雙工通訊了,但是A B之間還不能直接通訊。
解決辦法是:A向B的公網IP發送一個數據包,則NAT-A能接收來自NAT-B的數據包
並轉發給A了(即B現在能存取A了);再由S命令B向A的公網IP發送一個數據包,則
NAT-B能接收來自NAT-A的數據包並轉發給B了(即A現在能存取B了)。
以上就是「打洞」的原理。
1、雙方都通過UDP與伺服器通訊後,閘道器預設就是做了一個外網IP和埠號 與你內網IP與埠號的對映,這個無需設定的,伺服器也不需要知道客戶的真正內網IP
2、使用者A先通過伺服器知道使用者B的外網地址與埠
3、使用者A向使用者B的外網地址與埠發送訊息,
4、在這一次發送中,使用者B的閘道器會拒收這條訊息,因爲它的對映中並沒有這條規則。
5、但是使用者A的閘道器就會增加了一條允許規則,允許接收從B發送過來的訊息
6、伺服器要求使用者B發送一個訊息到使用者A的外網IP與埠號
7、使用者B發送一條訊息,這時使用者A就可以接收到B的訊息,而且閘道器B也增加了允許規則
8、之後,由於閘道器A與閘道器B都增加了允許規則,所以A與B都可以向對方的外網IP和埠號發送訊息。
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,但是是否存在實際上的異常,還有待更多觀察。
對於Cone NAT.要採用UDP打洞.需要一個公網機器server C來充當」介紹人」.處於NAT之後的內網的A,B先分別和C通訊,開啓各自的NAT埠.C這個時候知道A,B的公網IP: Port. 現在A和B想直接連線.比如A給B直接發包,除非B是Full Cone,否則不能通訊.反之亦然.
爲什麼啊?因爲對於處於NAT之後的A,B。如果想A要與外界的D通訊,則首先必須要A發包到D,然後A經過NAT裝置NA,NA把A的內網地址和埠轉換爲NA的外網地址和埠。和D通訊之後,D才能 纔能經過NA和A通訊。也就是說,只能A和外界主動通訊,外界不能主動和處於NA之後的A通訊。這種包會被NA直接丟棄的。這也就是上面所說的Port Restricted Cone 的情形啊! A(192.168.8.100:5000) -> NA(202.100.100.100:8000) -> D(292.88.88.88:2000)但是我們可以這樣.
A --- NA --- Server C --- NB --- B
注意: 路由器和防火牆的UDP打洞的埠有個時間限制的,在一定時間內如果沒有數據通訊會自動關閉
STUN
IP協定中TTL
把ttl的值設定小一點,比如4,使其路由轉發的時候減到0,而把數據包丟棄
在IPv4中, TTL是IP協定的一個8個二進制位的值【0-255】. 這個值可以被認爲是數據包在internet系統中可以跳躍的次數上限. TTL是由數據包的發送者設定的, 在前往目的地的過程中, 每經過一臺主機或裝置, 這個值就要減少一. 如果在數據包到達目的地前, TTL值被減到了0,那麼這個包將作爲一個ICMP錯誤的數據包被丟棄。 Linux預設64
很多時候,我們希望網路中的兩臺主機能夠直接進行通訊,即所謂的P2P通訊,而不需要其他公共伺服器的中轉。由於主機可能位於防火牆或NAT之後,在進行P2P通訊之前,我們需要進行檢測以確認它們之間能否進行P2P通訊以及如何通訊。這種技術通常稱爲NAT穿透(NAT Traversal)。最常見的NAT穿透是基於UDP的技術,如RFC3489中定義的STUN協定。
STUN(Simple Traversal of User Datagram Protocol Through Network Address Translators),即簡單的用UDP穿透NAT,是個輕量級的協定,是基於UDP的完整的穿透NAT的解決方案。它允許應用程式發現它們與公共網際網路之間存在的NAT和防火牆及其他型別。它也可以讓應用程式確定NAT分配給它們的公網IP地址和埠號。STUN是一種Client/Server的協定,也是一種Request/Response的協定,預設埠號是3478。
應用程式(即STUN CLIENT)向NAT外的STUN SERVER通過UDP發送請求STUN 訊息詢問自身的轉換後地址,STUN SERVER收到請求訊息,產生響應訊息,響應訊息中攜帶請求訊息的源埠,即STUN CLIENT在NAT上對應的外部埠。然後響應訊息通過NAT發送給STUN CLIENT,STUN CLIENT通過響應訊息體中的內容得知其在NAT上對應的外部地址,並且將其填入以後呼叫協定的UDP負載中,告知對端,同時還可以在終端註冊時直接註冊這個轉換後的公有IP地址,這樣就解決了H.323/MGCP/SIP穿越NAT的通訊建立問題以及作爲被叫時的問題。本端的接收地址和埠號爲NAT外的地址和埠號。由於通過STUN協定已在NAT上預先建立媒體流的NAT對映表項,故媒體流可順利穿越NAT。
另外STUN server並非指一個專用的伺服器,而是指一種功能、一個協定,我們可以在softswitch或者任何一個需要此功能的伺服器上內建此協定, 後面程式碼也包含一個簡單的Server實現。
但是在NAT採用對稱模式(symmetric NAT)工作時,STUN的方案就會出現問題。假如我們在softswitch上提供STUN server功能,終端A通過STUN可以獲得NAT爲終端A與softswitch之間通訊分配的地址A',並將這個地址註冊在softswitch上,當一個公網上的終端B呼叫終端A時,A'和B通過softswitch完成呼叫建立過程。當B試圖向A'發送媒體流時,問題就出現了。因爲對稱NAT只允許從softswitch發送數據給地址A',從B發送的媒體流將被丟棄。所以STUN無法應用於工作在對稱模式的NAT.
STUN協定最大的優點是無需現有NAT/FW裝置做任何改動,同時STUN方式可在多個NAT串聯的網路環境中使用. STUN的侷限性在於STUN並不適合支援TCP連線的穿越,同時STUN方式不支援對對稱NAT(Symmetric NAT).
在RFC5766中定義,英文全稱Traversal Using Relays around NAT(TURN):Relay Extensions to Session Traversal Utilities for NAT(STUN),即使用中繼穿透NAT:STUN的中繼擴充套件。簡單的說,TURN與STUN的共同點都是通過修改應用層中的私網地址達到NAT穿透的效果,異同點是TURN是通過兩方通訊的「中間人」方式實現穿透。
如果一個主機位於NAT的後面,在某些情況下它不能夠與其他主機對等直接連線。在這些情況下,它需要使用中間網點提供的中繼連線服務。TURN協定就是用來允許主機控制中繼的操作並且使用中繼與對端交換數據。TURN與其他中繼控制協定不同的是它能夠允許一個用戶端使用一箇中繼地址與多個對端連線。
TURN協定被設計爲ICE的一部分,用於NAT穿越,雖然如此,它也可以在沒有ICE的地方單獨使用。