How can I find local IP addresses (i.e. 192.168.x.x or 10.0.x.x) in Python platform independently and using only the standard library?
networking – Finding local IP addresses using Python’s stdlib
The Question :
- The local IP? Or public IP? How are you going to deal with systems with multiple IPs?
- use
ifconfig -a
and use the output from there… - @Fredrik That’s a bad idea. First of all, you’re unnecessarily forking a new process, and that may prevent your program from working in tightly locked configurations (or, you’ll have to allow rights your program doesn’t need). Secondly, you’ll introduce bugs for users of different locales. Thirdly, if you decide to start a new program at all, you shouldn’t start a deprecated one –
ip addr
is far more suitable (and easier to parse, to boot). - @phihag you are absolutely correct, thanks for correcting my stupidity
- A more fundamental problem here is that in a properly written modern networking program the right (set of) local IP address(es) depends on the peer, or the set of potential peers. If the local IP address is needed to
bind
a socket to a particular interface, then it is a policy matter. If the local IP address is needed to hand it over to a peer so that the peer can “call back”, i.e. to open a connection back to the local machine, then the situation depends on whether there are any NAT (Network Address Translation) boxes in between. If there are no NATs,getsockname
is a good choice.
The Answer 1
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.
The Answer 2
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.
import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) print(s.getsockname()[0]) s.close()
This assumes you have an internet access, and that there is no local proxy.
The Answer 3
This method returns the “primary” IP on the local box (the one with a default route).
- Does NOT need routable net access or any connection at all.
- Works even if all interfaces are unplugged from the network.
- Does NOT need or even try to get anywhere else.
- Works with NAT, public, private, external, and internal IP’s
- Pure Python 2 (or 3) with no external dependencies.
- Works on Linux, Windows, and OSX.
Python 3 or 2:
import socket def get_ip(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: # doesn't even have to be reachable s.connect(('10.255.255.255', 1)) IP = s.getsockname()[0] except Exception: IP = '127.0.0.1' finally: s.close() return IP
This returns a single IP which is the primary (the one with a default route). If you need instead all IP’s attached to all interfaces (including localhost, etc), see this answer.
If you are behind a NAT firewall like your wifi box at home, then this will not show your public NAT IP, but instead your private IP on the local network which has a default route to your local WIFI router; getting your wifi router’s external IP would either require running this on THAT box, or connecting to an external service such as whatismyip.com/whatismyipaddress.com that could reflect back the IP… but that is completely different from the original question. 🙂
The Answer 4
As an alias called myip
, that should work everywhere:
alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"
- Works correctly with Python 2.x, Python 3.x, modern and old Linux distros, OSX/macOS and Windows for finding the current IPv4 address.
- Will not return the correct result for machines with multiple IP addresses, IPv6, no configured IP address or no internet access.
NOTE: If you intend to use something like this within a Python program, the proper way is to make use of a Python module that has IPv6 support.
Same as above, but only the Python code:
import socket print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
- This will throw an exception if no IP address is configured.
Version that will also work on LANs without an internet connection:
import socket print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])
(thanks @ccpizza)
Background:
Using socket.gethostbyname(socket.gethostname())
did not work here, 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 was my initial attempt, which weeds out all addresses starting with "127."
:
import socket print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])
This works with Python 2 and 3, on Linux and Windows, but does not deal with several network devices or IPv6. However, it stopped working on recent Linux distros, so I tried this alternative technique instead. It tries to connect to the Google DNS server at 8.8.8.8
at port 53
:
import socket print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])
Then I combined the two above techniques into a one-liner that should work everywhere, and created the myip
alias and Python snippet at the top of this answer.
With the increasing popularity of IPv6, and for servers with multiple network interfaces, using a third-party Python module for finding the IP address is probably both more robust and reliable than any of the methods listed here.
The Answer 5
You can use the netifaces module. Just type:
pip 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).setdefault(AF_INET, [{'addr':'No IP addr'}] )] 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.
The Answer 6
If the computer has a route to the Internet, this will always work to get the preferred local ip address, even if /etc/hosts is not set correctly.
import socket s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 1)) # connect() for UDP doesn't send packets local_ip_address = s.getsockname()[0]
The Answer 7
Socket API method
see https://stackoverflow.com/a/28950776/711085
Downsides:
- Not cross-platform.
- Requires more fallback code, tied to existence of particular addresses on the internet
- This will also not work if you’re behind a NAT
- Probably creates a UDP connection, not independent of (usually ISP’s) DNS availability (see other answers for ideas like using 8.8.8.8: Google’s (coincidentally also DNS) server)
- Make sure you make the destination address UNREACHABLE, like a numeric IP address that is spec-guaranteed to be unused. Do NOT use some domain like fakesubdomain.google.com or somefakewebsite.com; you’ll still be spamming that party (now or in the future), and spamming your own network boxes as well in the process.
Reflector method
(Do note that this does not answer the OP’s question of the local IP address, e.g. 192.168…; it gives you your public IP address, which might be more desirable depending on use case.)
You can query some site like whatismyip.com (but with an API), such as:
from urllib.request import urlopen import re def getPublicIp(): data = str(urlopen('http://checkip.dyndns.com/').read()) # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n' return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)
or if using python2:
from urllib import urlopen import re def getPublicIp(): data = str(urlopen('http://checkip.dyndns.com/').read()) # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n' return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)
Advantages:
- One upside of this method is it’s cross-platform
- It works from behind ugly NATs (e.g. your home router).
Disadvantages (and workarounds):
- Requires this website to be up, the format to not change (almost certainly won’t), and your DNS servers to be working. One can mitigate this issue by also querying other third-party IP address reflectors in case of failure.
- Possible attack vector if you don’t query multiple reflectors (to prevent a compromised reflector from telling you that your address is something it’s not), or if you don’t use HTTPS (to prevent a man-in-the-middle attack pretending to be the server)
edit: Though initially I thought these methods were really bad (unless you use many fallbacks, the code may be irrelevant many years from now), it does pose the question “what is the internet?”. A computer may have many interfaces pointing to many different networks. For a more thorough description of the topic, google for gateways and routes
. A computer may be able to access an internal network via an internal gateway, or access the world-wide web via a gateway on for example a router (usually the case). The local IP address that the OP asks about is only well-defined with respect to a single link layer, so you have to specify that (“is it the network card, or the ethernet cable, which we’re talking about?”). There may be multiple non-unique answers to this question as posed. However the global IP address on the world-wide web is probably well-defined (in the absence of massive network fragmentation): probably the return path via the gateway which can access the TLDs.
The Answer 8
On Linux:
>>> import socket, struct, fcntl >>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) >>> sockfd = sock.fileno() >>> SIOCGIFADDR = 0x8915 >>> >>> def get_ip(iface = 'eth0'): ... ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14) ... try: ... res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq) ... except: ... return None ... ip = struct.unpack('16sH2x4s8x', res)[2] ... return socket.inet_ntoa(ip) ... >>> get_ip('eth0') '10.80.40.234' >>>
The Answer 9
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', bytes(ifname[:15], 'utf-8')) # Python 2.7: remove the second argument for the bytes call )[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 IPv4 based LAN.
The fixed list of interface names does not work for recent linux versions, which have adopted the systemd v197 change regarding predictable interface names as pointed out by Alexander. In such cases, you need to manually replace the list with the interface names on your system, or use another solution like netifaces.
The Answer 10
I use this on my ubuntu machines:
import commands commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]
This doesn’t work.
The Answer 11
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.
The Answer 12
On Debian (tested) and I suspect most Linux’s..
import commands RetMyIP = commands.getoutput("hostname -I")
On MS Windows (tested)
import socket socket.gethostbyname(socket.gethostname())
The Answer 13
A version I do not believe that has been posted yet. I tested with python 2.7 on Ubuntu 12.04.
Found this solution at : http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/
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])
Example Result:
>>> get_ip_address('eth0') '38.113.228.130'
The Answer 14
Variation on ninjagecko’s answer. This should work on any LAN that allows UDP broadcast and doesn’t require access to an address on the LAN or internet.
import socket def getNetworkIp(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.connect(('<broadcast>', 0)) return s.getsockname()[0] print (getNetworkIp())
The Answer 15
This is a variant of UnkwnTech’s answer — it provides a get_local_addr()
function, which returns the primary LAN ip address of the host. I’m posting it because this adds a number of things: ipv6 support, error handling, ignoring localhost/linklocal addrs, and uses a TESTNET addr (rfc5737) to connect to.
# imports import errno import socket import logging # localhost prefixes _local_networks = ("127.", "0:0:0:0:0:0:0:1") # ignore these prefixes -- localhost, unspecified, and link-local _ignored_networks = _local_networks + ("0.", "0:0:0:0:0:0:0:0", "169.254.", "fe80:") def detect_family(addr): if "." in addr: assert ":" not in addr return socket.AF_INET elif ":" in addr: return socket.AF_INET6 else: raise ValueError("invalid ipv4/6 address: %r" % addr) def expand_addr(addr): """convert address into canonical expanded form -- no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups. """ family = detect_family(addr) addr = socket.inet_ntop(family, socket.inet_pton(family, addr)) if "::" in addr: count = 8-addr.count(":") addr = addr.replace("::", (":0" * count) + ":") if addr.startswith(":"): addr = "0" + addr return addr def _get_local_addr(family, remote): try: s = socket.socket(family, socket.SOCK_DGRAM) try: s.connect((remote, 9)) return s.getsockname()[0] finally: s.close() except socket.error: # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True) return None def get_local_addr(remote=None, ipv6=True): """get LAN address of host :param remote: return LAN address that host would use to access that specific remote address. by default, returns address it would use to access the public internet. :param ipv6: by default, attempts to find an ipv6 address first. if set to False, only checks ipv4. :returns: primary LAN address for host, or ``None`` if couldn't be determined. """ if remote: family = detect_family(remote) local = _get_local_addr(family, remote) if not local: return None if family == socket.AF_INET6: # expand zero groups so the startswith() test works. local = expand_addr(local) if local.startswith(_local_networks): # border case where remote addr belongs to host return local else: # NOTE: the two addresses used here are TESTNET addresses, # which should never exist in the real world. if ipv6: local = _get_local_addr(socket.AF_INET6, "2001:db8::1234") # expand zero groups so the startswith() test works. if local: local = expand_addr(local) else: local = None if not local: local = _get_local_addr(socket.AF_INET, "192.0.2.123") if not local: return None if local.startswith(_ignored_networks): return None return local
The Answer 16
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.
The Answer 17
One simple way to produce “clean” output via command line utils:
import commands ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " + "awk {'print $2'} | sed -ne 's/addr\:/ /p'") print ips
It will show all IPv4 addresses on the system.
The Answer 18
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.
The Answer 19
import socket [i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]
The Answer 20
This will work on most linux boxes:
import socket, subprocess, re def get_ipv4_address(): """ Returns IP address(es) of current machine. :return: """ p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE) ifc_resp = p.communicate() patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') resp = patt.findall(ifc_resp[0]) print resp get_ipv4_address()
The Answer 21
This answer is my personal attempt to solve the problem of getting the LAN IP, since socket.gethostbyname(socket.gethostname())
also returned 127.0.0.1. This method does not require Internet just a LAN connection. Code is for Python 3.x but could easily be converted for 2.x. Using UDP Broadcast:
import select import socket import threading from queue import Queue, Empty def get_local_ip(): def udp_listening_server(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.bind(('<broadcast>', 8888)) s.setblocking(0) while True: result = select.select([s],[],[]) msg, address = result[0][0].recvfrom(1024) msg = str(msg, 'UTF-8') if msg == 'What is my LAN IP address?': break queue.put(address) queue = Queue() thread = threading.Thread(target=udp_listening_server) thread.queue = queue thread.start() s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) waiting = True while waiting: s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888)) try: address = queue.get(False) except Empty: pass else: waiting = False return address[0] if __name__ == '__main__': print(get_local_ip())
The Answer 22
If you’re looking for an IPV4 address different from your localhost IP address 127.0.0.1
, here is a neat piece of python codes:
import subprocess address = subprocess.check_output(['hostname', '-s', '-I']) address = address.decode('utf-8') address=address[:-1]
Which can also be written in a single line:
address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]
Even if you put localhost
in /etc/hostname
, the code will still give your local IP address.
The Answer 23
For linux, you can just use check_output
of the hostname -I
system command like so:
from subprocess import check_output check_output(['hostname', '-I'])
The Answer 24
127.0.1.1
is your real IP address. More generally speaking, a computer can have any number of IP addresses. You can filter them for private networks – 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.
However, there is no cross-platform way to get all IP addresses. On Linux, you can use the SIOCGIFCONF
ioctl.
The Answer 25
A slight refinement of the commands version that uses the IP command, and returns IPv4 and IPv6 addresses:
import commands,re,socket #A generator that returns stripped lines of output from "ip address show" iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n')) #Turn that into a list of IPv4 and IPv6 address/mask strings addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines)) #addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64'] #Get a list of IPv4 addresses as (IPstring,subnetsize) tuples ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)] #ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)] #Get IPv6 addresses ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]
The Answer 26
Well you can use the command “ip route” on GNU/Linux to know your current IP address.
This shows the IP given to the interface by the DHCP server running on the router/modem. Usually “192.168.1.1/24” is the IP for local network where “24” means the range of posible IP addresses given by the DHCP server within the mask range.
Here’s an example: Note that PyNotify is just an addition to get my point straight and is not required at all
#! /usr/bin/env python import sys , pynotify if sys.version_info[1] != 7: raise RuntimeError('Python 2.7 And Above Only') from subprocess import check_output # Available on Python 2.7+ | N/A IP = check_output(['ip', 'route']) Split_Result = IP.split() # print Split_Result[2] # Remove "#" to enable pynotify.init("image") notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png") notify.show()
The advantage of this is that you don’t need to specify the network interface. That’s pretty useful when running a socket server
You can install PyNotify using easy_install or even Pip:
easy_install py-notify
or
pip install py-notify
or within python script/interpreter
from pip import main main(['install', 'py-notify'])
The Answer 27
Note: This is not using the standard library, but quite simple.
$ pip install pif
from pif import get_public_ip get_public_ip()
The Answer 28
netifaces is available via pip and easy_install. (I know, it’s not in base, but it could be worth the install.)
netifaces does have some oddities across platforms:
- The localhost/loop-back interface may not always be included (Cygwin).
- Addresses are listed per-protocol (e.g., IPv4, IPv6) and protocols are listed per-interface. On some systems (Linux) each protocol-interface pair has its own associated interface (using the interface_name:n notation) while on other systems (Windows) a single interface will have a list of addresses for each protocol. In both cases there is a protocol list, but it may contain only a single element.
Here’s some netifaces code to play with:
import netifaces PROTO = netifaces.AF_INET # We want only IPv4, for now at least # Get list of network interfaces # Note: Can't filter for 'lo' here because Windows lacks it. ifaces = netifaces.interfaces() # Get all addresses (of all kinds) for each interface if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces] # Filter for the desired address type if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr] iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s] # Can filter for '127.0.0.1' here.
The above code doesn’t map an address back to its interface name (useful for generating ebtables/iptables rules on the fly). So here’s a version that keeps the above information with the interface name in a tuple:
import netifaces PROTO = netifaces.AF_INET # We want only IPv4, for now at least # Get list of network interfaces ifaces = netifaces.interfaces() # Get addresses for each interface if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces] # Filter for only IPv4 addresses if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]] iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]
And, no, I’m not in love with list comprehensions. It’s just the way my brain works these days.
The following snippet will print it all out:
from __future__ import print_function # For 2.x folks from pprint import pprint as pp print('\nifaces = ', end='') pp(ifaces) print('\nif_addrs = ', end='') pp(if_addrs) print('\nif_inet_addrs = ', end='') pp(if_inet_addrs) print('\niface_addrs = ', end='') pp(iface_addrs)
Enjoy!
The Answer 29
A Python 3.4 version utilizing the newly introduced asyncio package.
async get_local_ip(): loop = asyncio.get_event_loop() transport, protocol = await loop.create_datagram_endpoint( asyncio.DatagramProtocol, remote_addr=('8.8.8.8', 80)) result = transport.get_extra_info('sockname')[0]) transport.close() return result
This is based on UnkwnTech’s excellent answer.
The Answer 30
import netifaces as ni ni.ifaddresses('eth0') ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr'] print(ip)
This will return you the IP address in the Ubuntu system as well as MacOS. The output will be the system IP address as like my IP: 192.168.1.10.