Vincular programa unix a uma interface de rede específica

27

Pergunta: Como faço para iniciar um programa enquanto garanto que seu acesso à rede esteja vinculado por meio de uma interface de rede específica?

Caso: Eu quero acessar duas máquinas distintas com o mesmo IP (192.168.1.1), mas acessível através de duas interfaces de rede diferentes (eth1 e eth2).

Exemplo:

net-bind -D eth1 -exec {Program 192.168.1.1}
net-bind -D eth2 -exec {Program 192.168.1.1}

O texto acima é uma aproximação do que eu gostaria, inspirado na ligação de hardware feita por primusrun e optirun .

Desafio: Conforme sugerido em a thread relacionado , as interfaces usadas não são escolhidas pelo programa, mas pelo kernel (daí a sintaxe de pré-binding no exemplo acima).

Encontrei algumas soluções relacionadas, que são insatisfatórias. Eles são baseados em interfaces de rede vinculantes por meio de listas negras de rede específicas do usuário; isto é, executando o processo como um usuário que só pode acessar uma única interface de rede específica.

    
por Skeen 20.06.2015 / 13:22

2 respostas

24

Para Linux, isso já foi respondido no Superusuário - Como usar diferentes interfaces de rede para diferentes processos? .

A resposta mais popular usa um truque LD_PRELOAD para alterar a ligação de rede para um programa, mas os kernels modernos suportam um recurso muito mais flexível chamado 'namespaces de rede' que é exposto através do programa ip . Esta resposta mostra como usar isso. De minhas próprias experiências, fiz o seguinte (como 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

Também é possível gerenciar namespaces de rede com os comandos unshare e nsenter . Isso permite também criar espaços separados para PIDs, usuários e pontos de montagem. Para mais informações, consulte:

por 20.06.2015 / 15:16
12

Estou aceitando a resposta de Graeme; isto é simplesmente um acompanhamento para explicar as mudanças que fiz à sua sugestão para resolver o meu problema.

Em vez de vincular a interface física dentro do namespace, criei um par de interface de rede virtual, com uma extremidade no namespace da rede e uma na raiz. Os pacotes são então roteados por meio dessa rede virtual do namespace, para o namespace raiz e depois para a interface física. - Como tal, posso executar todas as minhas transferências de dados comuns e, além disso, iniciar processos que só podem acessar uma interface específica.

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

Uma vez que as interfaces tenham sido configuradas para eth0 e eth1, com seus respectivos namespaces eth0_ns e eth1_ns, os programas podem ser executados na interface especificada via;

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish
    
por 21.06.2015 / 11:34