Enlace un programa de Unix a una interfaz de red específica

40

Pregunta: ¿Cómo inicio un programa mientras me aseguro de que su acceso a la red esté vinculado a través de una interfaz de red específica?

Caso: quiero acceder a dos máquinas distintas con la misma IP (192.168.1.1), pero accesible a través de dos interfaces de red diferentes (eth1 y eth2).

Ejemplo:

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

Lo anterior es una aproximación de lo que me gustaría, inspirado en el enlace de hardware realizado a través de primusrun y optirun .

Desafío: como se sugiere en un hilo relacionado , las interfaces utilizadas no son elegidas por el programa, sino por el núcleo (de ahí la sintaxis previa al enlace en el ejemplo anterior).

He encontrado algunas soluciones relacionadas, que no son satisfactorias. Se basan en interfaces de red vinculantes a través de listas negras de red específicas del usuario; es decir, ejecutar el proceso como un usuario que solo puede acceder a una única interfaz de red específica.

Skeen
fuente
¿Está insinuando que su máquina está conectada a dos redes diferentes, ambas 192.168.1.0? ¿Cómo es tu tabla de enrutamiento? Si desea restringir las interfaces visibles desde un proceso, la solución más ligera sería cgroups, un contenedor más pesado.
lgeorget
Sí, dos redes diferentes, ambas en el mismo rango de IP. No estoy seguro de querer restringir las interfaces visibles, ¿solo dictar cuál usar como predeterminado? :)
Skeen
3
Lo que pides es difícil por una buena razón: tener dos redes interconectadas usando el mismo dominio IP es como tener un ascensor en un edificio de dos pisos con el mismo número. El rango de IP es lo que identifica el dominio, no la interfaz de salida. Sin embargo, debe haber una manera de evitar el diseño defectuoso de su red con iptables.
lgeorget
Estoy conectando mi sistema a dos infraestructuras diferentes en el lugar, como tal, las infraestructuras nunca fueron diseñadas para interactuar, y por lo tanto el diseño de la red es defectuoso en ese sentido.
Skeen
1
Mi argumento hacia los NAT era que los espacios de direcciones enteros generalmente están ocultos detrás del NAT, y cuando conecto dos infraestructuras con NAT, se produce la colisión. - No estoy en posición de modificar la infraestructura. - Intenté usar espacios de nombres de red con pares de interfaces de red virtuales (uno en el espacio de nombres, uno en el espacio de nombres raíz) conectando el espacio de nombres raíz uno a la interfaz física y ejecutando programas dentro del espacio de nombres de red. - Esto parece estar funcionando, pero no obtengo acceso más allá del espacio de nombres raíz (es decir, no hay acceso fuera de la máquina).
Skeen

Respuestas:

35

Para Linux, esto ya se ha respondido en Superusuario: ¿cómo usar diferentes interfaces de red para diferentes procesos? .

La respuesta más popular utiliza un LD_PRELOADtruco para cambiar el enlace de red para un programa, pero los núcleos modernos admiten una característica mucho más flexible llamada 'espacios de nombres de red' que se expone a través del ipprograma. Esta respuesta muestra cómo usar esto. De mis propios experimentos he hecho lo siguiente (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

También es posible administrar espacios de nombres de red hasta cierto punto con los comandos unsharey nsenter. Esto le permite también crear espacios separados para PID, usuarios y puntos de montaje. Para más información ver:

Graeme
fuente
"después de este punto, eth0 no puede ser utilizado por programas fuera del espacio de nombres" - ¿Entonces estoy desconectando la conexión para todos los demás problemas al hacer esto?
Skeen
1
@Skeen, sí, así que presumiblemente empujaría una interfaz que ningún otro programa está usando en el espacio de nombres y usará la principal normalmente.
Graeme
1
@Graerne; Ambas interfaces se están utilizando activamente; No puedo permitirme quitar las interfaces.
Skeen
¿Y qué pasa con la puerta de enlace predeterminada? wvdialpor ejemplo, no parece configurarlo en absoluto ... por lo que debe definirse en el propio espacio de nombres
Flash Thunder
¿Podría incluir instrucciones sobre cómo deshacer eso? ¿Simplemente vuelves ip netns remove test_nsa la normalidad? ¿O tienes que hacer algo especial?
Multihunter
17

Estoy aceptando la respuesta de Graeme; Esto es simplemente un seguimiento para explicar los cambios que hice a su sugerencia para resolver mi problema.

En lugar de vincular la interfaz física dentro del espacio de nombres, creé un par de interfaces de red virtual, con un extremo en el espacio de nombres de red y otro en la raíz. Los paquetes se enrutan a través de esta red virtual desde el espacio de nombres, al espacio de nombres raíz y luego a la interfaz física. - Como tal, puedo ejecutar todas mis transferencias de datos normales y, además, iniciar procesos que solo pueden acceder a una interfaz 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_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}}

