如何通過另一台伺服器路由傳出流量?
我想要實現的是讓來自機器A的 http(s) 請求在目標伺服器看來來自機器B。
舉個例子:
假設我有兩台執行 Ubuntu 的虛擬機A和B,並且生活在同一個 VPN 中,機器A有公共 ip
1.1.1.1
和私有 ip10.1.0.1
,而機器B有公共 ip2.2.2.2
和私有 ip10.1.0.2
,VPN 的 ip 範圍是10.1.0.0/20
。鑑於上述情況,我希望能夠做到這一點:
ssh root@1.1.1.1 root@1.1.1.1:~# curl ifconfig.me 2.2.2.2 root@1.1.1.1:~#
請注意,我正在尋找一種僅路由傳出流量的解決方案,我希望不更改任何傳入流量的路由。
通過執行以下操作,我能夠到達一半:
- 在機器B上啟用 ip 轉發
sysctl -w net.ipv4.ip_forward=1
- 在機器B上更新 iptables
iptables -t nat -A POSTROUTING -s 10.1.0.0/20 -o eth0 -j MASQUERADE
- 在機器A上更新路由
ip route change default via 10.1.0.2
然而,這種方法會破壞所有直接進入的
1.1.1.1
流量,例如ssh
連接到1.1.1.1
我現在必須這樣做ssh -o ProxyCommand="ssh -W %h:%p root@2.2.2.2" root@10.1.0.1
,這對於我的案例來說是不可接受的。據我了解,通過
iptables
在機器A(而不是ip route change default ...
)上使用,我應該能夠通過機器B路由出站流量,但是,到目前為止,我失敗了。我嘗試過的一件事是在機器A
OUTPUT
上更新鏈(機器B設置如上),但這會導致任何和所有請求超時。DNAT
ssh root@1.1.1.1 root@1.1.1.1:~# curl -m 5 ifconfig.me 1.1.1.1 root@1.1.1.1:~# iptables -t nat -A OUTPUT -p tcp -m multiport --dports 80,443 -j DNAT --to-destination 10.1.0.2 root@1.1.1.1:~# curl -m 5 ifconfig.me curl: (28) Failed to connect to ifconfig.me port 80: Connection timed out
雖然我並不熱衷於
iptables
解決方案,但我希望盡可能避免需要下載非標準工具的解決方案。萬一這很重要,我使用的特定平台是 Digital Ocean,所以 VM 是 Droplet,而 VPN 就是他們所說的虛擬私有云。
使用 MASQUERADE 設置進行 SSH 訪問的最簡單解決方案是在以下位置添加埠轉發規則
2.2.2.2
:iptables -t nat -I PREROUTING -i eth0 -p tcp --dport 222 -j DNAT --to-destination 1.1.1.1:22
然後您可以使用
ssh -p 222 user@2.2.2.2
連接到1.1.1.1
.如果此解決方案還不夠,那麼您需要更複雜的設置。
上面的 MASQUERADE 解決方案由於在
1.1.1.1
.在此設置中,用於 SSH 連接的傳入數據包來自面向 Internet 的介面。但是,
1.1.1.1
通過 發送響應數據包2.2.2.2
,這會丟棄它們,因為它們與連接無關。要解決此問題,您需要標記屬於 SSH 連接的數據包:
iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 22 -j MARK --set-mark 1 iptables -t mangle -A PREROUTING -m connmark --mark 1 -j CONNMARK --restore-mark iptables -t mangle -A POSTROUTING -m mark --mark 1 -j CONNMARK --save-mark
第一條規則將數據包標記 1 應用於所有發往 SSH 埠的數據包。
第二條規則將現有連接標記恢復為數據包標記,以處理雙向路由。
第三條規則將現有的數據包標記保存到連接標記以供以後的連接數據包使用。
下一步是為與 SSH 連接相關的數據包創建自定義路由表:
編輯
/etc/iproute2/rt_tables
並添加以下行:100 ssh
接下來,添加自定義路由表:
sudo ip rule add priority 1000 fwmark 0x1 table ssh
然後,將路由添加到自定義路由表:
sudo ip route add table ssh 0.0.0.0/0 via <original default route> dev eth0 src 1.1.1.1