總覽與定位
私有網段裡的主機如何共用少數公有 IP 上網?外面又怎麼連回內網服務?
我們在 IP 定址篇學會解讀 IPv4 與子網路遮罩,知道同網段直送、跨網段交 Gateway。真實家用/公司網路幾乎都長這樣:
- 內網一堆主機用
192.168.x.x/10.x.x.x這種私有 IP - 路由器對外只有少數(常是一個)公有 IP向 ISP 註冊
- 內網要上網 → 路由器做 NAT(Network Address Translation)改寫來源位址
- 外面要連內網服務(自家 NAS、開發機 webhook)→ 靠 Port Forwarding(DNAT)
- 哪些流量能過 → 由防火牆規則把關
本篇把這三件事串成一條可面試、可除錯的因果鏈:公私有 IP 為什麼要分 → NAT 表怎麼記映射 → Port Forwarding 怎麼反向開洞 → 防火牆預設拒/允許的心智模型。
承接「IPv4 定址與子網路劃分」:你已會算網段與 Gateway,本篇回答「Gateway 對外怎麼改寫位址」。區域網路設備(Switch/MAC)與 DNS 解析留給鄰近主題;本篇只在網路層+傳輸層 port 的層次談 NAT/防火牆。
公有 IP vs 私有 IP
不是「能不能 ping」,而是「網際網路上的路由器肯不肯幫你轉」。
私有 IP(Private / RFC 1918)刻意留給組織內部重複使用。網際網路上的骨幹路由器不會把目的地落在這些網段的封包轉出去——這叫「不可全域路由(non-globally routable)」。反過來說,公有 IP在 IANA/RIR 分配體系裡是唯一的,可由 ISP 公告到全球 BGP。
| 面向 | 私有 IP | 公有 IP |
|---|---|---|
| 範圍 | 10/8、172.16/12、192.168/16 | 其餘可分配空間(含文件用 203.0.113.0/24 等) |
| 可重複? | 每個公司/家庭可各自再用同一段 | 全球唯一(同一時間) |
| 網際網路路由 | 被過濾/不公告 | 可經 BGP 到達 |
| 典型角色 | LAN 主機、K8s Pod、VPC 內網 | NAT Gateway、LB、對外 API |
面試陷阱:127.0.0.0/8 是 loopback、169.254.0.0/16 是 link-local(APIPA),都不是 RFC 1918 私有網段,但同樣不應出現在「對外來源 IP」。
為什麼要這樣設計?IPv4 位址不夠用。若每台筆電都要一顆全球唯一公有 IP,位址空間早耗盡。私有+NAT 讓「組織內部任意擴張」,對外只消耗少數公有 IP——這是 IPv4 時代的務實妥協,不是長期銀彈(長期方向是 IPv6 端到端定址)。
雲主機常有公有 IP,但安全群組/防火牆預設只開 22/443。家用則是整段 LAN 藏在一個公有 IP 後面:外面看到的是路由器,不是你的 192.168.1.20。要對外提供服務,還得 Port Forwarding(或反向代理/Tunnel)。
NAT 怎麼轉換內外網
核心不是「改 IP」 alone,而是「記一張連線狀態表,讓回程找得回路由」。
最常見的家用/辦公室場景是 NAPT(Network Address Port Translation),也常被叫成 PAT 或「IP masquerading」:多台內網主機共用同一個公有 IP,靠不同的來源 port區分連線。
路由器在轉出時改寫封包的 來源 IP(+常改來源 port),並在 NAT 表(conntrack / translation table)留下一列映射。回程封包目的地是公有 IP:40001 時,路由器查表還原成 10.0.0.8:54321 再送進 LAN——否則內網主機根本收不到回應。
| 方向 | 改寫什麼 | 別名 | 典型用途 |
|---|---|---|---|
| 內 → 外 | 來源 IP/port | SNAT / Masquerade | 上網、呼叫外部 API |
| 外 → 內 | 目的 IP/port | DNAT / Port Forward | 對外公開內網服務 |
Masquerade 是 SNAT 的動態版:出口 IP 隨介面位址變(DHCP 換 IP 時規則不用重寫)。
NAT 表一列通常至少包含:協議(TCP/UDP)、內網五元組資訊、對外映射的公有 IP:port、對端位址、以及逾時。TCP 有連線狀態可跟較久;UDP 通常用較短 idle timeout。在 Linux 上可用 conntrack -L 直接看這張表:
$ conntrack -L
tcp 6 431999 ESTABLISHED \
src=10.0.0.8 dst=93.184.216.34 sport=54321 dport=443 \ # 原始方向(內→外)
src=93.184.216.34 dst=203.0.113.50 sport=443 dport=40001 \ # 回程方向(外→內)
[ASSURED]
同一筆連線用「原始 + 回程」兩個方向的五元組描述:回程的 dport=40001 就是路由器替 10.0.0.8:54321 分配的對外 port,回來的封包靠它還原。
這也點出 NAPT 的天花板:單一公有 IP 對每個「協議 × 對端 IP:port」大約只有 ~64K 個可用來源 port。連線暴增(大量短連線、P2P、掃描)時 port 會耗盡,或 conntrack 表達到 nf_conntrack_max 上限,表現就是偶發、難重現的連線失敗——正式環境除錯時常見的盲點。
對端伺服器只看得到路由器的公有 IP,看不到真實客戶端。這影響來源 IP 限流、地理定位、雙向 peer 連線(P2P/WebRTC 常需 STUN/TURN 穿透)。系統設計時要把 NAT 當成預設存在的中間盒,而不是例外。
Port Forwarding:讓外面連到內網
DNAT 在邊界把「打到公有 IP:port」的流量轉寫成「內網主機:port」。
假設你家路由器公有 IP 是 203.0.113.50,內網有一台開發機 10.0.0.20 跑 HTTP :8080。你設定 Port Forwarding:
外部客戶連 203.0.113.50:8080 時,路由器改寫目的 IP(必要時也改目的 port),送進 LAN;回程再做對應的來源改寫,讓客戶端以為一直在跟公有 IP 說話。
| 設定項 | 範例 | 說明 |
|---|---|---|
| 外部 port | 8080 或 443 | 對端實際連的 port;可與內部不同 |
| 內部 IP | 10.0.0.20 | 必須是穩定位址(建議 DHCP reservation/靜態) |
| 內部 port | 8080 | 服務實際 listen 的 port |
| 協議 | TCP / UDP | NAT 表與防火牆都按協議分開 |
Port Forwarding 把內網服務暴露到整個網際網路。正式做法通常是:只轉必要 port、前置反向代理/WAF、強制 TLS、搭配防火牆白名單,或改用 VPN/Cloudflare Tunnel/SSH reverse tunnel,避免把整台機器裸露在公網。
雲端對應觀念:Security Group/NLB Listener/Ingress 規則,本質也是「在邊界決定哪些外→內流量被改寫或放行」。家用路由器的 Port Forward 面板,只是同一設計的精簡版。
「Port Forward 明明設對了,外面就是連不進來」——最常見的真兇是你的路由器根本沒有公有 IP。當 IPv4 位址枯竭,許多 ISP 改發私有 IP(如 100.64.0.0/10)給用戶,再於機房用一層 CGNAT(Carrier-Grade NAT,營運商級 NAT)共用少數公網 IP。這時封包會經過兩層 NAT:家用路由器一層、ISP 一層。你在自家路由器開的洞,外部流量根本到不了那台你看不見、也無權設定的 ISP NAT。同理,把數據機接到自己的路由器 WAN 口卻沒設 Bridge 模式,也會在自家造成雙 NAT。破解法:向 ISP 申請公有/固定 IP、把前段設備切 Bridge 模式,或改用不需入站洞的反向 Tunnel/VPN(見第 7 節)。
防火牆基礎心智模型
NAT 負責「怎麼改寫」;防火牆負責「允不允許這類流量存在」。
實務上 NAT 與防火牆常落在同一台路由器/同一套 netfilter(iptables/nftables)規則鏈,但概念要分開:
- 防火牆:依規則決定 ACCEPT/DROP/REJECT(誰可以從哪進、到哪出)
- NAT:在已允許的路徑上改寫位址/port
| 面向 | 建議預設 | 為什麼 |
|---|---|---|
| 入站(WAN → LAN) | 預設拒絕 | 只放行明確 Port Forward/管理 port |
| 出站(LAN → WAN) | 多數家用允許 | 企業常做出站白名單/代理 |
| 已建立連線 | 允許 RELATED,ESTABLISHED | 回程封包必須能回來 |
| 規則順序 | 由上而下、先匹配先生效 | 錯序會造成「規則寫了卻沒擋到」 |
除錯口訣:先問「封包有沒有被防火牆丟掉」,再問「NAT 有沒有改對」。兩者混淆時,常見現象是:tcpdump 在 WAN 口看到 SYN,但 LAN 口沒有對應封包——可能是入站規則沒放行,或 DNAT 目標寫錯。
(PREROUTING) → 路由決策 → 防火牆過濾
(FORWARD) → 轉發到目標區
以 Linux netfilter 入站轉發為例:DNAT 在 PREROUTING(路由決策前)先改寫目的,過濾則在 FORWARD 鏈判定。順序依 hook 而定,但面試重點不變——「改寫」與「過濾」是兩層獨立決策,別混成一句「開了 port 就好」。
把上述心智模型落成一組最小 iptables 規則,正好看出「改寫(nat 表)」與「過濾(filter 表)」是分開的兩件事:
# 出站放行、入站預設拒絕;永遠放行已建立/相關連線的回程
iptables -P FORWARD DROP
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 改寫:Port Forward 外部 :8080 → 內網 10.0.0.20:8080(DNAT 在 nat 表)
iptables -t nat -A PREROUTING -i wan0 -p tcp --dport 8080 \
-j DNAT --to-destination 10.0.0.20:8080
# 過濾:還得在 filter 表放行這條新入站,否則 FORWARD 預設 DROP 會擋掉
iptables -A FORWARD -p tcp -d 10.0.0.20 --dport 8080 -j ACCEPT
只寫了 DNAT 卻忘了那條 FORWARD ACCEPT,就是「規則寫了卻沒通」的經典陷阱——改寫成功,但過濾把它擋下。
互動 · NAT 表映射模擬
自己發一筆出站或入站連線,看 NAT 表如何新增列、封包欄位如何被改寫。
路由器公有 IP 固定為 203.0.113.50。SNAT 會分配對外 port;DNAT 模式下請先「設定轉發規則」開洞,再「送出連線」——若把外部 Port 改成沒開洞的值再送,會示範防火牆預設拒絕、封包被丟棄(DROP)。
| # | 類型 | 內網 | 公網映射 | 對端 | 狀態 |
|---|---|---|---|---|---|
| 尚無映射列 — 送出連線後會出現 | |||||
面試折衷與實務選型
何時靠 NAT/Port Forward,何時改用 Tunnel、IPv6 或雲負載均衡。
| 方案 | 優點 | 代價 | 適用 |
|---|---|---|---|
| NAPT 出站 | 省公有 IP、部署簡單 | 破壞端到端、除錯難、連線數受 port 上限 | 家用/辦公室上網 |
| Port Forward | 快速暴露單一服務 | 攻擊面大、動態 IP/雙 NAT 易失敗 | 臨時 demo、家庭 Lab |
| 反向 Tunnel/VPN | 不必開入站洞、可繞過雙 NAT | 多一跳延遲、依賴隧道服務 | 遠端開發、IoT、零信任 |
| 雲 LB + 私有後端 | TLS/健康檢查/水平擴展 | 成本與供應商耦合 | 正式對外 API |
| IPv6 端到端 | 恢復端到端定址 | 生態與雙堆疊複雜度 | 長期方向、新網路 |
「為什麼 WebRTC 需要 STUN?」——因為雙方都可能在 NAT 後,得先透過 STUN 問出「我對外的公網 IP:port 長怎樣」,再交換給對方嘗試打洞。而打不打得通,取決於 NAT 類型:
- Full-cone:對外映射固定,任何外部主機都能循該 port 回連——最好打洞。
- Restricted / Port-restricted:只放行「你先連過的」對端(IP/IP+port),需雙方近乎同時對打。
- Symmetric:對每個不同目的地都分配不同對外 port,STUN 問到的映射對 peer 不成立,打洞多半失敗,只能退回 TURN 中繼。
「為什麼微服務在 K8s 還要再談 NAT?」——NodePort/kube-proxy/Cloud NAT 都是同一類邊界改寫,只是控制面不同。