Dirige el tráfico a través de una interfaz específica para un proceso en Linux


20

¿Es posible enrutar el tráfico utilizado por un proceso a través de una interfaz específica?

Por ejemplo, el tráfico de red por aplicación de descarga siempre debe usar la interfaz, wlan0mientras que todas las demás aplicaciones en la máquina deben usar eth0.

¿Es posible tener este tipo de regla en Linux?

Respuestas:


22

Se puede hacer usando espacios de nombres de red de Linux.

Aquí hay un artículo que explica cómo. Básicamente, crea un espacio de nombres de red con una ruta predeterminada diferente y ejecuta los procesos que lo necesitan allí. Conecta el espacio de nombres de red recién creado al adaptador físico con un puente (pero otras soluciones son posibles, por supuesto).

Actualización: desde el kernel 3.14 es aún más fácil usar grupos de control, como se describe en este artículo . Tienes que:

1) defina un grupo de control net_cls para anotar los paquetes de un proceso determinado con un classid (o grupo de proceso, tenga en cuenta que no debe haber ninguna relación padre-hijo entre ellos)

2) use el módulo iptables cgroup (agregado en Linux 3.14) para marcar los paquetes

3) utilice el enrutamiento de políticas (ip rule add fwmark ....) para crear una nueva tabla de enrutamiento para los paquetes marcados

La ventaja es que no tenemos que hacer el puente y todo es mucho más dinámico gracias a cgroups.


14

He luchado muchísimo con esto, así que aquí hay una solución COMPLETA. Se probó en Ubuntu 15 y 16. Puede usarlo especialmente con OpenVPN para enrutar ciertas aplicaciones fuera de la interfaz del túnel VPN.

La solución completa "cgroup"

¿Cómo funciona eso?

  • El kernel de Linux colocará la aplicación en un grupo de control . El tráfico de red de las aplicaciones en este cgroup se identificará por su ID de clase en el nivel del controlador de red.
  • iptables marcará este tráfico y lo obligará a salir con la IP correcta
  • ip route procesará el tráfico marcado en una tabla de enrutamiento diferente, con una ruta predeterminada a la IP de la puerta de enlace que desee.

Script automatizado

He creado un script novpn.sh para automatizar las dependencias de instalación y ejecución. Probado en Ubuntu.

Comience su VPN primero.

wget https://gist.githubusercontent.com/kriswebdev/a8d291936fe4299fb17d3744497b1170/raw/cf8b37fbe6c3f50a0be825eb77cafa3e0134946f/novpn.sh
# If you don't use eth0, edit the script setting.
sudo chmod +x novpn.sh
./novpn.sh traceroute www.google.com
./novpn.sh --help

Manual de instrucciones

Primero, instale el soporte y las herramientas de cgroup:

sudo apt-get install cgroup-lite cgmanager cgroup-tools

Reiniciar (puede no ser necesario).

Necesita iptables 1.6 .0+. Obtenga la fuente de lanzamiento de iptables 1.6.0 , extráigala, luego ejecute esto (el --disable-nftablesindicador evitará errores) desde el directorio de origen de iptables:

sudo apt-get install dh-autoreconf bison flex
./configure --prefix=/usr      \
            --sbindir=/sbin    \
            --disable-nftables \
            --enable-libipq    \
            --with-xtlibdir=/lib/xtables
make
sudo make install
iptables --version

Ahora, la configuración real. Defina un grupo de control llamado novpn. Los procesos en este cgroup tendrán un classid de 0x00110011(11:11).

sudo su
mkdir /sys/fs/cgroup/net_cls/novpn
cd /sys/fs/cgroup/net_cls/novpn
echo 0x00110011 > net_cls.classid

Ahora, supondremos que la interfaz que desea utilizar para la aplicación específica es eth0con una puerta de enlace IP de 10.0.0.1. Reemplácelos por lo que realmente desea (obtenga la información de ip route). Ejecutar todavía como root:

# Add mark 11 on packets of classid 0x00110011
iptables -t mangle -A OUTPUT -m cgroup --cgroup 0x00110011 -j MARK --set-mark 11

# Force the packets to exit through eth0 with NAT
iptables -t nat -A POSTROUTING -m cgroup --cgroup 0x00110011 -o eth0 -j MASQUERADE

# Define a new "novpn" routing table
# DO THIS JUST ONCE !
echo 11 novpn >> /etc/iproute2/rt_tables

# Packets with mark 11 will use novpn
ip rule add fwmark 11 table novpn

