Подтвердить что ты не робот

Может ли Python выбрать сетевой адаптер при открытии сокета?

На целевой машине, на которой запущено приложение python, будут доступны три сетевых интерфейса. В целом все три сети будут значительно отличаться, однако есть вероятность, что две из трех могут быть в подобных сетях.

В приведенном ниже примере я не контролирую адрес назначения на ETH 2 (так как это предварительно сконфигурированная система), поэтому я вынужден выбирать, какой адаптер использовать программно.

Я уверен, что это будет связано с тем, как ОС работает с маршрутизацией соединений. Я надеюсь, что для решения этой проблемы будет использоваться независимый от платформы способ использования python, так как есть вероятность, что это приложение нужно будет запускать на Windows 7, а также на машине Linux.

Пример кода

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

Обычный случай

  • ETH 0 Источник: 192.168.0.1
  • ETH 0 Назначение: 192.168.0.2
  • ETH 1 Источник: 10.20.30.1
  • ETH 1 Пункт назначения: 10.20.30.2
  • ETH 2 Источник: 60.50.40.1
  • ETH 2 Пункт назначения: 60.50.40.1

Возможный случай неисправности

  • ETH 0 Источник: 192.168.0.1
  • ETH 0 Назначение: 192.168.0.2
  • ETH 1 Источник: 10.20.30.1
  • ETH 1 Пункт назначения: 10.20.30.2
  • ETH 2 Источник: 192.168.0.3
  • ETH 2 Назначение: 192.168.0.2

Дополнительная информация
Адаптеры ETH0,1 и 2 подключены к различным физическим сетям

4b9b3361

Ответ 1

В Windows, если вы знаете IP-адрес интерфейса, который хотите использовать, просто привязывайтесь к нему перед подключением. В Linux используйте опцию сокета SO_BINDTODEVICE, как было предложено JimB (похоже, это тоже привилегированный вызов).

то есть. на Windows

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

Адрес источника привязки в Windows, выбирает интерфейс с тем же IP-адресом, что и это устройство, даже если этот IP-адрес имеет более высокую стоимость маршрутизации. Это не работает в Linux, хотя, поскольку он всегда перезаписывает адрес источника с IP-адресом выбранного устройства. Маршрутизация выполняется исключительно на целевом адресе. Единственное исключение - если вы укажете адрес источника 127.0.0.1, тогда Linux не позволит этим пакетам выйти из этого поля.

Ответ 2

Я не могу много говорить о Windows, но в Linux интерфейс обычно не выбирается до тех пор, пока не будет принято решение о маршрутизации, поэтому вы, как правило, не можете сказать, на каком интерфейсе уходят ваши пакеты.

Однако у вас есть опция использования SO_BINDTODEVICE (см. man 7 socket) в Linux. Это связывает сокет с устройством, однако только root может установить этот параметр в сокете.


Только что проверено, и в библиотеке сокетов python не указано SO_BINDTODEVICE, но вы получите его из 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')

См. также:

Ответ 3

SO_BINDTODEVICE звучит разумно, но обычно вы косвенным образом выбираете устройство по тому IP-адресу, к которому вы привязываетесь. Чаще всего вы просто привязываетесь к '', чтобы привязываться ко всему адресу машины.