前言
某支 API 要掛載到 APIM 上,我的同事問我這支 API 的後端伺服器有跟 Data plane 同網段嗎?同網段可能會有問題喔~ 我又嗅到新知識的味道了,趕緊來研究跟記錄一下:
TCP 4-Tuple
首先必須先簡單提一下這個概念。這概念是指,每個 TCP 連線都是透過四個關鍵資訊組合成唯一識別,分別為:
(Client IP, Client Port, Server IP, Server Port)
- Client IP: 來源 IP 位址
- Client Port: 來源埠號
- Server IP: 目的地 IP 位址
- Server Port: 目的地埠號
或稱 Source & Destination 這四個資訊合起來,可確保網路上每一條 TCP 連線都是獨一無二的。
因此若 TCP 三方交握時,如果接收到的封包其 4-tuple 不符合系統 listen 的條件(如目的 IP 或目的 Port 不正確),該封包會被丟棄,不會產生連線。
情境分析
不同網段(非對稱路由)
假設:
Client:10.1.1.10 (網段 A)
NLB VIP:10.2.2.100 (網段 B)
Server A:10.2.2.50 (網段 B)
請求階段(去程)
- Client → Gateway:
- Client 準備發送一個封包給 NLB VIP (10.2.2.100)。
- 它檢查自己的路由表,發現 10.2.2.100 不在本地網段 A,故必須將封包交給預設閘道 (Default Gateway) 來轉送。
- 此時封包內容:
- 來源 IP:10.1.1.10
- 目的 IP:10.2.2.100 (VIP)
- Gateway → NLB → Server A:
- 封包經由路由器,最終到達 NLB。
- NLB 執行 DNAT (目的位址轉換),將目的 IP 從 VIP (10.2.2.100) 改為 Server A (10.2.2.50)。
- 此時封包內容更新為:
- 來源 IP:10.1.1.10 (不變)
- 目的 IP:10.2.2.50 (Server A)
- NLB 將此封包傳給 Server A。
- 回應階段 (回程)
- Server A → Gateway:
- Server A 收到請求,準備回覆給 Client(10.1.1.10)。
- 它檢查自己的路由表,發現 10.1.1.10 不在本地網段。因此,它也必須將回應封包交給自己的預設閘道。在這種架構下,這個閘道器通常就是負載平衡器本身,或是指向它的路由器。
- 此時回應封包內容:
- 來源 IP:10.2.2.50 (Server A)
- 目的 IP:10.1.1.10 (Client)
- Gateway (NLB) 進行反向轉換:
- NLB 收到了來自 Server A 的回程封包。
- NLB 查詢自己的連線狀態表 (State Table),發現這個封包屬於先前建立的一個連線。
- 它執行反向來源位址轉換 (Reverse SNAT),將封包的來源 IP 從 Server A (10.2.2.50) 改回 VIP(10.2.2.100)。
- 封包內容最終更新為:
- 來源 IP:10.2.2.100 (VIP)
- 目的 IP:10.1.1.10 (Client)
- NLB → Client:
- NLB 將這個修改過的封包送回給 Client。
- Client 收到一個來自 10.2.2.100 (VIP) 的回應。因為它當初就是向 VIP 發起連線,所以 TCP 4-Tuple 可對應,連線視為合法。
同個網段(對稱路由)
假設:
- Client:10.2.2.10 (網段 B)
- NLB VIP:10.2.2.100 (網段 B)
- Server A:10.2.2.50 (網段 B)
- 請求階段(去程)
- Client → NLB:
- Client 準備發送封包給 NLB VIP (10.2.2.100)。
- 它檢查自己的路由表,發現 10.2.2.100 在同一個網段內,因此直接透過 Layer 2 (MAC 位址) 傳送,不需要經過閘道器。
- 此時封包內容:
- 來源 IP:10.2.2.10
- 目的 IP:10.2.2.100 (VIP)
- NLB → Server A:
- NLB 執行 DNAT,將目的 IP 從 VIP (10.2.2.100) 改為 Server A (10.2.2.50)。
- 此時封包內容更新為:
- 來源 IP:10.2.2.10 (不變)
- 目的 IP:10.2.2.50 (Server A)
- NLB 將此封包傳給 Server A。
- 回應階段(回程)- 問題發生處
- Server A 收到請求後,準備回覆給 Client(10.2.2.10)。
- Server A 檢查自己的路由表,根據路由表的最長前綴匹配原則(Longest Prefix Match)1,發現 10.2.2.10 在同一個網段內。因此會直接在同一個 Layer 2 網段內回應 Client,繞過了 NLB。
- 直接回應(繞過 NLB):
- Server A 直接將回應封包傳送給 Client,完全繞過了 NLB。
- 此時回應封包內容:
- 來源 IP:10.2.2.50 (Server A)
- 目的 IP:10.2.2.10 (Client)
- TCP 4-Tuple 不匹配:
- Client 收到來自 10.2.2.50 的回應封包。
- 但是 Client 原本是向 10.2.2.100 (VIP) 發起連線的。
- TCP 4-Tuple 不匹配:
- 預期的 4-Tuple:(10.2.2.10, port_x, 10.2.2.100, port_y)
- 實際收到的 4-Tuple:(10.2.2.10, port_x, 10.2.2.50, port_y)
- Client 無法將此回應與原本的連線建立關聯,因此會丟棄此封包。
解決方案
- 啟用 SNAT (Source NAT)2: NLB 同時執行 DNAT 和 SNAT,將來源 IP 也改為 NLB 的 IP,強制回程流量必須經過 NLB
- 分離網段: 最直接的做法,將 Client 和 Server 放在不同網段。