在 iptables 中添加 REDIRECT 規則後,Tcpdump 顯示不同的重定向埠
我正在嘗試將客戶端流量定向到正在偵聽的 kubernetes 集群 NodePort
192.168.1.100.30000
。客戶需要發出請求,
192.168.1.100.8000
所以我在 iptables 中添加了以下 REDIRECT 規則:iptables -t nat -I PREROUTING -p tcp --dst 192.168.1.100 --dport 8000 -j REDIRECT --to-port 30000
然後我發出一個 curl,
192.168.1.100:8000
但是,在 tcpdump 中我看到了一個不同的埠:# tcpdump -i lo -nnvvv host 192.168.1.100 and port 8000 tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes [Interface: lo] 20:39:22.685968 IP (tos 0x0, ttl 64, id 20590, offset 0, flags [DF], proto TCP (6), length 40) [Interface: lo] 192.168.1.100.8000 > 192.168.1.100.49816: Flags [R.], cksum 0xacda (correct), seq 0, ack 3840205844, win 0, length 0 [Interface: lo] 20:39:37.519256 IP (tos 0x0, ttl 64, id 34221, offset 0, flags [DF], proto TCP (6), length 40)
我希望 tcpdump 顯示類似
192.168.1.100.8000 > 192.168.1.100.30000
但是,它顯示並導致連接被拒絕錯誤,因為沒有程序列在
192.168.1.100.49816
.192.168.1.100.8000 > 192.168.1.100.49816
我正在使用測試環境,所以我無法訪問遠端設備,這就是我
curl
用來測試 iptables REDIRECT 路徑的原因。添加 REDIRECT 規則是否會導致 tcpdump 將流量重定向到指定埠以外的其他埠?
編輯:
在@AB 建議後添加了以下 OUTPUT 規則:
iptables -t nat -I OUTPUT -d 192.168.1.100 -p tcp --dport 8000 -j REDIRECT --to-port 30000
並且 curl 確實繼續進行,OUTPUT 鏈的數據包計數確實增加了(雖然 PREROUTING REDIRECT 鏈數據包沒有增加):
2 10 600 REDIRECT tcp -- * * 0.0.0.0/0 192.168.1.100 tcp dpt:8000 redir ports 30000
但是,收到以下錯誤:
# curl -vk https://192.168.1.100:8000/v1/api * About to connect() to 192.168.1.100 port 8000 (#0) * Trying 192.168.1.100... * Connected to 192.168.1.100 (192.168.1.100) port 8000 (#0) * Initializing NSS with certpath: sql:/etc/pki/nssdb * NSS error -12263 (SSL_ERROR_RX_RECORD_TOO_LONG) * SSL received a record that exceeded the maximum permissible length. * Closing connection 0 curl: (35) SSL received a record that exceeded the maximum permissible length.
另外,嘗試添加一個遠端系統網路,這次 PREROUTING REDIRECT CHAIN 數據包計數在執行後增加
remotesystem curl ...
(但 OUTPUT CHAIN 不增加):2 34 2040 REDIRECT tcp -- * * 0.0.0.0/0 172.16.128.1 tcp dpt:8000 redir ports 30000
錯誤:
# ip netns exec remotesystem curl -vk https://192.168.1.100:8000/v1/api * About to connect() to 192.168.1.100 port 8000 (#0) * Trying 192.168.1.100... * Connection timed out * Failed connect to 192.168.1.100:8000; Connection timed out * Closing connection 0 curl: (7) Failed connect to 192.168.1.100:8000; Connection timed out
需要說明的是:OP 的測試是從系統 192.168.1.100 到它自己完成的,而不是從遠端系統完成的,這就是問題的原因。在這種情況下,埠沒有更改,因為沒有匹配的 NAT 規則,而如果從遠端系統完成,它會匹配。
下面的示意圖顯示瞭如何對數據包執行操作順序:
原因是 NAT 在 Linux 上的工作方式:iptables僅在表中看到
nat
新 conntrack 流的第一個數據包的數據包(因此處於 NEW 狀態)。當來自遠端系統時,此規則可以正常工作。在這種情況下,看到的第一個數據包將是一個傳入數據包:
to port 8000 --> AF_PACKET (tcpdump) --> conntrack --> nat/PREROUTING (iptables REDIRECT): to port 30000
--> routing decision --> ... --> local process receiving on port 30000
同一流中的所有後續數據包將直接使用 conntrack 處理埠更改(或回复的埠反轉),並將跳過
nat
表中的任何 iptables 規則(如示意圖中所述:nat
僅諮詢NEW
連接的表)。因此,(跳過回複數據包部分),下一個傳入數據包將改為:
to port 8000 --> AF_PACKET (tcpdump) --> conntrack: to port 30000
--> routing decision --> ... --> local process receiving on port 30000
對於系統自身的測試,第一個數據包不是傳入數據包,而是傳出數據包。相反,使用傳出
lo
介面會發生這種情況:
local process client curl --> routing decision --> conntrack --> nat/OUTPUT (
no rule here
)
--> reroute check --> AF_PACKET (tcpdump) --> to port 8000
現在這個數據包在介面上環回
lo
,它重新出現為一個不再是連接中的第一個數據包的數據包,因此遵循上面的第二種情況:單獨的 conntrack 負責 NAT 並且不呼叫nat/PREROUTING
. 除非在之前的步驟中沒有指示進行任何 NAT:
to port 8000 --> AF_PACKET (tcpdump) --> conntrack
--> routing decision --> ... -->
no
local process receiving on port
8000
由於埠 8000 上沒有任何監聽,作業系統會發回 TCP RST。
為了在本地系統上工作,
REDIRECT
還必須在nat/OUTPUT
鏈中放入一條規則:iptables -t nat -I OUTPUT -d 192.168.1.100 -p tcp --dport 8000 -j REDIRECT --to-port 30000
補充筆記
- 如果該案例用於遠端使用,請不要從本地系統進行測試:測試遍歷的規則不一樣。這使得測試無法反映現實。
只需使用網路命名空間來創建一個袖珍遠端系統,以防沒有其他系統可用。應該與僅具有 OP
nat/PREROUTING
規則並執行curl http://192.168.1.100/
(不需要 DNS)的系統一起使用的範例:ip netns add remotesystem ip link add name vethremote up type veth peer netns remotesystem name eth0 ip address add 192.0.2.1/24 dev vethremote ip -n remotesystem address add 192.0.2.2/24 dev eth0 ip -n remotesystem link set eth0 up ip -n remotesystem route add 192.168.1.100 via 192.0.2.1 ip netns exec remotesystem curl http://192.168.1.100:8000/
tcpdump
和 NAT
tcpdump
發生在AF_PACKET
上面示意圖中的步驟:入口非常早,出口非常晚。這意味著對於遠端系統案例,即使它正在工作,它也永遠不會擷取埠 30000。對於本地系統情況,一旦nat/OUTPUT
添加規則,它將擷取埠 30000。只是不要盲目相信
tcpdump
在進行 NAT 時顯示的地址/埠:這取決於情況和擷取發生的位置。