ver - Usando Linux, cómo especificar qué datos de la interfaz de ethernet se transmiten
ver interfaces de red linux (1)
Estoy trabajando en un sistema de servidor basado en Linux en el que hay dos interfaces de red, ambas en la misma subred (por ahora, digamos que son 172.17.32.10
y 172.17.32.11
). Cuando envío datos a un host en la red, me gustaría especificar en qué interfaz de mi servidor se transmiten los datos. Necesito poder cambiar de una interfaz a otra (o incluso transmitir en ambas) en el software (las reglas de enrutamiento estático no funcionarán para esta aplicación).
Encontré una pregunta relacionada en StackOverflow que sugería usar la biblioteca de netlink para modificar rutas sobre la marcha. Intuitivamente, parece que debería funcionar, pero me preguntaba si había otras opciones para lograr el mismo resultado.
Sin intención de ofender, pero la respuesta sobre el uso de bind () es bastante incorrecta. bind () controlará la dirección IP de origen ubicada dentro del encabezado IP del paquete. No controla qué interfaz se utilizará para enviar el paquete: se consultará la tabla de enrutamiento del kernel para determinar qué interfaz tiene el costo más bajo para llegar a un destino particular. (*ver nota)
En su lugar, debe usar SO_BINDTODEVICE
sockopt. Esto hace dos cosas:
- Los paquetes siempre saldrán de la interfaz que especificó, independientemente de lo que indiquen las tablas de enrutamiento del kernel.
- Solo los paquetes que lleguen a la interfaz especificada se entregarán al socket. Los paquetes que llegan a otras interfaces no lo harán.
Si tiene múltiples interfaces que quiere cambiar, le sugiero que cree un socket por interfaz. Como también solo recibirá paquetes en la interfaz a la que se ha vinculado, deberá agregar todos estos sockets a su select()
/ poll()
/ lo que sea que use.
#include <net/if.h>
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name));
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
(void *)&ifr, sizeof(ifr)) < 0) {
perror("SO_BINDTODEVICE failed");
}
(* nota) Bind()
a una dirección IP de interfaz puede conducir a un comportamiento confuso pero no obstante correcto. Por ejemplo, si bind()
a la dirección IP para eth1, pero la tabla de enrutamiento envía el paquete eth0, entonces aparecerá un paquete en el cable eth0 pero con la dirección IP de origen de la interfaz eth1. Esto es extraño, pero permitido, aunque los paquetes devueltos a la dirección IP eth1 se redirigirían a eth1. Puede probar esto usando un sistema Linux con dos interfaces de IP. Tengo uno, y lo probé, y bind()
no es efectivo para sacar el paquete de una interfaz física.
Aunque técnicamente permitido, dependiendo de la topología, esto puede no funcionar. Para amortiguar los ataques de denegación distribuida de servicio donde los atacantes usan direcciones fuente IP falsificadas, muchos enrutadores ahora realizan comprobaciones de reenvío de ruta inversa (RPF). Los paquetes con una dirección IP de origen en la ruta "incorrecta" se pueden descartar.