开发者

Finding local IP addresses using Python's stdlib

开发者 https://www.devze.com 2023-03-14 17:49 出处:网络
How can I fin开发者_如何学运维d local IP addresses (i.e. 192.168.x.x or 10.0.x.x) in Python platform independently and using only the standard library?I just found this but it seems a bit hackish, how

How can I fin开发者_如何学运维d local IP addresses (i.e. 192.168.x.x or 10.0.x.x) in Python platform independently and using only the standard library?


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.


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.


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)
        s.settimeout(0)
        try:
            # doesn't even have to be reachable
            s.connect(('10.254.254.254', 1))
            IP = s.getsockname()[0]
        except Exception:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP
    print(get_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 something like this answer.

If you are behind a NAT firewall like your wifi router 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. If you instead need your external IP:

  • running this function on THAT external device (wifi router), or

  • connecting to an external service such as https://www.ipify.org/ that could reflect back the IP as it's seen from the outside world

... but those ideas are completely different from the original question. :)


As an alias called myip:

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.
  • Reportedly, this does not work on the latest releases of macOS.

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.


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.


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]


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.


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'
>>> 


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.


[Windows only] 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.


I use this on my ubuntu machines:

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

This doesn't work.


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())


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())


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'


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'])


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


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.


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.


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.


import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]


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()


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())


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.


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.


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)]


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'])


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!


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.


To get the ip address you can use a shell command directly in python:

import socket, subprocess

def get_ip_and_hostname():
    hostname =  socket.gethostname()

    shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
    proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
    (out, err) = proc.communicate()

    ip_list = out.split('\n')
    ip = ip_list[0]

    for _ip in ip_list:
        try:
            if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
                ip = _ip
        except:
            pass
    return ip, hostname

ip_addr, hostname = get_ip_and_hostname()


A Python 3.4 version utilizing the newly introduced asyncio package.

async def 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号