Iptables

使用 vpn 將埠轉發到網路命名空間中的應用程序

  • April 8, 2021

我能夠設置一個網路命名空間,使用 openvpn 建立一個隧道,並在命名空間內啟動一個使用該隧道的應用程序。到目前為止一切順利,但是可以通過 Web 界面訪問此應用程序,我不知道如何將請求路由到 LAN 內的 Web 界面。

我按照@schnouki 的指南解釋瞭如何設置網路命名空間並在其中執行 OpenVPN

ip netns add myvpn
ip netns exec myvpn ip addr add 127.0.0.1/8 dev lo
ip netns exec myvpn ip link set lo up
ip link add vpn0 type veth peer name vpn1
ip link set vpn0 up
ip link set vpn1 netns myvpn up
ip addr add 10.200.200.1/24 dev vpn0
ip netns exec myvpn ip addr add 10.200.200.2/24 dev vpn1
ip netns exec myvpn ip route add default via 10.200.200.1 dev vpn1
iptables -A INPUT \! -i vpn0 -s 10.200.200.0/24 -j DROP
iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o en+ -j MASQUERADE
sysctl -q net.ipv4.ip_forward=1
mkdir -p /etc/netns/myvpn
echo 'nameserver 8.8.8.8' > /etc/netns/myvpn/resolv.conf

之後,我可以檢查我的外部 ip 並在命名空間內外得到不同的結果,正如預期的那樣:

curl -s ipv4.icanhazip.com
<my-isp-ip>
ip netns exec myvpn curl -s ipv4.icanhazip.com
<my-vpn-ip>

應用程序已啟動,我在此範例中使用 deluge。我嘗試了幾個帶有 Web 界面的應用程序,以確保它不是特定於洪水的問題。

ip netns exec myvpn sudo -u <my-user> /usr/bin/deluged
ip netns exec myvpn sudo -u <my-user> /usr/bin/deluge-web -f
ps $(ip netns pids myvpn)
PID TTY      STAT   TIME COMMAND
1468 ?        Ss     0:13 openvpn --config /etc/openvpn/myvpn/myvpn.conf
9302 ?        Sl    10:10 /usr/bin/python /usr/bin/deluged
9707 ?        S      0:37 /usr/bin/python /usr/bin/deluge-web -f

如果我指定 veth vpn1 的 ip,我可以從命名空間內部和外部訪問埠 8112 上的 Web 界面。

ip netns exec myvpn curl -Is localhost:8112 | head -1
HTTP/1.1 200 OK
ip netns exec myvpn curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK
curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK

但我確實想將埠 8112 從我的伺服器重定向到命名空間中的應用程序。目標是在區域網路內的電腦上打開瀏覽器並使用http://my-server-ip:8112獲取 Web 界面(my-server-ip 是實例化網路介面的伺服器的靜態 IP)

編輯:我刪除了創建 iptables 規則的嘗試。上面解釋了我想要做的事情,以下命令應該輸出 HTTP 200:

curl -I localhost:8112
curl: (7) Failed to connect to localhost port 8112: Connection refused
curl -I <my-server-ip>:8112
curl: (7) Failed to connect to <my-server-ip> port 8112: Connection refused

我嘗試了 DNAT 和 SNAT 規則,並使用 MASQUERADE 進行了很好的衡量,但由於我不知道自己在做什麼,所以我的嘗試是徒勞的。也許有人可以幫我把這個結構放在一起。

編輯: 的 tcpdump 輸出tcpdump -nn -q tcp port 8112。不出所料,第一個命令返回 HTTP 200,第二個命令以拒絕連接終止。

curl -Is 10.200.200.2:8112 | head -1
listening on vpn0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.200.200.1.36208 > 10.200.200.2.8112: tcp 82
IP 10.200.200.2.8112 > 10.200.200.1.36208: tcp 145

curl -Is <my-server-ip>:8112 | head -1
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
IP <my-server-ip>.58228 > <my-server-ip>.8112: tcp 0
IP <my-server-ip>.8112 > <my-server-ip>.58228: tcp 0

編輯:@schnouki 本人向我指出了一篇解釋通用 iptables TCP 代理的 Debian 管理文章。應用於手頭的問題,他們的腳本將如下所示:

YourIP=<my-server-ip>
YourPort=8112
TargetIP=10.200.200.2
TargetPort=8112

iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT \
--to-source $YourIP
iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort

不幸的是,veth 介面之間的流量被擷取,沒有其他任何事情發生。但是,@schnouki 也建議使用socatTCP 代理,這非常有效。

curl -Is <my-server-ip>:8112 | head -1
IP 10.200.200.1.43384 > 10.200.200.2.8112: tcp 913
IP 10.200.200.2.8112 > 10.200.200.1.43384: tcp 1495

當流量通過 veth 介面時,我還沒有理解奇怪的埠改組,但我的問題現在解決了。

我一直有 iptables 重定向的問題(可能是我的錯,我很確定它是可行的)。但是對於像你這樣的情況,IMO 更容易在沒有 iptables 的使用者空間中進行操作。

基本上,您需要在“預設”工作區中有一個守護程序,監聽 TCP 埠 8112 並將所有流量重定向到 10.200.200.2 埠 8112。所以它是一個簡單的 TCP 代理。

以下是使用socat的方法:

socat tcp-listen:8112,reuseaddr,fork tcp-connect:10.200.200.2:8112

fork需要該選項以避免socat在第一個代理連接關閉後停止)。

編輯reuseaddr按照評論中的建議添加。

如果你絕對想用 iptables 來做,Debian 管理網站上有一個指南。但我仍然更喜歡socat更高級的東西——比如將 IPv4 代理到 IPv6,或者剝離 SSL 以允許舊的 Java 程序連接到安全服務……

但是請注意,Deluge 中的所有連接都來自您的伺服器 IP,而不是真實的客戶端 IP。如果您想避免這種情況,您將需要使用真正的 HTTP 反向代理,將原始客戶端 IP 添加到 HTTP 標頭中的代理請求。

將網路命名空間與主命名空間互連總是困擾著我。我通常創建命名空間的原因是因為我希望它被隔離。根據您嘗試通過創建互連的名稱空間實現的目標可能會破壞該目的。

但即使是孤立的,為了方便起見,我仍然想通過網路戳它。

此解決方案可讓您保持隔離並將一些連接轉發給它。 您不需要為了轉發一個埠而在兩個網路命名空間之間創建所有網路。 在要接受連接的命名空間中執行它。必須以 root 身份執行ip netns exec才能工作。

socat tcp-listen:8112,fork,reuseaddr \
 exec:'ip netns exec myvpn socat STDIO "tcp-connect:127.0.0.1:8112"',nofork

它在您執行它的一個網路命名空間中偵聽連接,在埠 8112 上,然後連接的客戶端exec開始執行ip netns exec myvpn ...以在網路命名空間內執行其餘部分myvpn,然後一旦進入myvpn網路命名空間,它就會再次與另一個創建第二個連接socat

或將其作為 systemd 服務執行

這也使用socat.

創建包含內容的服務配置文件/etc/systemd/system/deluge-web-netns.service

[Unit]
Description=Forwarder to deluge-web in netns
After=network-online.target
#Requires=deluge-web.service
#After=deluge-web.service

[Service]
Type=simple

ExecStart=/usr/bin/socat tcp-listen:8112,fork,reuseaddr exec:'ip netns exec vpn-netns socat STDIO "tcp-connect:127.0.0.1:8112"',nofork
#User=deluge
#Group=deluge
SyslogIdentifier=deluge-web-fwd

Restart=on-failure

# Time to wait before forcefully stopped.
TimeoutStopSec=300

[Install]
WantedBy=multi-user.target

根據. ExecStart=/path/to/socat_ _ _man systemd.service

考慮設置正確的值並啟用指令RequiresAfter.

然後啟用並使用命令開始:

systemctl daemon-reload
systemctl enable deluge-web-netns
systemctl start  deluge-web-netns

或者在下面執行它xinetd

這也使用socat.

創建conf文件,例如/etc/xinetd.d/deluge-web-fwd內容

service deluge-web-vpn-netns
{
   type            = UNLISTED
   socket_type     = stream
   protocol        = tcp
   port            = 8112
   flags           = IPv4 KEEPALIVE
   wait            = no
   user            = root
   server          = /sbin/ip
   server_args     = netns exec vpn-netns socat STDIO tcp-connect:127.0.0.1:8112
}

重新開始xinetd

service xinetd restart

程序ncat也可以使用類似的socat

引用自:https://unix.stackexchange.com/questions/257510