# Novpn has a default gateway to the interface you want to use
ip route add default via 10.0.0.1 table novpn

# Unset reverse path filtering for all interfaces, or at least for "eth0" and "all"
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done

Finalmente, ejecute su aplicación en la interfaz específica:

exit
sudo cgcreate -t $USER:$USER -a $USER:$USER -g net_cls:novpn
cgexec -g net_cls:novpn traceroute www.google.com
# Close all Firefox windows first
cgexec -g net_cls:novpn firefox

O si desea mover un proceso que ya se está ejecutando al cgroup, bueno ... ¡no puede! Eso parece deberse a la función NAT (mascarada): iptables -nvL -t natno coincide cuando se cambia el cgroup, pero iptables -nvL -t manglesí coincide.

# Get PID of the process (we'll then suppose it's 1234)
pidof firefox
# Add to cgroup - THIS DOESN'T WORK! Silently fails to produce the final result.
sudo echo 1234 > /sys/fs/cgroup/net_cls/novpn/tasks
# Remove - but this works...
sudo echo 1234 > /sys/fs/cgroup/net_cls

Créditos: ninguna respuesta funcionó como se esperaba, pero una combinación de ellos funcionó: chripell answer artículo evolware Por enrutamiento de proceso, toma 2: usando cgroups, iptables y enrutamiento de políticas , ¿Cómo hago que un proceso específico NO atraviese una conexión OpenVPN? , Kill Switch para OpenVPN sobre la base de iptables


Gracias por la gran respuesta, ¿cómo hago que funcione con apache? ¡Intenté cgexec -g net_cls:novpn apache2y me di una lista completa de erros indefinidos variables!
razzak

2
Obtendrá los mismos errores al ejecutar apache2directamente desde la terminal. Eso es porque apache2normalmente se lanza como un servicio, con systemctl start apache2. Sin embargo, eso no funcionará cgexec. El programa llamado debe ser padre del apache2proceso deseado ( ) para que net_cls cgroup se propague. Entonces necesitas encontrar el script de lanzamiento. En este caso, es sudo cgexec -g net_cls:novpn /usr/sbin/apache2ctl start. Consulte con ./novpn.sh --list.
KrisWebDev

¡Ya no funciona en ubuntu 16.04!
razzak

2
Lo estoy usando en Ubuntu 16.04 y está funcionando bien. Los nombres de la interfaz han cambiado en Ubuntu 16, puede reemplazar la necesidad de reemplazar eth0por algo como enp7s0. Obtenga la información del ifconfigcomando.
KrisWebDev

Gracias. Pero no funciona en Ubuntu 18.04 porque cpmanager se ha eliminado debido a un conflicto con systemd
skonsoft


3

Combinando las excelentes respuestas de mariusmatutiae y KrisWebDev, he creado una versión ampliamente modificada del excelente novpn.shscript de KrisWebDev . Mientras que el script de KrisWebDev está diseñado para rascar una picazón más específica (ejecutar y mover procesos dentro / fuera de una VPN), mi versión le permite ejecutar básicamente cualquier comando en un entorno de red que especifique. Puede especificar la interfaz a la que se unirá, la ruta predeterminada, especificar sus propias reglas de iptables, rutas estáticas, especificar una "prueba" para confirmar que todo funciona como lo desea antes de ejecutar el comando ... etc. Le permite usar múltiples archivos de configuración para que pueda definir cualquier cantidad de entornos de red específicos en los que pueda ejecutar comandos / procesos.

Lo publiqué aquí: https://gist.github.com/level323/54a921216f0baaa163127d960bfebbf0

¡Incluso puede limpiar las tablas cgroup / iptables / routing después!

Comentarios bienvenidos.

PD: está diseñado para Debian 8 (Jessie)


Hola @allnatural, me gustaría usar tu script altnetworking.sh, pero ¿qué se supone que debo poner en el archivo de configuración?
Cris70

0

No por aplicación, no. Puede hacerlo por puerto o por dirección IP, etc., o una aplicación en sí misma puede unirse (y usar) una tarjeta de red específica.

Sin embargo, no puede configurar una regla para hacerlo.


Tengo una aplicación Java, ¿es posible vincular esa aplicación a una interfaz?
Suresh

¿Una aplicación Java para la que tiene el código fuente y puede reprogramar las partes internas?
Majenko

Tengo un código fuente de la aplicación java que usa la biblioteca apache http.
Suresh

Luego me dirijo a stackoverflow.com y pregunto a los programadores allí cómo cambiar su programa. Nunca he programado en Java.
Majenko
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.