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


39

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

案例: 我想访问两个具有相同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}

上面是我想要的近似值,受primusrunoptirun进行的硬件绑定的启发。

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

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


您是在暗示您的计算机已连接到两个不同的网络,都为192.168.1.0?您的路由表是什么样的?如果要限制进程可见的接口,最简单的解决方案是cgroups,这是一个较重的容器。
lgeorget 2015年

是的,两个不同的网络都在同一IP范围内。我不确定我是否要限制可见的接口,而只指示默认使用哪个接口?:)
Skeen 2015年

3
您提出的要求很困难是有一个充分的理由:使用相同的IP域将两个网络互连起来,就像在一栋楼中有两层具有相同编号的电梯中。IP范围是用来标识域的,而不是输出接口。但是,必须有一种方法可以解决您使用iptables进行的有缺陷的网络设计。
lgeorget

我正在将系统连接到两个不同的就地基础架构,因为这些基础架构从未设计为可以交互,因此在这方面网络设计存在缺陷。
Skeen 2015年

1
我对NAT的争论是,整个地址空间通常都隐藏在NAT的后面,当我连接两个NAT架构的基础结构时,就会发生冲突。-我无权修改基础架构。-我尝试将网络名称空间与虚拟网络接口对(名称空间中的一个,根名称空间中的一个)结合使用,将根名称空间与物理接口桥接,并在网络名称空间中运行程序。-这似乎可行,但是我无法获得根名称空间之外的访问权限(即,机器本身之外没有访问权限)。
Skeen 2015年

Answers:


34

对于Linux,这已经在超级用户上得到了解答- 如何将不同的网络接口用于不同的进程?

最受欢迎的答案是使用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

也可以使用unsharensenter命令在某种程度上管理网络名称空间。这还允许您为PID,用户和安装点创建单独的空间。有关更多信息,请参见:


“在此之后,eth0将无法在名称空间之外的程序中使用” –因此,我在执行此操作时会因为其他所有问题而断开连接?
Skeen 2015年

1
@Skeen,是的,因此大概您会将没有其他程序使用的接口推入名称空间,并正常使用您的主要接口。
Graeme 2015年

1
@Graerne; 这两个接口都在积极使用。我承担不起删除接口的费用。
Skeen 2015年

以及默认网关怎么办?wvdial例如似乎并没有设置它在所有...所以它必须在命名空间本身被定义
闪光雷

您能否提供有关如何撤消该操作的说明?你只是ip netns remove test_ns恢复正常吗?还是您需要做些特别的事情?
Multihunter

17

我接受格雷姆的回答;这只是一个后续步骤,以解释我对他为解决我的问题的建议所做的更改。

我没有将物理接口绑定在名称空间内,而是创建了一个虚拟网络接口对,一端在网络名称空间中,一端在根中。然后,通过此虚拟网络将程序包从名称空间路由到根名称空间,然后再路由到物理接口。-这样,我就能运行所有普通的数据传输,并启动只能访问特定接口的进程。

# 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}}

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

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish

4
做得好!我认为您还可以创建桥接设备,并将默认名称空间和虚拟对与物理设备之一桥接。虽然这看起来是等效的。
Graeme

1
我确实尝试过桥接虚拟和物理设备。使用该解决方案我无法访问外部网络。
Skeen 2015年

2
我这样做了,但是只能从新的命名空间中进行。我认为我遇到的问题与网络经理有关,但是我没有弄清楚,否则我会更新我的答案。
Graeme 2015年

我有同样的问题,但是我无法使用该解决方案。在最后一步中,我应该在{{ROUTE_SOURCE}}和{{ROUTE_TARGET}}中输入什么?
litov '16

@Graeme,至少在Ubuntu上,我可以通过在此处发出dhclient <bridge>per 重新获得名称空间和全局名称空间的连接。
克里斯·亨特

3

解决方案一:预加载特定的库

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

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

  • 强制绑定:具有很多功能,但绑定泄漏(不可靠)

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

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

解决方案二:Linux用户空间

  • 经典的Linux用户空间ip-netns:很好的解决方案,但要求root和interface只能存在于一个用户空间中

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

  • 使用netns的Firejail:Firejail可以强制应用程序使用单独创建的特定用户空间,这使我们无需使用root即可命名空间firejail --dns=8.8.8.8 --noprofile --netns=nameOfyourNS app-command

  • 带有伪装和桥接的 Firejail:Firejail可以强制应用程序使用带有iptables伪装特定接口,这很棒,不需要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

如何使用App-Route-Jail

  • 建立应用程序路线监狱
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Utils
chown 755 make.sh
./make.sh
  • 在此示例中,为将来标记的数据包添加了一条路由(用于入狱的应用程序)192.168.1.1用作强制网关,此路由规则不会影响其他应用程序,例如,如果您想在系统启动时仅执行一次此操作每天使用此解决方案
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
  • 启动您要入狱的应用程序
MARK=10 LD_PRELOAD=./mark.so firefox
  • 测试WAN IP地址
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me
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.