在 NAT 網關中配置 SNAT 源地址有什麼意義嗎?
NAT 網關
linux-router
具有以下 SNAT 規則:Chain POSTROUTING (policy ACCEPT) target prot opt source destination SNAT all -- 10.99.99.50 anywhere to:1.1.1.6
此外,如圖所示,
1.1.1.6
地址是在lo
介面上配置的。從技術上講,這不是必需的,即可以刪除它並且linux-svr
仍然具有連接性。那麼,是否有必要在 NAT 網關中配置 SNAT 源地址?1.1.1.6
僅用於故障排除目的,因為它更容易關聯和追溯linux-svr
?
netfilter與路由無關。這是解釋下面發生的事情的重要內容。netfilter的 NAT 處理會改變地址,並且在某些情況下,當這在路由決策之前完成時,這反過來會改變路由決策。netfilter本身不做路由決策:這只是路由堆棧的作用。
我在下面假設linux-router沒有額外的防火牆規則(在預設的iptables 過濾表中),因為它從未在問題中提及。另外,為了避免增加案例來解決,我假設在 10.99.99.0/24 LAN 中除了linux-srv(和linux-router)之外沒有其他系統需要考慮(解決它們也不難)。
關於刪除 1.1.1.6
SNAT 發生在 POSTROUTING,在任何路由決定之後。如果 SNAT 看到與給定條件匹配的 IP,它將添加一個 conntrack 條目來處理回复。在linux-router上會發生類似的事情(使用
conntrack -E -e NEW
):[NEW] tcp 6 120 SYN_SENT src=10.99.99.50 dst=8.8.8.8 sport=57490 dport=80 [UNREPLIED] src=8.8.8.8 dst=1.1.1.6 sport=80 dport=57490
確保回復真的會回來不是netfilter的工作。這又是路由堆棧作業(包括linux-router無法控制的外部路由)。
在被刪除之前,1.1.1.6 是linux-router的 IP 。添加此 IP 的介面並不重要,因為 Linux 遵循弱主機模型:它可以回答在任何介面上收到的對該 IP 的查詢。刪除此條目不會阻止接收 1.1.1.6 的數據包,因為M10i具有到達 1.1.1.6 的特定路由:使用 1.1.215.48 屬於linux-router。所以linux-router永遠不會收到此 IP 的 ARP 請求:來自M10i的 ARP 請求始終是 1.1.215.48(同樣,M10i的 ARP 表將只記憶體 1.1.215.48,而不是 1.1.1.6)。這意味著這個 IP 的存在無關緊要:linux-router將始終接收 1.1.1.6 的流量。但現在有區別了:
- 如果傳入數據包與先前創建的 conntrack 條目不匹配
如果數據包與來自linux-srv的先前活動無關,則此數據包將到達第一個路由決策,如圖所示。根據其目前的路由表,這應該是這樣的:
# ip route get from 198.51.100.101 iif eth0 1.1.1.6 1.1.1.6 from 198.51.100.101 via 1.1.215.60 dev eth0 cache iif eth0
如果是M10i(或 1.1.215.32/27 LAN 中的任何系統),linux-router也會不時添加 ICMP 重定向,如下所示:
# ip route get from 1.1.215.60 iif eth0 1.1.1.6 1.1.1.6 from 1.1.215.60 via 1.1.215.60 dev eth0 cache <redirect> iif eth0
無論如何,對於來自網際網路的數據包,數據包將被發送回M10i,這可能正在實施嚴格的反向路徑轉發:這個路由返回的數據包將被M10i丟棄,因為它的源(198.51.100.101)位於錯誤的一側它的路由表,因此被嚴格路徑轉發過濾。如果沒有嚴格的反向路徑轉發,這將導致M10i和linux-router之間出現循環,直到數據包的 TTL 減為 0,然後數據包也被丟棄。
- 如果傳入的數據包確實匹配先前 NAT 並由 conntrack 跟踪的流。
上一個範例:從 8.8.8.8 tcp 埠 80 到 1.1.1.6 埠 57490 收到的回複數據包,將被跟踪
conntrack -E
:[UPDATE] tcp 6 60 SYN_RECV src=10.99.99.50 dst=8.8.8.8 sport=57490 dport=80 src=8.8.8.8 dst=1.1.1.6 sport=80 dport=57490 [UPDATE] tcp 6 432000 ESTABLISHED src=10.99.99.50 dst=8.8.8.8 sport=57490 dport=80 src=8.8.8.8 dst=1.1.1.6 sport=80 dport=57490 [ASSURED]
在某個預路由點,conntrack將處理“de-SNAT”(提醒一下,這個數據包甚至不會再次遍歷iptables的 nat 表,這也寫在前面的示意圖中:“nat”表僅用於“NEW” “連接)。目標 IP 現在更改為 10.99.99.50,數據包到達第一個路由決策:它被路由到linux-srv。一切正常。
所以我解釋了當你刪除 1.1.1.6 時會發生什麼:不會影響linux-srv作為網際網路客戶端,但會在M10i和linux-router之間為無關的入口數據包造成一些輕微的中斷。
如果您希望 Internet 上的某些客戶端使用linux-router上的 DNAT 規則訪問linux-srv,那麼對於受影響的連接(例如:linux-srv tcp 埠 80 上的 Web 伺服器),一切都會正常工作而不會中斷。對於其他嘗試, M10i和linux-router之間再次存在小問題。
關於將源 IP 選擇器/過濾器刪除到 SNAT 規則
未提供資訊:傳出介面上是否還有選擇器/過濾器。下面的兩條規則將從
iptables -t nat -n -L
(但不是 fromiptables -t nat -n -v -L
或 betteriptables-save
)獲得相同的輸出:iptables -t nat -A POSTROUTING -o eth0 -s 10.99.99.254 -j SNAT --to-source 1.1.1.6
或者
iptables -t nat -A POSTROUTING -s 10.99.99.254 -j SNAT --to-source 1.1.1.6
實際上,在這種情況下,如果您現在使用以下兩個命令中的任何一個,都無關緊要:
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 1.1.1.6 iptables -t nat -A POSTROUTING -j SNAT --to-source 1.1.1.6
- 1.1.1.6 仍然屬於linux-router
因為從 eth0 一側看不到私有 IP 目標地址,所以linux-router只能有效地路由一個IP 地址:linux-srv的 10.99.99.50 並且該路由只能在它首先從 10.99.99.50 啟動時發生, 以便它被 SNATed 到公共 IP。由於iptables只會在初始連接(狀態 NEW)時創建新的 conntrack 條目,因此在此之後 conntrack 條目將不再更改,一切都會正常工作。
- 從linux-router中刪除 1.1.1.6
- 對於linux-srv,當它連接到 Internet 時,一切仍將按預期工作:前面的解釋也適用。
- 對於從外部到 1.1.1.6 的任何未知傳入連接(例如,從 198.51.100.101):
路由堆棧確定 1.1.1.6 應該路由到M10i(參見前面的解釋)。在狀態 NEW 中添加了一個暫定的 conntrack 條目,並且數據包到達 nat/POSTROUTING:數據包被 SNAT 到 1.1.1.6 並發送回M10i。M10i有一條到 1.1.1.6 的路由,並再次將更改後的數據包發送到linux-router,源 IP 和目標 IP 均為 1.1.1.6(因為源位於其路由表的正確一側,它甚至不會被嚴格反向路徑轉發丟棄)。linux-router接收到一個數據包……從那裡我無法判斷它是否是一個錯誤,但這是在重現你的案例的實驗中擷取的內容
conntrack -E
,從 198.51.100.101 接收到一個 TCP SYN 數據包:# conntrack -E [NEW] tcp 6 120 SYN_SENT src=198.51.100.101 dst=1.1.1.6 sport=48202 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=48202 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=48202 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=60062 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=60062 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=23442 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=23442 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=54429 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=54429 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=7652 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=7652 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=34503 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=34503 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=49256 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=49256 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=58399 [NEW] tcp 6 120 SYN_SENT src=1.1.1.6 dst=1.1.1.6 sport=58399 dport=5555 [UNREPLIED] src=1.1.1.6 dst=1.1.1.6 sport=5555 dport=54522 [...]
即使 netfilter 的行為不正常,M10i和linux-router之間也確實存在循環(直到 TTL 降至 0)。
結論
不要刪除本地 IP 地址 1.1.1.6。您正在創建路由問題,而糾正這些路由問題不是*netfilter的職責。*即使您添加了防止這些循環的防火牆規則,使用不正確的路由也不是明智的行為。
同樣,您可以選擇刪除 SNAT 規則的源 IP 選擇器,但最好不要選擇沒有介面:(即,如果您選擇此規則:)
iptables -t nat -A POSTROUTING -j SNAT --to-source 1.1.1.6
。它之所以有效,是因為有私有 IP 地址,在 Internet 上不可路由。如果不是這種情況,任何來自外部試圖到達linux-router的 eth2 介面後面的 LAN 的連接都將被 SNAT 到 1.1.1.6。例如,如果您添加了 DNAT 規則以使來自linux-srv的某些服務可以從 Internet 訪問,那麼情況也是如此,從而防止linux-srv看到與 1.1.1.6 不同的源地址。這是模擬中的一個具體範例(將 1.1.1.6 恢復到linux-router):
# ip -br a lo UNKNOWN 127.0.0.1/8 1.1.1.6/32 eth0@if5 UP 1.1.215.48/27 eth2@if4 UP 10.99.99.254/24 # iptables -t nat -A PREROUTING -d 1.1.1.6 -p tcp --dport 80 -j DNAT --to-destination 10.99.99.50 # iptables-save | grep -v ^# *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A PREROUTING -d 1.1.1.6/32 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.99.99.50 -A POSTROUTING -j SNAT --to-source 1.1.1.6 COMMIT *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # conntrack -E [NEW] tcp 6 120 SYN_SENT src=198.51.100.101 dst=1.1.1.6 sport=45752 dport=80 [UNREPLIED] src=10.99.99.50 dst=1.1.1.6 sport=80 dport=45752 [UPDATE] tcp 6 60 SYN_RECV src=198.51.100.101 dst=1.1.1.6 sport=45752 dport=80 src=10.99.99.50 dst=1.1.1.6 sport=80 dport=45752 [UPDATE] tcp 6 432000 ESTABLISHED src=198.51.100.101 dst=1.1.1.6 sport=45752 dport=80 src=10.99.99.50 dst=1.1.1.6 sport=80 dport=45752 [ASSURED]
雖然可能不清楚,但這意味著預期的回復是從 10.99.99.50 到 1.1.1.6(而不是 198.51.100.101):linux-srv對真正連接到它的 IP 地址保持盲目,它總是會看到 1.1.1.6 .