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


13

我能够设置网络名称空间,使用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>

该应用程序已启动,在此示例中,我使用的是洪水。我尝试了一些具有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本人向我指出了一篇Debian Administration文章,其中解释了通用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

不幸的是,第ve个接口之间的流量被捕获,没有其他任何反应。但是,@ 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接口穿越流量时奇怪的端口改组,但是现在我的问题已解决。


免责声明:我完全没有使用veth设备的经验(尽管发现非常有趣,但是... ;-))。您是否曾经使用tcpdump过检查传入数据包的距离?如果tcpdump -i veth0未显示任何内容,则tcpdumo -i lo可能有必要。
Hauke Laging,2016年

我添加了tcpdump的非详细输出
pskiebe

Answers:


9

我一直遇到iptables重定向问题(可能是我的错,我很确定它是可行的)。但是对于像您这样的情况,在没有iptables的用户域中使用IMO则更容易。

基本上,您需要在“默认”工作区中有一个守护程序,侦听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 Administration网站上找到指南。但我还是喜欢socat更高级的东西-例如将IPv4代理到IPv6,或者剥离SSL以允许旧的Java程序连接到安全服务...

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


1
你让我今天很开心!我从没碰到过socat,它完全可以完成我一段时间以来尝试使用iptables所做的事情。我测试了几个应用程序,它们都可以正常工作,通过tun0连接到外部世界,同时仍然通过veth1提供对其Web界面的访问。
pskiebe '02

1
经过一些测试后,我添加了reuseaddr标志。这样可以防止port already in use在快速连续启动和停止socat时出错:socat -4 TCP-LISTEN:8112,reuseaddr,fork TCP:10.200.200.2:8112
pskiebe '16

8

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

但是为了方便起见,即使是孤立的我也想通过网络对其进行戳戳。

通过该解决方案,您可以保持隔离状态,并始终向其转发一些连接。 您无需仅在转发一个端口的情况下在两个网络名称空间之间创建所有网络。 在要接受连接的名称空间中运行此命令。必须以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


像魅力一样工作

由于我不太熟悉linux管理,因此花了一些时间才知道:确保:在单引号中转义两个字符,否则您可能会遇到错误提示... wrong number of parameters (2 instead of 1)(2或3)。否则:效果很好!非常感谢!
伊戈尔

2

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

  1. 启动您的openvpn隧道
  2. 创建名称空间并将openvpn隧道带到此处:
ip netns添加$ NS
#等待TUN出现
而[[$(ip route | 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 route添加默认gw $ GATEWAY_IP
  1. 在默认名称空间和创建的名称空间之间建立第ve条连接:
#设置用于命名空间之间通信的veth接口
ip链接添加veth0类型veth对等名称veth1
#将第二个veth移到您的名称空间
ip链接集veth1 netns $ NS
#从未使用的IP范围到第一个IP地址
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中运行被淹没的内容,并在默认名称空间中运行deluge-web。将deluge-web指向第10.1.1.2个IP地址,被淹的IP地址将监听其连接。

瞧!当您的家庭网络可免费访问您的洪水网络时,您已经被VPN保护了


2

@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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.