这可能是一个相当新手的问题,但是......
我在 Ubuntu 18.04.3 LTS 上,我有一个VPN我想用它做一些应用程序。我查看了namespaced-openvpn
并且成功了!需要注意的是,我无法本地连接到此应用程序(出于管理目的)。
有没有办法将 VPN 隧道内的某个端口转发到本地主机VPN 隧道不会将其用于其他目的并因此泄露过多信息吗?
我已经可以做的事情:
- 跑步
namespaced-openvpn
-脚本:sudo ./namespaced-openvpn --namespace vpn --config /etc/openvpn/vpn-xxxxx.ovpn
- 在网络命名空间内执行应用程序:
sudo ip netns exec vpn application
我想要实现的目标:
1234
从真实的本地主机(enp3s0
以太网适配器)连接到在 VPN 隧道内启动的应用程序(例如在端口)- 转发此端口,以便我可以从 LAN 中的其他计算机访问它。
答案1
很多年过去了,但万一有人碰巧遇到这个问题,我希望过去几天我也能遇到。
希望这对某人有帮助。
首先,这里是 namespaced-vpn,它完成了使一切运行起来的 90% 的工作。
https://github.com/slingamn/namespaced-openvpn
这里有一个几乎与此完全相同的问题的答案,尽管我不明白做什么以及为什么要这样做,但它对我帮助很大。 https://unix.stackexchange.com/questions/391193/how-to-forward-traffic-between-linux-network-namespaces
我将尝试使用我在搜索中找到的零碎信息,解释我经过大量尝试和错误后得出的结论。
我认为,与将连接转发到您的服务(而不是从运行服务的 PC)最相关的部分是这个(请注意 PREROUTING 后面的感叹号):
iptables -t nat -A PREROUTING ! -s 10.0.0.0/24 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
其中,10.0.0.0/24
代表您不想转发的 IP 范围。
这主要是为了防止路由循环,即任何可通过10.0.0.0/24
子网访问的服务都会被路由回自身。--
dport 80 仅转发寻求端口 80 的数据包,即 Web 服务器连接。
10.0.0.2
是已移动到服务器正在运行的命名空间内的 veth 接口。
这使得10.0.0.0/24
寻求端口 80 服务的传入数据包(不是来自子网的数据包)的目标 IP 被转换为10.0.0.2
。示例:192.168.1.200:80
变成10.0.0.2:80
,这大概是服务器所在命名空间内的接口。
我在多个命名空间中启动并运行了多个 vpn 隧道。如果我不将 PREROUTING 规则添加到我的 iptables,我将无法从 LAN 上的 PC 外部访问资源。
如果您希望从自己的电脑上访问它,则必须添加一条规则,例如:
iptables --table nat --append OUTPUT --destination 192.168.1.2 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.0.0.2
因此,如果您在服务器所在的电脑上输入浏览器192.168.1.2
来访问您的服务器,它将被路由到您的服务器10.0.0.2
。
我将尝试解释我的一部分设置...
命名空间示例:ip netns add ns_example
创建 veth 对。一端将留在 root/normal 命名空间中(我称之为host
),另一端将进入带有 VPN 的命名空间。
ip link add dev ihost type veth peer name ivpn
将 veth 对的 vpn 端移至目标命名空间:
ip link set dev ivpn netns ns_example
将 ips 分配给您创建的 veth 对。
我使用 /32 是因为我只想分配这个确切的 IP,而不是一个范围。否则,当我启动设备时,一些路由会自动插入到我的ip route
表中,这会扰乱我其他命名空间的路由。
分配给主机端。
ip addr add 10.0.0.1/32 dev ihost
要分配给已移至命名空间的 vpn 端,必须在命令前加上前缀 ..
ip netns exec TARGET_NAMESPACE
因此,要将 IP 分配给 VPN 端:
ip netns exec ns_example ip addr add 10.0.0.2/32 dev ivpn
现在启动接口。
ip link set dev ihost up
ip netns exec ns_example ip link set dev ivpn up
这里我添加了路由和 iptables 来使流量在它们之间流动。
从根命名空间,要到达 VPN 端(10.0.0.2
),请使用接口 ihost 并将源地址重写为根命名空间端(10.0.0.1
)。
ip route add 10.0.0.2/32 dev ihost src 10.0.0.1
在 VPN 命名空间内,从相反的角度做同样的事情。
ip netns exec ns_example ip route add 10.0.0.1/32 dev ivpn src 10.0.0.2
现在,我添加相同的操作,iptables
这些操作与之分开ip route
,但可以完成类似的任务。
任何数据包10.0.0.2
的源地址都会被重写为10.0.0.1
iptables --table nat --append POSTROUTING --destination 10.0.0.2/32 --jump SNAT --to-source 10.0.0.1
完全相同的东西,但是视角和内部命名空间相反。
ip netns exec ns_example iptables --table nat --append POSTROUTING --destination 10.0.0.1/32 --jump SNAT --to-source 10.0.0.2
如果我理解正确的话,源地址重写只是为了确保数据包知道如何返回命名空间,反之亦然。
现在,例如:要访问端口 8080 上的命名空间中的 torrent webui,我会这样做。
任何数据包都会发送到我的 LAN ip(例如:我192.168.1.2:8080
在浏览器中输入)。它将把目的地重写到我的 torrent 客户端正在运行的命名空间(例如:)10.0.0.2
。
iptables --table nat --append OUTPUT --destination 192.168.1.2/32 --protocol tcp --match tcp --dport 8080 --jump DNAT --to-destination 10.0.0.2
此规则专门仅转发端口 8080,并且此规则适用于您访问正在运行服务的 PC 上的服务。网络上的任何其他 PC 都192.168.1.2:8080
需要我在答案顶部提到的 PREROUTING 规则(只需将 --dport 80 更改为 --dport 8080 或您需要的任何端口/协议)。
对于使用此方法和 namespaced-vpn.py 脚本的用户。如果您必须重置 vpn,则可能会遇到问题。当命名空间 vpn 检测到目标命名空间内除lo
环回接口以外的接口时,它会抛出异常。
当我使用 namespaced-vpn.py 时,当我的目标命名空间已经存在并且它有我的 veth 对时,以下是抛出异常的部分。
if os.path.exists(os.path.join('/var/run/netns', namespace)):
adapters = _adapter_names(namespace)
if adapters != [b'lo']:
LOG.error('Namespace %s already has adapters %s, exiting.' % (namespace, adapters))
raise Exception
以下是我使用过的一个示例修改。
allowed_adapters = [b'lo', b'ivpn']
if os.path.exists(os.path.join('/var/run/netns', namespace)):
adapters = _adapter_names(namespace)
# Iterate and ensure all are in allowed list
for a in adapters:
if not a.split(b'@')[0] in allowed_adapters:
LOG.error('Namespace %s has non-whitelisted adapters %s, exiting.' % (namespace, adapters))
raise Exception
只需确保在 `def setup_namespace(namespace)` 函数底部为每个你认为已经存在的接口添加这样的调用。用设备名称替换 LO
subprocess.check_call(_enter_namespace_cmd(namespace) + [IP_CMD, 'link', 'set', 'LO', 'up'])
例子:
subprocess.check_call(_enter_namespace_cmd(namespace) + [IP_CMD, 'link', 'set', 'ivpn', 'up'])
对于运行连接到 VPN 接口的 Bittorrent 客户端的用户,您可能会遇到客户端因某种原因随机停止连接的问题。例如,您早上醒来发现所有精彩的下载在您离开 10 分钟后都冻结了。
我相信这个问题是由于 VPN 软件 IE openvpn 因某种原因(错误、ping 重启等)重新连接到 VPN 提供商并被分配了新的 IP 地址。VPN 接口可能需要离线一秒钟才能重置配置,这会导致客户端出现故障(qBittorrent 肯定会这样做)。我开始研究的一个“修复”是编写一个脚本,用于检测 VPN 接口何时收到新 IP 地址或因某种原因离线。该脚本应该优雅地(重要:优雅地避免损坏某些东西/文件系统错误)退出 Torrent 客户端,然后重新启动它。我还没有一个可行的脚本,但这似乎是解决这个问题的一个不错的方法。
答案2
好的。似乎这个问题太复杂了,没有人能真正回答,或者可能之前已经回答过了,只是没人愿意回答。
无论如何:我又花了一天时间研究这个问题,发现既然我只对为应用程序的 Web 界面公开一个端口感兴趣,那么我还不如使用socat
。 所以我做了。
创建 namespaced-openvpn 连接并启动该网络命名空间内的应用程序后,我在专用终端中运行了以下命令:
sudo socat tcp-listen:PORT-TO-FORWARD-TO,fork,reuseaddr exec:'ip netns exec vpn socat STDIO tcp-connect\:127.0.0.1\:PORT-TO-LISTEN-TO',nofork
笔记:
PORT-TO-FORWARD-TO
是我希望端口转发到的端口(在根网络命名空间中)PORT-TO-LISTEN-TO
是应用程序的端口,我想将其公开到根命名空间127.0.0.1
我必须使用实际的本地主机 IP(而不是localhost
名称,因为它似乎无法正确解析):
确保转义单引号内的双点字符 ( )- 我不确定这是否会导致 DNS 泄漏;据我检查,不会,但我不能确定,因为我不知道如何测试它
剩下要做的事情:
- 自动执行所有命令以启动应用程序并在启动时转发端口:我目前不需要这个,但如果/当我找到如何做到这一点时,我会在这里添加它