ver tarjeta por interfaz interfaces consola configurar comandos activar linux sockets

tarjeta - Linux: ¿Cómo forzar el uso de una interfaz de red específica?



ver interfaces de red linux (4)

Esto podría considerarse una continuación de esta primera pregunta SO .

Idealmente, me gustaría encarcelar un proceso para que solo use una determinada interfaz, pase lo que pase. Hará conexiones TCP, enviará datagramas UDP y escuchará las transmisiones UDP. Actualmente, lo que estoy haciendo es:

  1. Determine la IP de la interfaz a usar.
  2. Cree una regla de política de IP para enrutar todos los paquetes provenientes de la interfaz a esa IP
  3. Cree otra regla de política de IP para enrutar todos los paquetes que provienen de esa IP a esa interfaz
  4. Configure una tabla de enrutamiento predeterminada para cada regla

Ahora, esto funciona, principalmente, pero el proceso del cliente también debe estar dispuesto a seguir el juego. Es decir, debe vincularse a la dirección IP específica de la interfaz que desea utilizar, y creo que también debo configurar SO_BINDTODEVICE . (Sin embargo, sigo leyendo información conflictiva sobre si SO_BINDTODEVICE realmente funciona cuando uso TCP o UDP.) Afortunadamente, la aplicación cliente es Python, y puedo extender la clase socket para hacer todo esto de forma transparente. Pero no estoy seguro de que sea una solución completa, especialmente con respecto a la recepción de transmisiones.

Mis preguntas son:

  1. ¿ SO_BINDTODEVICE hace lo que quiero aquí? ¿O solo es efectivo para tomas sin procesar? Alguien comentó que, " SO_BINDTODEVICE en un socket no garantiza que el socket solo recibirá los paquetes que llegaron a la antena / cable de esa interfaz física". Si esto es cierto, ¿qué hace SO_BINDTODEVICE ?

  2. ¿Hay alguna manera de hacer esto para que la IP local no tenga que ser única? Esto no sería un problema más que el hecho de que el servidor DHCP en una interfaz puede asignarle una IP que está siendo utilizada por otra interfaz, confundiendo así la tabla de enrutamiento.

  3. ¿Cómo recibo transmisiones solo desde una interfaz específica? La vinculación a una IP específica parece hacer que ignore las transmisiones, lo que tiene sentido, pero no es exactamente lo que estoy buscando.

Me estoy ejecutando en Ubuntu 8.04 con Linux kernel 2.6.26. Ser capaz de acceder a la misma subred en dos redes diferentes a través de dos interfaces diferentes simultáneamente es un requisito no negociable, por lo que es (en su mayoría) inmune a "no hacer eso". :)


En cuanto a mi pregunta general, parece haber algunas formas de hacerlo:

  • La forma complicada que implica la tabla de enrutamiento cambia y la cooperación de cada proceso. Esta es la forma que describí arriba. Una de sus ventajas es que funciona desde el espacio de usuario. He agregado algunas notas adicionales y he respondido a mis preguntas específicas a continuación.

  • Escriba un modelo de kernel personalizado que ignore completamente la tabla de enrutamiento, si está configurado SO_BINDTODEVICE . Sin embargo, aún es necesario que el proceso del cliente llame a setsockopt(SOL_SOCKET, SO_BINDTODEVICE, dev) . Esta opción definitivamente no es para los débiles de corazón.

  • Virtualiza el proceso. Esto probablemente no sea apropiado para mucha gente, y traerá dolores de cabeza propios, principalmente con la configuración. Pero vale la pena mencionarlo.

Las opciones 1 y 2 requieren procesos para habilitar el trabajo como nos gustaría. Esto puede aliviarse parcialmente creando una biblioteca dinámica que secuestra la llamada de socket () para crear el socket y luego vincularlo inmediatamente al dispositivo antes de devolver el descriptor. Esto se describe con más detalle aquí .

Después de investigar un poco y buscar en Google, puedo sacar algunas conclusiones sobre cómo se comporta el kernel de Linux 2.6.26. Tenga en cuenta que estos son probablemente todos los comportamientos específicos de la implementación, y quizás incluso específicos del kernel. Pruebe su propia plataforma antes de decidir implementar funciones basadas en mi único punto de datos.

  1. SO_BINDTODEVICE hace lo que dice, al menos para UDP.

  2. Las direcciones IP únicas para cada interfaz parecen ser necesarias, ya que estamos utilizando las tablas de enrutamiento. Un módulo kernel personalizado podría eludir esta restricción.

  3. Para recibir transmisiones en una interfaz específica, SO_BINDTODEVICE primero al dispositivo usando SO_BINDTODEVICE , y luego vincule a la dirección de difusión con la llamada bind () usual. El enlace del dispositivo debe hacerse antes que cualquier otra cosa. Entonces, el socket recibirá solo las transmisiones que lleguen a esa interfaz.

