¿Puede Python seleccionar qué adaptador de red al abrir un socket?

La máquina de destino que ejecuta la aplicación python tendrá tres interfaces de red disponibles. En general, las tres redes serán muy diferentes, sin embargo, existe la posibilidad de que dos de las tres redes estén en redes similares.

En el siguiente ejemplo, no tengo control sobre la dirección de destino en ETH 2 (ya que es un sistema preconfigurado), por lo que me obligué a seleccionar qué adaptador usar de forma programática.

Estoy bastante seguro de que esto dependerá de cómo funciona el sistema operativo al enrutar las conexiones. Mi esperanza es que haya una forma independiente de la plataforma para resolver el problema usando python, porque existe la posibilidad de que esta aplicación necesite ejecutarse en Windows 7 y en una máquina Linux.

Código de ejemplo

import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('192.168.0.2', 8000)) # Which device will this connect to?? 

Caso normal

  • ETH 0 Fuente: 192.168.0.1.
  • ETH 0 Destino: 192.168.0.2
  • ETH 1 Fuente: 10.20.30.1
  • ETH 1 Destino: 10.20.30.2
  • ETH 2 Fuente: 60.50.40.1
  • ETH 2 Destino: 60.50.40.1

Posible caso de problemas

  • ETH 0 Fuente: 192.168.0.1.
  • ETH 0 Destino: 192.168.0.2
  • ETH 1 Fuente: 10.20.30.1
  • ETH 1 Destino: 10.20.30.2
  • ETH 2 Fuente: 192.168.0.3.
  • ETH 2 Destino: 192.168.0.2

Información Adicional
Los adaptadores ETH0,1 y 2 están todos conectados a diferentes redes físicas.

En Windows, si conoce la dirección IP de la interfaz que desea usar, simplemente ajústela antes de conectarse. En Linux, use la opción de socket SO_BINDTODEVICE como lo sugiere JimB (también parece ser una llamada privilegiada).

es decir, en Windows

 import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('192.168.0.1', 0)) s.connect(('...')) 

Al vincular la dirección de origen en Windows, selecciona la interfaz con la misma dirección IP que ese dispositivo, incluso si esa dirección IP tiene un costo métrico de enrutamiento más alto. Sin embargo, esto no funciona en Linux, ya que siempre sobrescribe la dirección de origen con la dirección IP del dispositivo seleccionado. El enrutamiento se realiza basándose únicamente en la dirección de destino. La única excepción que parece es que si establece la dirección de origen en 127.0.0.1, entonces Linux evita que estos paquetes salgan de esa caja.

No puedo hablar mucho de Windows, pero en Linux la interfaz normalmente no se elige hasta que se toma una decisión de enrutamiento, por lo tanto, por lo general, no tiene nada que decir sobre qué interfaz dejan sus paquetes.

Sin embargo, tiene la opción de usar SO_BINDTODEVICE (ver man 7 socket ) en Linux. Esto une un socket a un dispositivo, sin embargo, solo la raíz puede establecer esta opción en un socket.


Se acaba de SO_BINDTODEVICE y la biblioteca de socket de python no tiene SO_BINDTODEVICE definido, pero lo obtiene de socket.h :

 # from socket.h # define SO_BINDTODEVICE 25 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, 25, 'eth0') 

Ver también:

  • Linux: ¿Cómo fuerzo el uso de una interfaz de red específica?
  • ¿Cómo hago un socket saliente a una interfaz de red ESPECÍFICA?

SO_BINDTODEVICE suena razonable, pero normalmente seleccionará indirectamente un dispositivo por la dirección IP a la que se enlaza. Más a menudo que eso, simplemente se unirá a ”, para enlazar a todas las direcciones de la máquina.