views:

6888

answers:

9

How can I find the local IP address (i.e. 192.168.x.x or 10.0.x.x) in python, preferably with only built-in moduals, I would also like it to be platform independent.

+13  A: 
import socket
socket.gethostbyname(socket.gethostname())

This won't work always (returns 127.0.0.1 on machines having the hostname in /etc/hosts as 127.0.0.1), a paliative would be what gimel shows, use socket.getfqdn() instead. Of course your machine needs a resolvable hostname.

Vinko Vrsalovic
One should note that this isn't a platform independent solution. A lot of Linuxes will return 127.0.0.1 as your IP address using this method.
Jason Baker
A variation: socket.gethostbyname(socket.getfqdn())
gimel
I am accepting this despite the potential for unreliability.
Unkwntech
This appears to only return a single IP address. What if the machine has multiple addresses?
Jason R. Coombs
+3  A: 

I'm afraid there aren't any good platform independent ways to do this other than connecting to another computer and having it send you your IP address. For example: findmyipaddress. Note that this won't work if you need an IP address that's behind NAT unless the computer you're connecting to is behind NAT as well.

Here's one solution that works in Linux: get the IP address associated with a network interface.

Jason Baker
+6  A: 

I just found this but it seems a bit hackish, however they say tried it on *nix and I did on windows and it worked.

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("gmail.com",80))
print s.getsockname()

This assumes you have an internet access, and that there is no local proxy.

Unkwntech
Nice if you have several interfaces on the machine, and needs the one which routes to e.g. gmail.com
elzapp
+2  A: 

You can use the netifaces module. Just type:

easy_install netifaces

in your command shell and it will install itself on default Python installation.

Then you can use it like this:

from netifaces import interfaces, ifaddresses, AF_INET
for ifaceName in interfaces():
    addresses = [i['addr'] for i in ifaddresses(ifaceName)[AF_INET]]
    print '%s: %s' % (ifaceName, ', '.join(addresses))

On my computer it printed:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207

Author of this module claims it should work on Windows, UNIX and Mac OS X.

DzinX
As stated in the question I want something from the default install, as in no additional installs needed.
Unkwntech
+5  A: 

If you don't want to use external packages and don't want to rely on outside Internet servers, this might help. It's a code sample that I found on Google Code Search and modified to return required information:

def getIPAddresses():
    from ctypes import Structure, windll, sizeof
    from ctypes import POINTER, byref
    from ctypes import c_ulong, c_uint, c_ubyte, c_char
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128
    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_ADDRESS_LENGTH = 8
    class IP_ADDR_STRING(Structure):
        pass
    LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", c_char * 16),
        ("ipMask", c_char * 16),
        ("context", c_ulong)]
    class IP_ADAPTER_INFO (Structure):
        pass
    LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", c_ulong),
        ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", c_uint),
        ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", c_ulong),
        ("type", c_uint),
        ("dhcpEnabled", c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", c_ulong),
        ("leaseExpires", c_ulong)]
    GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = c_ulong
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
    adapterList = (IP_ADAPTER_INFO * 10)()
    buflen = c_ulong(sizeof(adapterList))
    rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
    if rc == 0:
        for a in adapterList:
            adNode = a.ipAddressList
            while True:
                ipAddr = adNode.ipAddress
                if ipAddr:
                    yield ipAddr
                adNode = adNode.next
                if not adNode:
                    break

Usage:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

As it relies on windll, this will work only on Windows.

DzinX
The one liner solution above generally works on windows. It's the Linux one that's being a problem.
+1 This technique at least attempts to return all addresses on the machine.
Jason R. Coombs
This script fails on my machine after returning the first address. Error is "AttributeError: 'LP_IP_ADDR_STRING' object has no attribute 'ipAddress'" I suspect it has something to do with the IPv6 address.
Jason R. Coombs
It turns out the issue is that for anything but the first IP address, the adNode isn't dereferenced. Add one more line to the example in the while loop and it works for me: adNode = adNode.contents
Jason R. Coombs
+8  A: 
import socket
print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][0])

I'm using this, because one of the computers I was on had an /etc/hosts with duplicate entries and references to itself. socket.gethostbyname() only returns the last entry in /etc/hosts. This solution weeds out the ones starting with "127.". Works with Python 3 and 2.5, possibly other versions too. Does not deal with several network devices or IPv6.

Alexander
seems to work fine in python 2.5 too :)
nornagon
Awesome. Thanks.
ayaz
+1  A: 

im using following module:

#!/usr/bin/python

# module for getting the lan ip address of the computer

import os

import socket

if os.name != "nt":

    import fcntl

    import struct

    def get_interface_ip(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])



def get_lan_ip():

    ip = socket.gethostbyname(socket.gethostname())

    if ip.startswith("127.") and os.name != "nt":

     interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]

     for ifname in interfaces:

      try:

       ip = get_interface_ip(ifname)

       break;

      except IOError:

       pass

    return ip

Tested with windows and linux (and doesnt require additional modules for those) intended for use on systems which are in a single LAN.

smerlin
+1  A: 

FYI I can verify that the method:

import socket
addr = socket.gethostbyname(socket.gethostname())

Works in OS X (10.6,10.5), Windows XP, and on a well administered RHEL department server. It did not work on a very minimal CentOS VM that I just do some kernel hacking on. So for that instance you can just check for a 127.0.0.1 address and in that case do the following:

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)

And then parse the ip address from the output. It should be noted that ifconfig is not in a normal user's PATH by default and that is why I give the full path in the command. I hope this helps.

gavaletz
+1  A: 

I use this on my ubuntu machines:

import commands
commands.getoutput("ifconfig").split("\n")[1].split()[1][5:]
synapz