我能够设置一个网络命名空间,使用 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 ...
内的其余部分,然后一旦进入网络命名空间,它就会再次与另一个.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
。
考虑设置正确的值并启用指令Requires
和After
。
然后启用并启动命令:
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。步骤如下:
- 启动你的 openvpn 隧道
- 创建命名空间并将您的 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
- 在您的默认命名空间和您创建的命名空间之间建立 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
- 在 $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