Can Python Select What Network Adapter When Opening a Socket

Can Python select what network adapter when opening a socket?

On Windows, if you know the IP address of the interface you want to use, just bind to that before you connect. On Linux,use socket option SO_BINDTODEVICE as suggested by JimB (seems to be a privileged call too).

i.e. on Windows

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

Binding source address under Windows, selects the interface with the same IP address as that device, even if that IP address has a higher routing metric cost. This doesn't work under Linux though, as it always overwrites the source address with the IP address of the selected device. Routing is done based solely on the destination address. The only exception it seems is if you set source address to 127.0.0.1, then Linux prevents these packets from going out of that box.

Is it possible to choose specific network interface to transmit data in Python?

If we're talking about tcp/udp, then (like in any other langauge) the socket interface allows you to bind a specific ip address to it, so you do that by binding the interface's address.

People have the misconception that binding is only for listening on a socket, but this is also true for connecting, and its just that in normal usage the binding is chosen for you.
Try this:

import socket
s = socket.socket()
s.bind(('192.168.1.111', 0))
s.connect(('www.google.com', 80))

Here we use the ip from interface eth0 (mine is 192.168.1.111) with a system-chosen source port to connect to google's web server. (You can also choose the source port if you want by replacing the 0)

EDIT:
To get the IP address that is used for a specific interface you can use this recipe (linux only) - http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/

(if you have multiple IPs on the same interface I'm not sure that it'll work. I assume it will return one of them)

How to select a network interface for multicasting with python

Tested working with Python 2.7 in Linux Debian 8 and Windows 10.

For Linux:

def get_local_wireless_ip_linux():
import fcntl
import struct
import socket
ifname = 'wlan0'
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
wlan0_ip = (socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24]))
return wlan0_ip

and for Windows:

def get_local_wireless_ip_windows():
import subprocess
arp = subprocess.check_output('arp -a')
local_ipv4 = []
for line in arp.split('\n'):
if 'Interface' in line:
local_ipv4.append(line.split(':')[1].split('---')[0].strip())
return local_ipv4[-1]

How do I make an outgoing socket to a SPECIFIC network interface?

You can certainly bind a socket to a specific device.

I don't know how to do it in python, but using the berkeley socket api (in C) you need to call setsockopt(), using the option SO_BINDTODEVICE.

You pass in an interface descriptor, which is of type struct ifreq. Ideally you would get the contents of the interface descriptor by using ioctl(), and requesting SIOCGIFINDEX - passing the name of the interface (eg. eth0) as an argument.


edit: Just did a quick search and found this documentation of the socket methods in python. setsockopt() is amongst them.

How does a socket know which network interface controller to use?

I dont know why im included in the edit suggestion when i was not even related to this question .I got similar edit suggestion before as well..might be some bug/issue.

(If you feel inclined to up-vote, @Shtééf's answer deserves it more than mine.)

That depends on whether you are connecting or binding.

If you bind, you can bind to a specific IP address corresponding to one of the machine's interfaces, or you can bind to 0.0.0.0, in which case the socket will listen on all interfaces.

If you connect an unbound socket, then the machine's routing tables, in conjunction with the destination IP adress, will determine which interface the connection request goes out on.

It is possible to bind a socket then connect it. In this case, the socket will remain bound as per the bind call when it makes the connection. (Thanks to @RemyLebeau for pointing this out.)

How to bind socket to an interface in python (socket.SO_BINDTODEVICE missing)

If you don't understand the error message, it means you're referring a name IN which is not available at that point. Your code snippet is likely missing an import statement.

The socket module may not offer SO_BINDTODEVICE for portability reasons. If you are absolutely sure that you're running on Linux that supports it, try replacing it with it's numerical value, which is 25:

s.setsockopt(socket.SOL_SOCKET, 25, "eth1"+'\0')

Or for python 3:

s.setsockopt(socket.SOL_SOCKET, 25, str("eth1" + '\0').encode('utf-8'))


Related Topics



Leave a reply



Submit