25

What I have done so far, using PyQt classes:

all_Addresses = QNetworkInterface.allAddresses()    #list-of-QHostAddress

for addr in all_Addresses:
    print(addr.toString())

Output:

172.16.0.186 - Virtual Interface IP address
192.168.10.2 - Physical interface IP address. I want this one.
127.0.0.1

Using socket:

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

Output:

172.16.0.186 - When openVPN is on
192.168.10.2 - When its off
  1. Is there a way to distinguish between them?
  2. Can this be done with ordinary Python, instead of using PyQt classes?
  3. How can I get the IPv6 address as well?
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Johny_M
  • 641
  • 1
  • 7
  • 16
  • possible duplicate of [Finding local IP addresses in Python.](http://stackoverflow.com/questions/166506/finding-local-ip-addresses-in-python) – Lennart Regebro Jun 05 '11 at 14:37
  • The loopback is always 127.0.0.1, so that's hardly a problem. – Lennart Regebro Jun 05 '11 at 14:37
  • By the way in address schemes `127.0.0.1` is the same as `localhost` is the same as `::-1` – Jakob Bowyer Jun 05 '11 at 15:17
  • Thank you for your swift answers. I tried the example that Lennart provided, using import socket. There is the issue that an Interface can have many IP addresses, and when using VPN different output is shown with the socket way. – Johny_M Jun 05 '11 at 15:23
  • What are you trying to achieve? – Jakob Bowyer Jun 05 '11 at 15:30
  • I would like to get 192.168.10.2 whether VPN is on or off, disregarding the virtual interfaces that are installed by various applications on a computer. – Johny_M Jun 05 '11 at 15:35
  • Are you trying to find the IP address associated with the "default gateway" (routing concept)? – Craig McQueen Jun 06 '11 at 00:40
  • *Why* would you like to get 192.168.10.2? What is the essential property of 192.168.10.2 that makes it "the good one" for your purposes? – Craig McQueen Jun 06 '11 at 23:53
  • 192.168.10.2 is "the good one" because it is always listening, regardless of the state of other virtual interfaces. – Johny_M Jun 08 '11 at 20:34
  • Loopback is not always `127.0.0.1`. Usually, any address under 127.0.0.0/24 is reached through the loopback interface, but that can be configured. – jjmontes Jan 31 '17 at 17:57

3 Answers3

48

You should use netifaces. It is designed to be cross-platform and contains specialised code for Windows together with a variety of generic versions that work on different UNIX/UNIX-like platforms.

As of netifaces version 0.10.0, Python3 is supported.

Usage Summary

>>> from netifaces import AF_INET, AF_INET6, AF_LINK, AF_PACKET, AF_BRIDGE
>>> import netifaces as ni
>>> ni.interfaces()
['lo', 'eth0', 'eth1', 'vboxnet0', 'dummy1']
>>>
>>> ni.ifaddresses('eth0')[AF_LINK]   # NOTE: AF_LINK is an alias for AF_PACKET
[{'broadcast': 'ff:ff:ff:ff:ff:ff', 'addr': '00:02:55:7b:b2:f6'}]
>>> ni.ifaddresses('eth0')[AF_INET]
[{'broadcast': '172.16.161.7', 'netmask': '255.255.255.248', 'addr': '172.16.161.6'}]
>>>
>>> # eth0 ipv4 interface address
>>> ni.ifaddresses('eth0')[AF_INET][0]['addr']
'172.16.161.6'
>>>>

Details

Windows Support:

No compiler required for most MS Windows installs. If you get warnings about installing MS Visual C++ for Windows, be very careful because you need to match the version of compiler used for your python with that used for the module.

Detailed example of netifaces data structures:

>>> import netifaces as ni
>>> ni.interfaces()
['lo', 'eth0', 'eth1', 'vboxnet0', 'dummy1']
>>> ni.ifaddresses('eth0')
{
    17: [
        {
            'broadcast': 'ff:ff:ff:ff:ff:ff',
            'addr': '00:02:55:7b:b2:f6'
        }
    ],
    2: [
        {
            'broadcast': '172.16.161.7',
            'netmask': '255.255.255.248',
            'addr': '172.16.161.6'
        }
    ],
    10: [
        {
            'netmask': 'ffff:ffff:ffff:ffff::',
            'addr': 'fe80::202:55ff:fe7b:b2f6%eth0'
        }
    ]
}
>>> 
>>> print(ni.ifaddresses.__doc__)
Obtain information about the specified network interface.

Returns a dict whose keys are equal to the address family constants,
e.g. netifaces.AF_INET, and whose values are a list of addresses in
that family that are attached to the network interface.
>>>
>>> # for the IPv4 address of eth0
>>> ni.ifaddresses('eth0')[2][0]['addr']
'172.16.161.6'

The numbers used to index protocols are from /usr/include/linux/socket.h (in Linux)... EDIT: my 3.2 kernel has them here: /usr/src/linux-headers-3.2.0-4-common/include/linux/socket.h

#define AF_INET         2       /* Internet IP Protocol         */
#define AF_INET6        10      /* IP version 6                 */
#define AF_PACKET       17      /* Packet family                */

The good news is that you don't have to remember all those header constants, they are included with netifaces:

>>> from netifaces import AF_INET, AF_INET6, AF_LINK, AF_PACKET, AF_BRIDGE
>>> import netifaces as ni
Community
  • 1
  • 1
Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
  • 1
    It looks interesting, but i cant get it to work. i have trouble installing easy_install which looks as a requirement of netifaces. Sorry i am new to Python :-( – Johny_M Jun 08 '11 at 20:36
  • @Johny Mnemonic, you don't need `easy_install`... just [download the source](http://alastairs-place.net/2007/03/netifaces/netifaces-0.5.tar.gz), extract with `tar xvfz netifaces-0.5.tar.gz` and install as root: `cd netifaces-0.5/; python setup.py install` – Mike Pennington Jun 08 '11 at 20:58
  • 1
    netifaces is all well and good, but it doesn't support py3k, and clones that provide such still require a C compiler on windows. – Matt Joiner Jun 05 '12 at 06:38
  • 2
    netifaces 0.10.0 and higher *do* support Py3K and also have Windows binaries so you don't need a compiler. – al45tair May 02 '14 at 15:50
  • on ubuntu sudo apt-get install python-netifaces or for python3 sudo apt-get install python3-netifaces – shao.lo Sep 22 '16 at 14:38
18

Uses the Linux SIOCGIFADDR ioctl to find the IP address associated with a network interface, given the name of that interface, e.g. "eth0". The address is returned as a string containing a dotted quad.

import socket
import fcntl
import struct

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

>>> get_ip_address('lo')
'127.0.0.1'

>>> get_ip_address('eth0')
'38.113.228.130'

For more

Tanveer Alam
  • 5,185
  • 4
  • 22
  • 43
  • 1
    But its not working with python3.4.3, getting below error, `Traceback (most recent call last): File "/home/user1/ipadd.py", line 27, in defaultIpAddr = get_ip_address(defaultIfaceName) File "/home/user1/ipadd.py", line 24, in get_ip_address struct.pack('256s', ifname[:15]) struct.error: argument for 's' must be a bytes object ` – Karthi1234 Mar 18 '17 at 09:18
  • 1
    on python 3.4 this functions doesnt work, transform ifname in a byte array like so (ifname[:15] **.encode('utf-8')**) – Bruno Romano Jul 27 '17 at 20:26
  • I don't understand the magic ioctl-address fiddling enough to get all addresses when the interface has more than one. Can you elaborate the code a bit? – cessor Jul 28 '18 at 14:11
8

I use this solution. It's a little bit tricky actually, and it's only works on linux family.

import commands
intf = 'eth0'
intf_ip = commands.getoutput("ip address show dev " + intf).split()
intf_ip = intf_ip[intf_ip.index('inet') + 1].split('/')[0]
print intf_ip

Those code utilize ip command on linux family operating system. It split the output from ip command and only take the IPv4 address of those interface. You can change the value intf to eth1 or p2p1.

Data
  • 408
  • 4
  • 10