将 unix 程序绑定到特定的网络接口

Ske*_*een 55 routing network-interface

问题: 如何在启动程序的同时确保其网络访问是通过特定网络接口绑定的?

案例: 我想使用相同的 IP (192.168.1.1) 访问两台不同的机器,但可以通过两个不同的网络接口(eth1 和 eth2)访问。

例子:

net-bind -D eth1 -exec {Program 192.168.1.1}
net-bind -D eth2 -exec {Program 192.168.1.1}
Run Code Online (Sandbox Code Playgroud)

以上是我想要的近似值,灵感来自通过primusrunoptirun完成的硬件绑定。

挑战:正如在相关线程中所建议的,所使用的接口不是由程序选择的,而是由内核选择的(因此是上例中的预绑定语法)。

我找到了一些相关的解决方案,但并不令人满意。它们基于通过用户特定的网络黑名单绑定网络接口;即,以只能访问单个特定网络接口的用户身份运行该进程。

Gra*_*eme 47

对于 Linux,这已经在 Superuser - How to use different network interfaces for different processes上得到了回答.

最流行的答案使用一种LD_PRELOAD技巧来更改程序的网络绑定,但现代内核支持一种更灵活的功能,称为“网络命名空间”,该功能通过ip程序公开。这个答案显示了如何使用它。从我自己的实验中,我做了以下(作为 root):

# Add a new namespace called test_ns
ip netns add test_ns

# Set test to use eth0, after this point eth0 is not usable by programs
# outside the namespace
ip link set eth0 netns test_ns

# Bring up eth0 inside test_ns
ip netns exec test_ns ip link set eth0 up

# Use dhcp to get an ipv4 address for eth0
ip netns exec test_ns dhclient eth0

# Ping google from inside the namespace
ip netns exec test_ns ping www.google.co.uk
Run Code Online (Sandbox Code Playgroud)

也可以使用unsharensenter命令在一定程度上管理网络命名空间。这还允许您为 PID、用户和挂载点创建单独的空间。有关更多信息,请参阅:

  • 您能否提供有关如何撤消该操作的说明?您只需“ip netns remove test_ns”即可恢复正常吗?或者你需要做一些特别的事情吗? (2认同)

Ske*_*een 24

我接受格雷姆的回答;这只是为了解释我为解决我的问题而对他的建议所做的更改的后续行动。

我没有在命名空间内绑定物理接口,而是创建了一对虚拟网络接口,一端在网络命名空间中,另一端在根中。然后包通过这个虚拟网络从命名空间路由到根命名空间,然后到物理接口。- 因此,我可以运行所有普通数据传输,此外还可以启动只能访问特定界面的进程。

# Create the eth0 network namespace
ip netns add eth0_ns

# Create the virtual network pair
ip link add v_eth0a type veth peer name v_eth0b

# Move v_eth0a to the eth0_ns namespace, the virtual pair is now split
# between two network namespaces.
ip link set v_eth0a netns eth0_ns

# Configure the ends of the virtual network pairs
ip netns exec eth0_ns ifconfig v_eth0a up {{NAMESPACE_IP}} netmask {{NAMESPACE_NETMASK}}
ifconfig v_eth0b up {{ROOT_NS_IP}} netmask {{ROOT_NS_NETMASK}}

# Setup routing from namespace to root
ip netns exec eth0_ns route add default gw {{ROOT_NS_IP}} dev v_eth0a

# Setup IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s {{ROUTE_SOURCE}}/24 -o {{NETWORK_INTERFACE}} -j SNAT --to-source {{ROUTE_TARGET}}
Run Code Online (Sandbox Code Playgroud)

一旦为 eth0 和 eth1 设置了接口,使用它们各自的命名空间 eth0_ns 和 eth1_ns,程序就可以通过以下方式在指定的接口上执行;

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish
Run Code Online (Sandbox Code Playgroud)

  • 做得好!我认为您还可以创建一个桥接设备并将默认命名空间和虚拟对与其中一个物理设备桥接。不过这看起来是等价的。 (4认同)
  • 我做了,但只是来自新的命名空间。我认为我遇到的问题与网络管理员有关,但我没有弄清楚,否则我会更新我的答案。 (2认同)
  • 呻吟。很棒的例子,但它完全无法使用,因为“{{ }}”的内容没有记录。 (2认同)

int*_*ika 10

