web-dev-qa-db-ja.com

Pythonソケットを開くときにどのネットワークアダプタを選択できますか?

pythonアプリケーションを実行しているターゲットマシンでは、3つのネットワークインターフェイスを使用できます。通常、3つのネットワークはすべて大きく異なりますが、3つのうち2つが同様のネットワーク上にある可能性があります。 。

以下の例では、ETH 2の宛先アドレスを制御できないため(事前構成されたシステムであるため)、プログラムで使用するアダプターを選択する必要がありました。

これは、OSが接続のルーティングでどのように機能するかに当てはまると確信しています。このアプリケーションはLinuxマシンだけでなくWindows7でも実行する必要がある可能性があるため、Pythonを使用して問題を解決するプラットフォームに依存しない方法があることを願っています。

サンプルコード

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はすべて異なる物理ネットワークに接続されています

19
Adam Lewis

Windowsでは、使用するインターフェイスのIPアドレスがわかっている場合は、接続する前にそれにバインドするだけです。 Linuxでは、JimBが提案するソケットオプションSO_BINDTODEVICEを使用します(特権呼び出しでもあるようです)。

つまり、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はこれらのパケットがそのボックスから出て行くのを防ぎます。

14
Lloyd Macrohon

Windowsについてはあまり話せませんが、Linuxでは通常、ルーティングの決定が行われるまでインターフェイスは選択されないため、通常、パケットがどのインターフェイスを離れるかについてはわかりません。

ただし、LinuxでSO_BINDTODEVICEman 7 socketを参照)を使用するオプションがあります。これにより、ソケットがデバイスにバインドされますが、このオプションをソケットに設定できるのは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')

参照:

19
JimB