Lo probé creando primero un socket. Luego lo setsockopt(SOL_SOCKET, SO_BINDTODEVICE, dev) a una interfaz específica usando setsockopt(SOL_SOCKET, SO_BINDTODEVICE, dev) . Finalmente, lo vinculé a la dirección de difusión. Desde otra computadora, envié una transmisión que se recibiría a través de una interfaz no vinculada. El socket de dispositivo no recibió esta transmisión, lo que tiene sentido. Elimine la setsockopt(SOL_SOCKET, SO_BINDTODEVICE, dev) y se recibirá la transmisión.

También se debe mencionar que puede usar setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) aquí también. Tenga en cuenta que la semántica de SO_REUSEADDR cambia con las direcciones de difusión. Específicamente, es legal tener dos sockets vinculados a la dirección de difusión y el mismo puerto en la misma máquina si ambos tienen configurado SO_REUSEADDR .

ACTUALIZACIÓN: SO_BINDTODEVICE con transmisiones parece estar lleno de peligros, específicamente, la recepción de tramas de difusión. Estaba observando tramas de transmisión recibidas en una interfaz, pero desapareciendo en la otra al mismo tiempo. Parece que se ven afectados por la tabla de enrutamiento local, pero son inmunes a las reglas de la política de IP. Sin embargo, no estoy 100% seguro de esto y solo lo menciono como un punto de investigación si desea continuarlo. Todo esto para decir: use bajo su propio riesgo. En aras del tiempo, abrí un conector en bruto en la interfaz y analicé los encabezados Ethernet e IP yo mismo.


No es una respuesta directa a su pregunta, sino solo un FYI. Como mencionó anteriormente, esta solución puede ser demasiado trabajo para lo que necesita / desea hacer.

Personalmente, me gusta la idea de crear un módulo kernel de enganche de red que me permita hacer esto. De esta forma, tengo control total sobre los marcos de multidifusión y de transmisión unitaria que van y vienen del espacio de usuario. Tendría que usar algo como los sockets netlink para enviar / recibir datos hacia y desde su controlador y aplicación de espacio de usuario, pero funciona muy bien y es muy rápido.

También puede conectarse a cualquier nivel de la pila de esta manera ... Ethernet o IP. Por lo tanto, tiene control total sobre lo que envía / recibe.

Aquí hay un artículo de ejemplo que habla de engancharse en la pila netfilter.
Nota: este artículo se engancha en la pila de IP y también es antiguo. Sé que las API han cambiado, pero gran parte de este artículo todavía se aplica práctica y teóricamente. Si quisiera enganchar en la capa de puente, usaría un mecanismo similar, pero especifique

BR_LOCAL_IN instead of NF_IP_LOCAL_IN

Nota: Esto es muy similar a abrir un socket sin formato en la interfaz. Tendrás que construir tus cuadros tú mismo.


Después de un fin de semana muy reñido, me complace presentar una solución que aborda casi todo lo que he discutido anteriormente con casi cero problemas.

Hay un sysctl llamado net.ipv4.conf.all.rp_filter que se puede establecer en 0 para deshabilitar la validación de origen:

rp_filter - INTEGER 2 - do source validation by reversed path, as specified in RFC1812 Recommended option for single homed hosts and stub network routers. Could cause troubles for complicated (not loop free) networks running a slow unreliable protocol (sort of RIP), or using static routes. 1 - (DEFAULT) Weaker form of RP filtering: drop all the packets that look as sourced at a directly connected interface, but were input from another interface. 0 - No source validation.

Esto también puede establecerse por interfaz usando / proc / sys / net / ipv4 / conf / <interface> / rp_filter.

Como lo explicó un afiche, hace que el enrutamiento IP sea "menos determinista" en el sentido de que no se garantiza que los paquetes provenientes de una subred siempre salgan por la misma interfaz. En este caso, esto es exactamente lo que se necesita. Haga una investigación adicional para determinar si esto es realmente lo que quiere.

Las transmisiones siguen siendo problemáticas por razones que no entiendo, pero finalmente estoy satisfecho con este tema y espero que ayude a otros.


podría tratar de limitar el espacio de nombres de la red del proceso a una única interfaz. Necesita una compilación kernel con CONFIG_NETNS (la mayoría de los núcleos de las distribuciones modernas) y algún script para hacer la tarea por usted. Configuración de muestra