Finding local IP addresses using Python's stdlib under Debian jessie

I am writing a distributed systems program in python, and in this program I need to know the local ip-address... eg. 168.192.... 10.13..... etc, not 127.0.0.1 or hostname.

I have found following solution on stackoverflow

https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib

import socket
socket.gethostbyname(socket.gethostname())

When I run this on my Debian jessie laptop, I get 127.0.0.1, however, my friend who is using Fedora on his machine gets the desired ip address when he runs the same script (eg. 168.192..)

I prefer to use the solution above if possible to get the local ip address, because most of the other proposed solutions are either hacks or incredible long...

Is there something I can setup on my Debian jessie laptop such that python will return the correct local ip-address?

  • using debian jessie
  • python 3
  • is connected to network (.. and computer is turned on)... ;)
  • /etc/hosts currently contains:

127.0.0.1 localhost 127.0.0.1 debianASUS ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters


Solution 1:

The most reliable way to find the IP address your host will use to communicate is by using getsockname on a connected UDP socket. In case of UDP the connect system call doesn't involve any network communication.

Here is a Python function I have written in the past for a similar purpose. If you don't know in advance which remote IP address you will communicate with, you should be looking for one which will be using the default route. If you already know which remote IP address you will communicate with, then it is better to use that IP address in the connect call.

def my_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.connect(('192.0.0.8', 1027))
    except socket.error:
        return None
    return s.getsockname()[0]

With a few minor changes, this function can be adapted to return an IPv6 address rather than IPv4:

def my_ipv6():
    s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    try:
        s.connect(('2001:db8::', 1027))
    except socket.error:
        return None
    return s.getsockname()[0]

Solution 2:

Have you considered defering the decision to the end user at runtime, through a configuration parameter ? This is a standard practice for this problem.

The reason is there is no systematic foolproof way to figure "the" local IP address (a host may be multihomed, may be running a v4/v6 dual stack, a VPN, etc..). Runtime configuration will make the sysadmin's job easier !