使用 iptables 進行埠轉發
我得到了
lo
(127.0.0.1
) 和eth0
(172.17.0.8
)。我想將登陸的數據包重定向127.0.0.1:80
到172.17.42.1:80
(路由來自eth0
)。我試過
iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.1 -j DNAT --to 172.17.42.1:80
但是當我這樣做時,我
curl localhost:80
沒有得到回應,當我這樣做時curl 172.17.42.1:80
,它就起作用了。
當您嘗試訪問 localhost 時,您的源地址是 127.0.0.1,目標地址也是如此。所以,數據包看起來像這樣:
| SRC | DST | | 127.0.0.1 | 127.0.0.1 |
由於本地生成的數據包首先遍歷 OUTPUT 鏈,因此您使用 DNAT 規則修改數據包:
iptables -t nat -A OUTPUT \ -d 127.0.0.1 \ -p tcp --dport 80 \ -j DNAT \ --to 172.17.42.1:80
在 OUTPUT 鏈之後,數據包如下所示:
| SRC | DST | | 127.0.0.1 | 172.17.42.1 |
因此,您看到的第一個錯誤是即使此數據包被路由到源設備之外,目的地也不知道如何正確返回它。因此,您還需要添加額外的 SNAT 規則:
iptables -t nat -A POSTROUTING \ -d 172.17.42.1 \ -p tcp --dport 80 \ -j SNAT \ --to-source <your_ip_addr>
現在,數據包在網路上退出看起來非常正確(源地址將是該設備的公共地址,而不是本地主機地址)。
但是,這還不能解決你的痛苦。
本地機器上生成的數據包的路由決策在兩個地方進行。
- 在 OUTPUT 鏈之前
- 在 OUTPUT 鏈之後和 POSTROUTING 之前
此數據包的決定將在第二階段做出,在 POSTROUTING 鏈中重寫源 IP 之前…
因此,核心安全機制將丟棄數據包,因為預設情況下核心拒絕路由 src 為 127.0.0.1 的數據包。這意味著即使 mangle 與 fwmark 結合也無濟於事。為此,需要啟用 route_localnet。這是 per-iface 變數,它允許將 127/8 用於本地路由目的(預設為 0 - 也就是禁用)。
sysctl -w net.ipv4.conf.all.route_localnet=1
在您的情況下,您可以安全地更改傳出介面名稱的“全部”。
現在,數據包將按照表中之前的規則進行路由,並且由於我們有 POSTROUTING SNAT,我們將修復源 ip 127.0.0.1 並重寫它。
希望這可以幫助。
PS。抱歉,在 2-3 次編輯之前,現在是凌晨 5 點,我還醒著 :)