Una vez que las interfaces se han configurado para eth0 y eth1, con sus respectivos espacios de nombres eth0_ns y eth1_ns, los programas se pueden ejecutar en la interfaz especificada a través de;

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish
Skeen
fuente
44
¡Bien hecho! Creo que también puede crear un dispositivo puente y unir el espacio de nombres predeterminado y el par virtual con uno de los dispositivos físicos. Sin embargo, esto parece equivalente.
Graeme
1
Intenté unir el dispositivo virtual y físico; No pude llegar a la red externa utilizando esa solución.
Skeen
2
Lo hice, pero solo desde el nuevo espacio de nombres. Creo que el problema que tenía estaba relacionado con el administrador de red, aunque no lo resolví o habría actualizado mi respuesta.
Graeme
Tengo el mismo problema, pero no pude usar esa solución. ¿Qué debo ingresar exactamente en {{ROUTE_SOURCE}} y {{ROUTE_TARGET}} en el último paso?
litov
@Graeme, al menos en Ubuntu pude recuperar la conectividad tanto en el espacio de nombres como en el espacio de nombres global emitiendo dhclient <bridge>por aquí .
Chris Hunt
4

Solución I: precargando una biblioteca específica

  • App-Route-Jail : use ld_preload para forzar la puerta de enlace de la interfaz (gran idea pero requiere capacidades de root o marcas) el uso se detalla en las notas a continuación

  • Proxybound : use ld_preload para forzar un proxy a una aplicación específica (esto es usar proxy en lugar de interfaz)

  • Force-Bind : tiene muchas características, pero el enlace tiene fugas (no confiable)

  • Bind-Interface-IP : conexiones demasiado simples y con fugas (no confiable)

  • Bind-IP : conexiones demasiado simples y con fugas (no confiable)

Solución II: espacio de usuario de Linux

  • Espacio de usuario clásico de Linux ip-netns : gran solución, pero requiere root e interfaz solo puede existir en un solo espacio de usuario

  • Firejail : Firejail puede obligar a una aplicación a usar una red específica, pero la compatibilidad es limitada (por ejemplo, no es compatible con las interfaces tun). firejail no requiere rootfirejail --dns=8.8.8.8 --noprofile --net=eth0 --ip=192.168.1.1 app-command

  • Firejail con netns : Firejail puede obligar a una aplicación a usar un espacio de usuario específico que se creó por separado, esto nos permite nombrar espacios sin rootfirejail --dns=8.8.8.8 --noprofile --netns=nameOfyourNS app-command

  • Firejail con mascarada y puente : Firejail puede obligar a una aplicación a usar una interfaz específica con iptables masquerade , esto es genial y no requiere root pero requiere ip_forward y podría implicar un impacto en la seguridadfirejail --net=br0 firefox

Solución III: iptables de Linux

Iptables podrían usarse para este propósito, pero esto requiere ip_forward y podría implicar un impacto en la seguridad si no está configurado correctamente, ejemplo 1 , ejemplo 2 , ejemplo 3 , ejemplo 4

Notas de soluciones (I, II y III):

Wireguard

Si está utilizando una VPN (especialmente Wireguard) y desea aplicar esta solución a una interfaz Wireguard ( Wireguard con espacio de usuario ), puede seguir las instrucciones vinculadas para crear un espacio de usuario que contenga una interfaz wg (y por lo tanto limitado a una interfaz vpn ) también se puede combinar firejail --netns=containerpara poder usar el espacio de usuario sin root.

Cómo encontrar la puerta de enlace de la interfaz

Hay muchas soluciones para encontrar la puerta de enlace, aquí hay algunos comandos que permiten encontrar la puerta de enlace utilizada

$ 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

Cómo usar App-Route-Jail

  • Construir App-Route-Jail
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Utils
chown 755 make.sh
./make.sh
  • Agregar una ruta para los futuros paquetes marcados (para la aplicación encarcelada) en este ejemplo 192.168.1.1se usa como puerta de enlace forzada, esta regla de ruta no afectará a otras aplicaciones, esta manipulación debe hacerse solo una vez en el arranque del sistema, por ejemplo, si desea usa esta solución diariamente
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
  • Inicie la aplicación que desea encarcelar
MARK=10 LD_PRELOAD=./mark.so firefox
  • Probar la dirección IP wan
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me
intika
fuente