NAT,讓你 IP 位置用不完的 NAT 是怎麼做到的?
你是否有想過,一個長度只有 32 位元的 IPv4 位置,計算下來約莫只能提供 42 億個位置,早已經少於世界人口總數,無法讓人人皆有了。
但是每個連上網際網路的裝置,都需要一個 IP 位置怎麼辦?這一系列的文章將由簡入深,聊聊這個問題是怎麼被 NAT 所解決的、帶來了什麼額外的問題、什麼是穿透、什麼是 STUN 等等,讓我們接著聊下去。
稀缺的 IP 位置
根據一些統計資料,在 2022 年 5 月時,想擁有一個 IPv4 位置大約要 50 美元,折合新台幣 1500 元左右。就連最大的雲端服務供應商 AWS,都宣布在 2024 年會開始對每個 IPv4 位置收取每月大約 100 元新台幣的租金。
雖然對於大部分的使用者來說,除非有建立伺服器相關服務的需求,似乎也沒有必要一個公開、固定的 IP 位置。那麼當我們下載網頁時,回傳的封包要怎麼被收到呢?
封包怎麼被轉送
在正式談及 NAT 之前,我們來看看一個簡單的小例子回顧封包傳輸的路徑。
假設你有一台電腦,有個 Public IP Address 1.2.3.4,當你到 google.com 瀏覽時,會和網頁伺服器尋求下載一份網頁文件。由於你的 IP 位置是公開的,回傳的網頁很容易就能被你收到了。
我們知道在你的電腦和網頁伺服器中間,其實是經由許多 Router 在幫你轉送資料的,所以當伺服器回覆你所需的網頁時,更精確一點的路徑其實是長這個樣子的。
然而,由於剛剛所提到 IPv4 位置枯竭的問題,不是每一台設備都有一個公開的 IP 位置的。常見的情況是,當你申請上網服務時,你的網路服務供應商(ISP)可能會分配一個公開 IP 位置,但有可能是動態的(意謂著可能隔一段時間、數據機重開時會被更換),也或許是虛擬的。
不論是什麼形式,你的所有設備如果都透過這台數據機上網的話,你最多就只有一組 Public IP 位置。如果此時有多台設備同時上網的話怎麼辦?這時 NAT 這項技術就派上用場了!
NAT(一),何謂 NAT
何謂 NAT?全名為 Network Address Translation,中文翻譯成「網路位置轉譯」,顧名思義就是將 IP 位置做個轉換的技術。
我們且看以下例子:
當一個 Public IP 位置被分配給我們,我們的路由器會維護一份 NAPT 的表格,對應內部及外部的 IP 位置加上連接埠,這也是為何會 NAT 加上一個 P 的緣故,這裡的 P 指的就是 Port(連接埠)。
所以當我們內網中有個 IP 位置為 192.168.1.2 的電腦送了一個請求到 google.com 時,這台電腦會開啟一個 Port,如 5566,等待 google.com 的回傳資料。
此時路由器就會將此 192.168.1.2:5566 的組合轉換成一個 Public IP + Port 的組合 1.2.3.4:9200,然後讓 google.com 知道回傳資料要傳到這邊。最後收到資料時再根據同樣的這張表反查,知道目的地為 1.2.3.4:9200 其實就是我們這台電腦 192.168.1.2:5566。
這樣子就算內網有多台設備,也能根據不同的 Public IP 位置加上不同的 Port 反查回是哪台設備的什麼請求。
不過,解決了 IP 位置有限問題的 NAT,其實也衍伸出不一樣的問題,我們下一講接著聊。
參考資料
NAT(二),穿越 NAT 的牆,淺談 ngrok 及 Port Forwarding
上一講提到 NAT 雖然有效的解決了 IP 位置枯竭的問題,但這種透過轉譯來將公開 IP 位置對應到內網 IP 位置的方法,卻也造成了一些困擾!
NAT 帶來的問題
讓我們來聊聊一個軟體工程師時常會遇到情境:當你想要建立一個 Web Server 在你的個人電腦上,把架好的網站丟給朋友看一下時,會怎麼做呢?總不能把 localhost:80 這樣 Local IP 位置丟出去吧?
所以你可能會看看自己這台電腦的 IP 位置,查了一下發現居然是一段 Class C 的虛擬 IP 位置,是被我們的路由器所分配的,至於我們僅有的一個 Public IP 位置 1.2.3.4,和個人電腦要怎麼究竟要怎麼對應起來呢?又是一大問題。
且慢,那前面不是說 NAT 能幫我們做公開和私有的 IP 位置轉譯嗎?是否能夠交給 NAT 自動去做?
雖然可以,但還真沒那麼自動。
前面提到 NAT 幫忙轉譯時,發動來源於我們內網的某個裝置,所以路由器在幫忙傳遞請求的封包時,能夠在自己的小表格中建立內外網的對應。
然而,當你的朋友想要發起一個請求,只知道公開的 IP 位置是不夠的,因為路由器不知道要把封包轉送給誰。
這就是 NAT 可能帶來的困擾,難以「穿透」。
ngrok
遇到這樣的問題,我們要做的就是想辦法讓外網的設備找得到我們,那究竟要怎麼做到呢?
例如使用第三方的服務 ngrok,就是一種簡單快速的解法。
我們知道 NAT 僅在請求方在內網向外發送請求時,能夠讓回傳的資訊找到家。那麼,我們就在個人電腦中裝一支 ngrok 的 Daemon(小程式)即可!
這支 Daemon 會主動向 ngrok 的伺服器發送請求,並且建立一段長久的連線,這個連線的動作稱之為 Tunneling。我們可以指定個人電腦上的 localhost:80 這個網站給 ngrok,讓其透過 tunnel 變相的「公開」了你的網站。
而 ngrok 會提供你一個如 xxx.ngrok.io 的 URL,你的朋友便可以透過這個 URL 讓 ngrok 當作一個中繼站,連到你在內網中個人電腦所架設的網站了。
然而,雖然 ngrok 簡單好用,但要使用還是得額外安裝 Daemon 在本機端,而且用的多了可是得付費的,畢竟人家可是架了許多 Server,也是有開銷的。
那有沒有其他方式可以穿越 NAT 的牆呢?
Port Forwarding
另一種讓別人找到我們的方法,就得提到 Port Forwarding 了,這是 NAT 的其中一種應用。但使用這個技術有個前提,就是你得有權限操作對外的路由器。
我們一樣來看看,如何讓架設在 192.168.1.2:80 的這個網站能夠被找到。當我們有了操作路由器的權限,應該可以看到類似下面的設定頁面。
假設我們想讓朋友透過我們的 Public IP Address 1.2.3.4,搭配上 Port 5566 來連到網站,就可以將 External Port 設定成 5566,然後對應到本機電腦的 IP 及網站的 Port,就大功告成了。
本質上,也是一樣去修改 NAPT 的表格罷了,只不過這次是我們手動加上的邏輯。
今天聊了兩種 NAT 穿透的解法,實際上還有更複雜的穿透問題沒那麼容易解決的,我們接著聊。
參考資料
NAT(三),對稱、錐形、為何有奇形怪狀的 NAT?
前面提到 NAT 解決了 IP 位置枯竭的問題,也提到了藏在 NAT 後的設備沒有這麼容易被找到的某種情境,這次來聊聊更多更複雜的情況。
為何會有不同種類的 NAT?
常見的 NAT 大致可分為對稱(Symmetric)和錐形(Cone)兩種,而錐形又可以細分成限制等級不同的錐形,聽起來很相當繞口對吧!
由於路由器的廠商有非常多間,有的注重家庭用戶,也有的致力服務企業等級的用戶,所實作出來的 NAT 行為就會不太一樣,但主要會評估的因素是以下兩點:
安全性:企業用戶通常比較在意資安,像是對稱 NAT 就相較錐形 NAT 來的安全
服務相容性:家庭用戶通常更在意方便性,因此一些服務如 P2P 在錐形 NAT 的路由器就比較不會出問題,相容性較對稱型則高
雖說我們都想要更安全,但是達成更安全造成的後果如果是犧牲服務相容性的話,對於家庭用戶來講就可能就沒那麼方便。
所以在不同的路由器中,實作哪一種類型的 NAT 就是各廠商們對於其目標客群的需求找到平衡後所挑選的。
NAT 種類的形狀命名怎麼來的?
那麼,這些形狀命名從何而來?我們先從服務相容性高、安全性較低的錐形開始聊起。
會取名為錐形,其實是由於 IP 位置及 Port 的映射形式而來的。在錐形 NAT 中,在 Client 發起請求時會有一組來源 IP Address + Port 用來接收回覆訊息,而 Server 則可以發送訊息回來源位置。
但不只是請求的目標 Server 可以送回訊息給這組來源位置,在彈性最大的完全錐形 NAT 中,其他 Server 也能送訊息給 Client,由於這種 Client 到多個 Server 一對多的位置映射看起來像是個錐形,這種類型的 NAT 便被命名成錐形 NAT。
完全錐形 NAT
我們接著來看看彈性最大的完全錐形(Full Cone)NAT。之所以是彈性最大,是因為一旦一組來源 IP Address + Port 被 Router 記錄下來之後,任何人都可以透過這組位置來傳送訊息給 Client。
例如 Client 端送了一個請求給 Server 5.6.7.8,不但這個 Server 能回傳訊息回 Client,只要其他 Server 如 8.7.6.5 也知道了 Client 的這組位置 1.2.3.4:9200,就能夠將訊息也傳到 Client 的同一個服務。
這種類型的 NAT 就很適合 P2P 服務的使用,因為當兩個 Client 從某 Server 拿到對方的 IP 位置後,路由器中的映射表也就產生出來,任何人都能夠連線,如此一來雙方便可以互相傳遞資訊。
然而,這也產生了安全性的問題,由於 Client 的這個服務所開啟的 Port 可以被任何人取用,也當然就能攻擊。
於是乎,就會有安全了點,但限制較多 NAT 類型出現,我們下一講繼續聊。
參考資料
NAT(四),受限錐形、對稱 NAT
前面聊到了完全錐形 NAT,服務相容性很高,但是會有安全性的隱患,我們這講就來聊聊安全一些的 NAT 類型。
受限錐形 NAT
我們知道在完全錐形 NAT 類型 Router 之內的設備,只要 IP Address + Port 的映射產生出來,就能被任何人所取用。
為了要防範不知名的攻擊,可以加上一些限制,像是只允許目標 IP Address 回傳的訊息,其他人的一律不收,這就是受限錐形(Restricted Cone)NAT。
例如我們 Client 的服務請求是送給 5.6.7.8 這台 Server 的,就只允許這台 Server 的回傳訊息。如果有另外一台 8.7.6.5 的 Server 也得到這組 1.2.3.4:9200 的來源 External IP 位置組合,想要往這裡傳送訊息,Router 就會阻檔下來。
如果想要再次提高安全性,可以考慮將限制條件再提高。
埠受限錐形 NAT
我們可以使用埠受限錐形(Port Restricted Cone)NAT 來增加安全性,連帶的也可以減少不必要的流量。
在這種類型的 NAT 中,除了限定只允許我們送出請求的目標 Server 能回傳訊息外,還多加了連接埠(Port)的限制。也就是說就算在同一個 Server 內,不同的服務(通常就會使用不同的 Port)也沒辦法將訊息送回給 Client。
越少的服務可以取用 Client 映射出來的位置,安全性也就越高了一些,然而服務相容性勢必就會降低。
我們最後來看安全性最高,但服務相容性最低的一種 NAT 類型。
對稱 NAT
對稱(Symmetric)NAT,其名取自於來源位置到目標的對稱性,也就是一對一的映射。由於不像錐形是一對多的,而是每一組請求的來源目標的映射都是獨立的,所以相對錐形 NAT 又更加安全,也更不相容一些如 P2P 的服務。
但你可能會想問說,對稱 NAT 和埠受限錐形 NAT 有什麼區別,看起來不都是獨立的一對一映射,只有一組目標的 IP Address + Port 的組合才能回傳資料給 Client 嗎?
我們來看看埠受限錐形 NAT 中,其實是有一對多的情況。
當 Client 的服務都是由 192.168.1.2:5566 送出請求的,不論是向 5.6.7.8:7788 或是 8.7.6.5:5566 哪一個 Server 的服務送出請求,來源位置都會是 1.2.3.4:9200,兩個 Server 只要曾經被發送過請求,也都能回傳訊息給 Client。
但在對稱 NAT 中就有點不一樣了。就算 Client 的服務是同一個,只要目標 Server 的位置不同(不論是單純 IP Address 不同,或是相同 IP Address 不同的 Port),都會產生一筆新的映射。
也就是說,同樣從 192.168.1.2:5566 發出的請求,送到兩個不一樣的目標後,External 的 IP 位置組合會是不同的,例如不同 Port 9200 及 9201。
這種較嚴格的 NAT 類型,通常在企業級的 Router 裡面,比較重安全性的環境會使用,但如此一來也會有較低的服務相容性,導致許多服務需要更多的技術來穿越 NAT 這道牆,僅靠 Port Forwarding 是無法解決的。
至於是怎麼樣的技術,我們下一講接著聊。
參考資料
NAT(五),其他穿越機制,STUN 及打洞策略
前面聊過一些 NAT 穿越的機制,例如 Port Forwarding。而在大致理解了各種 NAT 的類型之後,我們來看看針對不同種類的 NAT 有何穿越機制。
STUN
STUN 的全名為 Session Traversal Utilities for NAT,中文翻譯成 NAT 對談穿透用程式,是 NAT 穿越中較為簡單的做法之一。其命名中的「對談(Session)」一般是指兩個裝置間的連線, 而 STUN 主要做的事情就是透過找到裝置的 External IP Address + Port,來幫助裝置間建立連線。
假設我們要和朋友建立 P2P 的連線,我們自己 Router 的設定是錐形 NAT,就算是限制最多的「埠受限錐形 NAT」,也能透過 STUN 來幫助建立直接的連線。
首先這個服務會需要架設一個 STUN Server,便能透過以下步驟來幫助我們建立 P2P 連線
我們的 P2P 服務 Client 端和 STUN Server 詢問公開的位置
STUN Server 回覆我們,得到 1.2.3.4:9200
將我們的公開位置傳送給朋友,朋友便能透過 1.2.3.4:9200 傳訊息給我們了
如此一來,我們雙方就能透過和 STUN 獲取的公開位置來建立連線了。
但是,先等等!
這個情境是當我們在 NAT 的後面,而我們朋友卻是假定其裝置是擁有公開 IP 位置的,假如他的裝置也在 NAT 後面,會發生什麼情形?
P2P 在(埠)受限錐形 NAT 下的策略:打洞
雖然我們雙方都可以透過 STUN Server 拿到各自的公開位置,但如果雙方的 Router 設定都是完全錐形 NAT 的話,傳送的訊息會被對方的 Router 給丟掉,因為對方並沒有傳送訊息給我們 1.2.3.4:9200 過。
同理可證,如果朋友想先傳訊息給我們,也會被我們的 Router 所擋掉!那麼,豈不是一個類似 Deadlock 的狀況,我們誰都沒辦法成功送出第一筆訊息?
不怕,我們可以同時傳,多傳幾筆!且看下方例子。
在時間 T1 的地方,我們先送訊息給對方,但此時對方的 NAT 表中還沒有記錄我們的 IP 位置,所以會被擋住。
但沒關係,我們的 NAT 表中已經記錄對方的 IP 位置了,因此在晚一點的時間 T2 上,對方送的封包不會被我們的路由器給擋掉。
而在 T3 時間上,對方已經將我們的位置新增在自己的 NAT 表上了,所以此時我們也能夠成功送出訊息,達成雙方都建立連線
這種同時傳、多傳幾次的策略就稱之為 Hole Punching(打洞),又分為 UDP 打洞及 TCP 打洞,兩者實施的邏輯類似,但細節上 TCP 的又更為複雜。
然而,要實施 Hole Punching 還會需要一個中繼的 Server,否則 P2P 的兩端不知道什麼時候要「同時」向對方傳送封包。
並且呢,這僅在雙方的 Router 設定是錐形 NAT 的情境底下成功機率較高,在 Router 設定是對稱 NAT 時,會因為對不同目標的連接都會產生新的連接埠映射,所以從 STUN Server 拿到 External IP 位置組合,只有 STUN Server 傳的訊息才被允許而已。
至於對稱 NAT 的問題要怎麼解決,我們下一講繼續聊。
參考資料
NAT(六),更複雜的穿越機制,STUN, TURN 及 ICE 怎麼處理 P2P 連線
我們在上一講聊到 STUN 及打洞的機制可以解決錐形 NAT 的穿越問題,然而還有對稱 NAT 這個難題要解決。
我們先再回顧一下為何 P2P 的連線對於對稱 NAT 的穿越如此困難。
內外網位置的一對一映射
由於對稱 NAT 會對於同一個內網的同一個服務(同 IP Address 同 Port,如 192.168.1.2:5566)產生一組新的映射,比如對到 STUN Server 和 8.7.6.5 這個位置的服務,就會產生 External IP Address 為 1.2.3.4,但是 Port 分別是 9200 及 9201 這樣的映射。
如此一來,就算 8.7.6.5 這個位置從中繼 Server 得知我們的服務位於 9200 Port(由我們和 STUN Server 所取得),也沒辦法建立連線,因為 9200 Port 是我們和 STUN Server 所建立的連線,無法被分享。
由於 NAT 的映射產生是 Router 所處理的,我們無法假定各種廠商 Router 上的映射表是我們裝置的服務可以取得的,因此也很難透過打洞的策略讓雙方知道對方到自己的映射位置。
怎麼解決這個問題呢?只好靠中繼伺服器!
TURN
TURN 的全名為 Traversal Using Relay around NAT,顧名思義,就是 NAT 的 Relay(中繼)。
其原理也就是當作兩個 NAT 中間的節點罷了,所有的流量都會透過 TURN Server,作為中繼站在兩個裝置間幫忙傳輸。
很明顯的,TURN 的最大缺點就是所有流量都會透過他,這樣也便沒有了 P2P 服務的意義了。當傳輸的內容為影像或音訊時,流量就會很大,而導致成本飆升。
因此,有些策略在處理對稱 NAT 時會先透過「猜」映射表,看看能否透過規律甚至運氣試個幾次矇中。真的不行的話,下策才是將流量導向 TURN Server 來建立雙方的連線。
ICE
最後我們來聊聊集大成的 ICE!其全名為 Interactive Connectivity Establishment,是一種幫助 P2P 服務建立連線的 NAT 穿越技術,例如 WebRTC 就是基於 ICE 的標準。
本質上 ICE 就像是將各種穿越法打包起來的武功秘笈,其運作的方法大概可以總結如下:
收集候選者並交換資料(Candidate Gathering and Exchange Candidate Information)
尋找並選擇最佳路徑(Connectivity Check and Nominate a Candidate Pair)
首先是透過 STUN Server 來找到雙方 Public IP Address + Port 的映射,也就是所謂的候選者們。並且把些資訊交給對方,接著就可以開始尋找最佳路徑。
尋找路徑的方式則是來試試看不同方法,假如是在完全錐形 NAT 後的裝置,直接拿 STUN Server 取得的資料一送就發現通了,最佳路徑便找到了!
若是在受限錐形 NAT 後的裝置,可能就要多試幾次,回到 Hole Punching 的章節,理論上也能夠找到一條不錯路徑。
然而在對稱 NAT 的阻擋下,可能最終還是找不到在兩個裝置間直接的連線路徑,最後只好透過 TURN Server 來幫忙交換封包。
但總而言之,ICE 最後還是能從成本低到高的嘗試中,幫兩台位於 NAT 後的裝置建立起 P2P 的連線!