算不下去的算術:只有 2^32 個位址
上一篇你已經知道:一個 IPv4 位址是 32 個位元,寫成像 192.168.1.10 這樣的四個數字,而 CIDR 讓我們能把位址空間切成任意大小的前綴。現在來做一道從 1990 年代就讓網路工程師憂心的算術。32 個位元給出 2^32 個不同的位址,大約是 43 億個。這聽起來很龐大,直到你想起地球上有超過 80 億人,而我們很多人還隨身帶著一支手機、一台筆電、一支手錶,外加滿屋子全都想上網的小玩意。
實情比 43 億聽起來更糟。位址空間裡有大塊根本不能用:保留給實驗的、保留給多播的、保留給回送(你電腦拿來跟自己講話的 127.x.x.x 範圍)的區塊,還有早年在「43 億還像是無限」的時代大方發出去的巨額配額。真正可用的公開位址池要小得多。負責發放位址的中央註冊機構,依地區不同,大約在 2011 到 2019 年間正式用罄了它們的免費池。網際網路並沒有在 2011 年停止成長,所以總得有東西讓步。
私有位址:可以重複使用的區碼
這個把戲的前半段,是把一些位址範圍劃出來、宣告為私有:任何人都能在自己的網路內部自由使用,但永遠不會被繞送到公開的網際網路上。為此保留了三個範圍:10.0.0.0/8、172.16.0.0/12,以及 192.168.0.0/16。其中 192.168.x.x 那個,幾乎可以肯定就是你家路由器發給你筆電的位址。一個 私有 IP 位址就像大公司裡的內部分機號碼:在大樓裡撥「分機 42」完全行得通,但對從另一家公司打電話過來的人來說毫無意義,因為在那邊分機 42 是完全不同的一張桌子。
因為私有範圍從不離開自己的網路,每一個家庭與辦公室都能重複使用完全相同的號碼而不衝突。幾百萬個家庭同時都有一台位於 192.168.1.10 的裝置,卻沒有任何一台相撞,因為那個位址從不跑到公開的網際網路上。這種重複使用正是重點所在:單一一個公開位址,可以站在一整個由成千上萬台裝置組成的私有網路前面。你的路由器通常會用 DHCP 自動把這些私有位址發出去——也就是先前提過、在每台裝置加入時租給它一個位址的那個協定。
NAT:一個公開位址,許多私有位址
私有位址解決了重複使用,卻引出一個問題:如果你筆電的位址在你家外面毫無意義,那麼網頁伺服器的回覆要怎麼找路回到你身上?這就是 NAT——網路位址轉換——的工作。你家的路由器坐在邊界上,兩個世界各踏一隻腳:一個像 192.168.1.1 的私有位址朝內面向你的裝置,以及一個單一的公開位址(你的網路供應商給你的那個)朝外面向網際網路。NAT 就是那位站在邊界的接待員,在每個封包跨越時改寫它的位址。
更深一層的把戲在於:NAT 不只是調換位址,它還同時拋接 連接埠號。回想傳輸層說過的:每一條連線的身分不是單靠一個位址辨認的,而是靠位址與連接埠這個配對。NAT 正是利用了這一點。當你的筆電對外開一條連線到網頁伺服器,路由器會把封包的來源從你的私有位址與連接埠,改寫成它自己的公開位址與一個新挑選的連接埠,並把這筆調換記在一張轉換表裡。這種讓許多裝置靠「每段對話各拿一個連接埠」來共用一個公開位址的版本太常見了,常見到它有自己的名字:PAT、NAPT,有時就叫「NAT 過載」。
- 你的筆電(私有位址 192.168.1.10,來源連接埠 51000)送出一個封包,目的地是位於 203.0.113.5 的網頁伺服器、TCP 連接埠 443。封包的目的地寫的是伺服器,但來源是它自己的私有配對。
- 封包抵達你的路由器。NAT 把來源改寫成(公開位址 198.51.100.7、連接埠 61234),挑這個連接埠是為了讓它獨一無二,並在表裡記下對應關係 198.51.100.7:61234 -> 192.168.1.10:51000。接著它把封包送上網際網路。
- 伺服器回覆到 198.51.100.7:61234,因為這是它見過的唯一來源。它根本不知道你那台私有筆電的存在。
- 回覆抵達你的路由器。NAT 在表裡查 61234,找到 192.168.1.10:51000,把目的地改寫回你的私有配對,再轉送到你的家用網路上。你的筆電收到回覆,彷彿什麼都沒發生過。
NAT translation table (one home router, one public IP) Public side (what the Internet sees) Private side (your devices) ------------------------------------ --------------------------- 198.51.100.7 : 61234 <--> 192.168.1.10 : 51000 (laptop) 198.51.100.7 : 61235 <--> 192.168.1.22 : 49870 (phone) 198.51.100.7 : 61236 <--> 192.168.1.10 : 51200 (laptop, 2nd tab) One public address out front; the port column keeps every conversation separate so replies find the right device.
NAT 悄悄弄壞了什麼
NAT 很出色,但不是免費的。最深層的代價是:它打破了網際網路最初的承諾——任何裝置都能直接跟任何其他裝置對話。在 NAT 後面,你的筆電沒有公開位址,所以外面的人沒辦法主動發起一條連到它的連線。對外連線之所以可行,是因為你送出第一個封包時路由器學到了對應關係;但一個沒被招呼過的對內封包進來時,表裡沒有對應條目,路由器不知道它屬於哪一台私有裝置,於是把它丟掉。這就是為什麼要在 NAT 後面架遊戲伺服器或開視訊通話,需要像連接埠轉送或「打洞」這類額外的機關來撬開一條路。
還有一個誘人的迷思值得現在就破除:人們常說 NAT 是一種安全機制。它不是,或者至少它從來就不是為此設計的。確實,作為一個副作用,NAT 後面的裝置無法被外界直接連到,這擋掉了一些隨手的試探。但隱藏位址跟檢視並過濾流量是兩回事。真正的防護是防火牆的工作——那是一個刻意決定要放行哪些流量的獨立機制。NAT 是一個位址耗盡的權宜之計,只是恰好順手把你的裝置遮起來,把這個副作用當成你的安全計畫是個錯誤。
NAT 還增加了工作量、並打破了一些假設。路由器必須為每一段進行中的對話保存狀態,所以它的表格空間可能用完;而一條閒置下來的條目會逾時被忘掉,這就是為什麼安靜很久的連線有時會莫名其妙地斷掉。有些協定把 IP 位址夾帶在自己的資料裡(而不只放在封包標頭中),當標頭被改寫、但夾帶的位址沒被改時,它們就會搞混,需要特別的輔助程式碼才能勉強運作。這些都不致命,但它們是「違反分層」累積出來的摩擦:一個中間的盒子正在改寫本該端對端的位址。
一個賴著不走的權宜之計
退一步看,整套手法的形狀就清楚了。私有定址讓相同的號碼能在各處重複使用;NAT 則用連接埠號追蹤對話,讓一整個私有網路藏在一個公開位址後面。兩者合起來,把那 43 億個 IPv4 位址硬是撐開,涵蓋了遠比算術所允許更多的數十億台裝置。它確實是史上影響最深遠的工程膠帶之一,而你家的網路此刻正仰賴著它。
但它終究只是膠帶。NAT 拿網際網路當初建立其上的那個乾淨、直接、任意對任意的模型去交換時間。真正的解藥一直都是把位址做大,而這正是 IPv6 做的事;下一篇的諷刺之處在於:NAT 太好用了,反而磨鈍了切換的急迫感。所以,理解 NAT,就是同時理解了兩件事:為什麼網際網路在用完位址之後還能繼續運轉,以及為什麼通往一個真正更大的網際網路那條漫長而緩慢的遷移之路,會如此難走。