Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Get local IP-Address used to send IP data to a specific remote IP-Address

Tags:

python

ip

I am using a Python script to send UDP packets to a server which will register my script to receive notifications from the server. The protocol requires that I send my own IP-Address and port on which I want to receive these notifications, so this should be an address that is reachable from the server's network.

Solutions should at least work on Windows XP and above and preferably Mac OS X, as this is my development platform.

The first step is to get the IP-Address of any of my interfaces. I am currently using the commonly suggested approach of resolving the machines own host name:

def get_local_address():
    return socket.gethostbyname(socket.gethostname())

This only works sometimes. Currently it returns 172.16.249.1, which is the address of a virtual interface used by VM Ware, so this is a problem.

Much better would be a way to get the IP-Address of the default interface, which should be the right one most of the time.

Even better would be a way to get the actual IP-Address used to connect to the server by a connection-oriented protocol like TCP. I can actually get that address, but not without attempting to open the connection:

def get_address_to_connect_to(server_addr):
    non_open_port = 50000
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        s.connect((server_addr, non_open_port))
    except socket.error:
        pass
    else:
        s.close() # just in case

    return s.getsockname()[0]

This will block until some TCP timeout has been reached in the case that the server is unreachable or an evil firewall in between is blocking ICMP packets. Is there a better way to get that information?

like image 818
Feuermurmel Avatar asked Sep 07 '11 13:09

Feuermurmel


People also ask

Which of the following Python statement is used to get IP address of the local machine?

Python socket module gethostbyname() function accepts hostname argument and returns the IP address in the string format.

What is IPAddr in Python?

ipaddr.py is a library for working with IP addresses, both IPv4 and IPv6. It has been superseded by ipaddress from the Python 3 standard library, and its Python 2 backport.


1 Answers

I had to solve the same problem once, and spent considerable time trying to find a better way, without success. I also started with gethostname, but discovered, as you did, that it doesn't always return the right result, and can even throw an exception in cases where there is a problem with the hosts file.

The only solution I could find that works reliably across platforms is to try the connection, as you're doing. One improvement on your code is to use UDP instead of TCP, i.e. SOCK_DGRAM instead of SOCK_STREAM. That avoids the connect timeout, and the function just completes immediately.

If you're deploying this code to client locations that might be running firewalls, make sure you document the fact that it does this check. Otherwise they may see a firewall warning for an outbound connection to port 50000, not understand its purpose, and consider it a bug.

Edit: here's roughly the code I used:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

try:
    s.connect((host, 9))
    client = s.getsockname()[0]
except socket.error:
    client = "Unknown IP"
finally:
    del s
return client

I think you're getting 0.0.0.0 because you're closing the socket before calling getsockname. Another tip is my use of port 9; it's the RFC863 UDP discard port, and therefore slightly less weird than some random high-numbered port.

like image 111
DNS Avatar answered Oct 13 '22 00:10

DNS