使用 vpn 将端口转发到网络命名空间中的应用程序

psk*_*ebe 15 iptables port-forwarding openvpn network-namespaces

我能够设置一个网络命名空间,使用 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
Run Code Online (Sandbox Code Playgroud)

之后,我可以检查我的外部 ip 并在命名空间内外获得不同的结果,正如预期的那样:

curl -s ipv4.icanhazip.com
<my-isp-ip>
ip netns exec myvpn curl -s ipv4.icanhazip.com
<my-vpn-ip>
Run Code Online (Sandbox Code Playgroud)

应用程序已启动,我在此示例中使用了 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
Run Code Online (Sandbox Code Playgroud)

如果我指定了 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
Run Code Online (Sandbox Code Playgroud)

但我确实想将端口 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
Run Code Online (Sandbox Code Playgroud)

我尝试了 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
Run Code Online (Sandbox Code Playgroud)

编辑:@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
Run Code Online (Sandbox Code Playgroud)

不幸的是,veth 接口之间的流量被占用,没有其他任何事情发生。但是,@schnouki 还建议将其socat用作 TCP 代理,并且效果很好。

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
Run Code Online (Sandbox Code Playgroud)

我还没有理解当流量通过 veth 接口时奇怪的端口改组,但我的问题现在已经解决了。

Any*_*Dev 12

将网络命名空间与主命名空间互连总是困扰着我。我通常创建命名空间的原因是因为我希望它被隔离。根据您尝试使用命名空间实现的目的,创建互连可能会破坏该目的。

但即使是孤立的我还是想通过网络戳一下,方便起见。

此解决方案可让您保持隔离并无论如何转发一些连接到它。 您不需要仅仅为了转发一个端口而在两个网络命名空间之间创建所有网络。 在要接受连接的命名空间中运行它。必须以 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
Run Code Online (Sandbox Code Playgroud)

它在您运行它的一个网络命名空间中侦听连接,在端口 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
Run Code Online (Sandbox Code Playgroud)

检查/修复的价值ExecStart=/path/to/socat,以“是一个可执行文件的绝对路径”所要求的man systemd.service

考虑设置正确的值并启用指令RequiresAfter.

然后启用并从命令开始:

systemctl daemon-reload
systemctl enable deluge-web-netns
systemctl start  deluge-web-netns
Run Code Online (Sandbox Code Playgroud)

或者在下面运行它 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
}
Run Code Online (Sandbox Code Playgroud)

重新开始 xinetd

service xinetd restart
Run Code Online (Sandbox Code Playgroud)

程序ncat也可以类似于socat.

  • 这应该是公认的答案。这是处理转发端口的最佳方式,而不是创建额外的接口或处理 iptables。 (2认同)

Sch*_*uki 11

我一直遇到 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
Run Code Online (Sandbox Code Playgroud)

fork需要该选项以避免socat在第一个代理连接关闭后停止)。

编辑reuseaddr按照评论中的建议添加。

如果你绝对想用 iptables 来做这件事,Debian 管理网站上有一个指南。但我仍然更喜欢socat更高级的东西——比如将 IPv4 代理到 IPv6,或者剥离 SSL 以允许旧的 Java 程序连接到安全服务......

但是请注意,Deluge 中的所有连接都将来自您的服务器 IP,而不是真实的客户端 IP。如果您想避免这种情况,您将需要使用真正的 HTTP 反向代理,将原始客户端 IP 添加到 HTTP 标头中的代理请求中。