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

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

我能够设置一个网络命名空间,使用 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 从我的服务器重定向到命名空间中的应用程序。目标是在 LAN 内的计算机上打开浏览器并使用以下命令获取 Web 界面http://我的服务器IP:8112(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 本人向我指出了一个Debian 管理文章解释通用 iptables TCP 代理。应用于手头的问题,他们的脚本将如下所示:

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 还建议使用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

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

答案1

将网络命名空间与主命名空间互连总是让我烦恼。我通常创建命名空间的原因是因为我希望它被隔离。根据您试图通过命名空间实现的目标,创建互连可能会破坏该目的。

但即使孤立我仍然想通过网络戳它,为了方便。

此解决方案可让您保持隔离并将一些连接转发给它。 您不需要在两个网络命名空间之间创建所有网络,只需转发一个端口即可。 在您想要接受连接的命名空间中运行此命令。必须以 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 ...内的其余部分,然后一旦进入网络命名空间,它就会再次与另一个.myvpnmyvpnsocat

或者将其作为 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.

答案2

我一直遇到 iptables 重定向问题(可能是我的错,我很确定这是可行的)。但对于像你这样的情况,在我看来,在没有 iptables 的用户空间中做到这一点更容易。

基本上,您需要在“默认”工作区中有一个守护程序,侦听 TCP 端口 8112 并将所有流量重定向到 10.200.200.2 端口 8112。所以它是一个简单的 TCP 代理。

以下是如何做到这一点索卡特:

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 标头中的代理请求中。

答案3

对于洪水,这是我的解决方案。不需要 iptables。步骤如下:

  1. 启动你的 openvpn 隧道
  2. 创建命名空间并将您的 openvpn 隧道引入其中:
ip netns 添加 $NS
# 等待 TUN 出现
而[[ $(ip 路由|grep $TUN|wc -l) == 0 ]];睡觉1;完毕
MY_IP=$(ip 地址显示 $TUN|grep inet|cut -d' ' -f6|cut -d'/' -f1)
# 对于您的 openvpn 连接,提取网关 IP 的方式可能会有所不同
GATEWAY_IP=$MY_IP
# 将我的 $TUN(VPN 接口)囚禁到命名空间中
ip 链接集 $TUN netns $NS
# 为接口设置一个子网(相当于 VPN 服务器给我的子网)
ip netns exec $NS ifconfig $TUN $MY_IP/24 向上
# 启动环回
ip netns exec $NS ifconfig lo 127.0.0.1/8 向上
# 设置远程网关(您的点对点 VPN IP 地址)
ip netns exec $NS 路由添加默认网关 $GATEWAY_IP
  1. 在您的默认命名空间和您创建的命名空间之间建立 veth 连接:
# 设置veth接口用于命名空间之间的通信
ip link 添加 veth0 类型 veth 对等名称 veth1
# 将第二个 veth 移动到你的命名空间
ip 链接设置 veth1 netns $NS
# 将未使用的 IP 范围中的 IP 提供给第一个 veth
ifconfig veth0 10.1.1.1/24 以上
# 第二个
ip netns exec $NS ifconfig veth1 10.1.1.2/24 向上
# TODO: 在 veth1 和 eth 接口之间建立一个桥接器,让它与 LAN 通信
# 设置 DNS 客户端。 ip netns 将使用此文件模拟 /etc/resolv.conf:
mkdir -p /etc/netns/$NS
echo“名称服务器8.8.4.4”>/etc/netns/$NS/resolv.conf
  1. 在 $NS 中运行 deluged,在默认命名空间中运行 deluge-web。将 deluge-web 指向 10.1.1.2 veth IP 地址,deluged 将在此侦听其连接。

瞧!您的 deluge 网络受到 VPN 的保护,同时您的 deluge 网络可以在您的家庭网络上自由访问

答案4

@AndrDevEK 的答案很有用。为了扩展这一点,您可能不想安装socat.在这种情况下,您可以通过稍微复杂的 SSH 端口转发设置来实现相同的效果。特别是,与 unix 域套接字进行端口转发的功能在这里非常有用,因为 unix 域套接字的操作独立于网络名称空间:

sudo ip netns exec myvpn su -c "ssh -N -L /tmp/myunixsock:localhost:8112 localhost" $USER &
ssh_pid1=$!
ssh -N -L localhost:8112:/tmp/myunixsock localhost &
ssh_pid2=$!

清理:

sudo kill $ssh_pid1
kill $ssh_pid2
rm /tmp/myunixsock

第一个ssh -N -L是在 myvpn 命名空间内启动的。这将创建一个 unix 域套接字/tmp/myunixsock并侦听它。传入连接将转发到 localhost:8112(在 myvpn 命名空间内)。第二个ssh -N -L在默认命名空间中启动。这将创建一个侦听 TCP 端口并将传入连接转发到 unix 域套接字。

应该注意的是,为了使其工作,ssh您的网络名称空间内部需要工作(如果尚未工作)(并且无密码的 pubkey 操作很有帮助):

sudo ip netns exec myvpn ip link set up dev lo
sudo ip netns exec myvpn /usr/sbin/sshd -o PidFile=/run/sshd-myvpn.pid
ssh-copy-id localhost

相关内容