解决方案 I:预加载特定库

  • App-Route-Jail:使用 ld_preload 强制接口网关(好主意,但需要 root 或标记功能)用法在下面的注释中详细说明

  • Proxybound:使用 ld_preload 强制代理到特定应用程序(这是使用代理而不是接口)

  • Force-Bind:有很多功能,但绑定泄漏(不可靠)

  • Bind-Interface-IP:太简单和泄漏连接(不可靠)

  • 绑定IP:方式太简单和泄漏连接(不可靠)

解决方案二:Linux 用户空间

  • 经典的 linux 用户空间ip-netns:很好的解决方案,但需要 root 和界面只能存在于一个用户空间

  • Firejail:Firejail 可以强制应用程序使用特定网络,但兼容性有限(例如它与 tun 接口不兼容)。firejail 不需要 rootfirejail --dns=8.8.8.8 --noprofile --net=eth0 --ip=192.168.1.1 app-command

  • Firejail with netns:Firejail 可以强制应用程序使用单独创建的特定用户空间,这让我们可以在没有 root 的情况下命名空间firejail --dns=8.8.8.8 --noprofile --netns=nameOfyourNS app-command

  • Firejail with masquerade 和 bridge:Firejail 可以强制应用程序使用带有 iptables masquerade特定接口,这很好,不需要 root,但这需要 ip_forward 并且可能暗示安全影响firejail --net=br0 firefox

方案三:Linux iptables

iptables 可用于此目的,但这需要 ip_forward 并且如果未正确配置可能意味着安全影响,示例 1示例 2示例 3示例 4

解决方案(I、II 和 III)说明:

线卫

如果您正在使用 VPN(尤其是wireguard)并且您想将此解决方案应用于wireguard接口(带有用户空间的wireguard),您可以按照链接指示创建一个包含wg接口的用户空间(因此仅限于vpn接口) ) 也可以将其与firejail --netns=container无需 root 即可使用用户空间结合使用。

如何找到接口网关

有很多找到网关的解决方案这里有一些命令可以找到使用的网关

$ route
$ route -n
$ ip rule list
$ ip route show
$ netstat -rn
$ cat /etc/network/interfaces
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0
$ traceroute www.google.com
$ ip route show 0.0.0.0/0 dev eth0
Run Code Online (Sandbox Code Playgroud)

如何使用 App-Route-Jail

  • 构建 App-Route-Jail
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Root-Jail
chmod 755 make.sh
./make.sh
Run Code Online (Sandbox Code Playgroud)
  • 在这个例子中192.168.1.1为未来标记的数据包(被监禁的应用程序)添加一个路由作为强制网关,这个路由规则不会影响其他应用程序,这个操作只需要在系统启动时完成一次,例如如果你想每天使用此解决方案
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
Run Code Online (Sandbox Code Playgroud)
  • 启动您想要监禁的应用程序
MARK=10 LD_PRELOAD=./mark.so firefox
Run Code Online (Sandbox Code Playgroud)
  • 测试广域网IP地址
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me
Run Code Online (Sandbox Code Playgroud)


Han*_*nes 6

还有另一种解决方案是预加载。

绑定到接口

BindToInterface加载一个强制程序使用特定接口的库。intika 强制绑定到特定 IP 地址的答案中的其他 3 个绑定选项。因此,而不是例如 0.0.0.0,这意味着您可以绑定到 192.168.178.68 的所有接口,以绑定仅侦听该接口。但是,当建立连接时,仍然会使用默认路由表并使用其他接口。

BindToInterface 的使用方式类似于BIND_INTERFACE=eth1 LD_PRELOAD=./bindToInterface.so <your command>. 您还可以覆盖 DNS 服务器,当您的默认 DNS 服务器无法通过绑定接口访问时,这非常有用。这加快了连接速度。您可以通过环境变量来控制它DNS_OVERRIDE_IP=8.8.8.8

如果您的程序绑定到 eth1,则它无法到达 localhost。如果它应该到达它或其他 IP,您可以通过排除它们BIND_EXCLUDE=127.0.0.1

所以命令看起来像 BIND_INTERFACE=eth1 DNS_OVERRIDE_IP=8.8.8.8 BIND_EXCLUDE=127.0.0.1 LD_PRELOAD=./bindToInterface.so <your command>.

Github 页面上解释了更多绑定到界面的选项。



目前(2020 年 3 月)firejail 解决方案无法通过 Wifi 实现,请参阅https://github.com/netblue30/firejail/issues/3000