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?
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.
socket.gethostbyname_ex(socket.gethostname())[-1]
–
Caseose socket.gethostbyname(socket.gethostname())
returned the Virtualbox address. @JasonR.Coombs answer was helpful because it returned both. VirtualBox is first on mine but I don't know how it decides on the order –
Leaflet socket.getfqdn()
introduces a delay of 8-10 seconds on my platform. (I'm using Windows on a large corporate network.) –
Aucoin socket.gethostbyname_ex(socket.gethostname())[-1][-1]
–
Papyraceous 127.0.1.1
on a VM set up with both NAT and host-only adapter. socket.gethostbyname_ex()
does not list any other interfaces other than 127.0.1.1
. Connecting to 8.8.8.8
then getting the IP address works, but does not really seem straightforward. –
Buckeen 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.
s.connect(('10.255.255.255', 1))
. –
Rheingold connect
. So you should stick to some TCP address –
Janniejanos net-tools
are installed but for some mysterious reason can't run ifconfig
. You can find out your local IP with only few lines of code. Python simply rocks. –
Rhombencephalon 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.
socket.gethostbyname_ex(socket.gethostname())[-1]
–
Caseose socket.gethostbyname(socket.gethostname())
returned the Virtualbox address. @JasonR.Coombs answer was helpful because it returned both. VirtualBox is first on mine but I don't know how it decides on the order –
Leaflet socket.getfqdn()
introduces a delay of 8-10 seconds on my platform. (I'm using Windows on a large corporate network.) –
Aucoin socket.gethostbyname_ex(socket.gethostname())[-1][-1]
–
Papyraceous 127.0.1.1
on a VM set up with both NAT and host-only adapter. socket.gethostbyname_ex()
does not list any other interfaces other than 127.0.1.1
. Connecting to 8.8.8.8
then getting the IP address works, but does not really seem straightforward. –
Buckeen 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. :)
socket.gethostbyname(socket.gethostname())
gives horrible results. –
Bullion 10.0.0.0
also works for me. –
Reconstitute utun1
interface (assume that's VPN ip) –
Papyraceous Permission denied
exception with this, on Ubuntu 22.04 –
Eau 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])
This method also works on the latest versions of macOS!
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.
socket.gethostbyname_ex('')
appears to work great without relying on the hostname of the computer. It happens to also return said hostname as the first item in tuple. So, socket.gethostbyname_ex('')[2]
gives me all my local IPs and /not/ 127.0.0.1 for some reason. This is on Python 2.6.6 32bit, Windows 7 64bit. –
Rhombencephalon socket.getaddrinfo()
for that. In other words, the answer by Nakilon way below will give you better results. –
Understood socket.getaddrinfo()
should work consistently across platforms - but I only checked it on Linux, didn't bother about any other operating systems. –
Understood /etc/resolve.conf: No such file or directory
and I have local IPv4 address shown by ifconfig
. –
Bloodandthunder 8.8.8.8
on port 80 - anyone else has this problem? google.com
on the other hand works fine –
Ptosis socket.gethostbyname_ex(socket.gethostname())[2]
which works for my needs which is dual-homed Arch Linux and python2/3. I am not sure what I am missing by not using the whole of the snippet given in the answer. –
Bi gethostbyname_ex
returned a valid IP. This will break in 'walled garden'-type of LANs with no internet. The external call can be made conditional by using or
, e.g.: ips = [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]]
–
Electrobiology 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.
sys
it seems like a good candidate for that. –
Pickerelweed 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]
8.8.8.8
is a google dns server can we do it with a local dns server ? –
Plaster Socket API method
see https://mcmap.net/q/63357/-finding-local-ip-addresses-using-python-39-s-stdlib
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'
>>>
ioctl
). The socket isn't bound the interface for which you want addr info about- its just a communication mechanism between userspace and the kernel. en.wikipedia.org/wiki/Ioctl lxr.free-electrons.com/source/net/socket.c –
Merideth struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
should be replaced with struct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14)
–
Materials ioctl
is a legacy interface I don't believe supports IPv6 and likely never will. I think the 'Right' way is via Netlink which isn't very straightforward in Python. I think libc should have the function getifaddrs
which can be accessed via pythons ctypes
module which may work - man7.org/linux/man-pages/man3/getifaddrs.3.html –
Merideth 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.
enp0s25
. For more info, see wiki.archlinux.org/index.php/Network_Configuration#Device_names –
Skeen struct.pack('256s', bytes(ifname[:15]))
–
Mitsukomitt [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.
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())
<broadcast>
a valid hostname?!! How many of these kinds of verbal hostnames are valid? –
Rimmer <broadcast>
on Windows 10, I get Wireless NIC IP address. When I use 10.255.255.255
then I get Ethernet TAP Adapter's IP address. Both are valid. But results re different, lol. –
Backstroke I use this on my ubuntu machines:
import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]
This doesn't work.
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())
hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]
–
Mauriciomaurie 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'])
check_output(['hostname', '-I']).decode().strip()
–
Fanaticism 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
None
–
Octal get_local_addr(remove="www.google.com")
return? Logging the socket.error
thrown by _get_local_addr() might help diagnostically. –
Monopteros 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)]
['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2']
on Windows desktop. –
Comprehend 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!
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.
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()
ifconfig
is deprecated -- even back when this answer was written in 2016, it didn't support all available kernel socket and address types, and could silently hide things (like secondary addresses that aren't bound to named aliases) that the newer iproute2 tools (such as ip addr list
) can show. –
Gharry 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.
For a list of IP addresses on *nix systems,
import subprocess
co = subprocess.Popen(['ifconfig'], stdout = subprocess.PIPE)
ifconfig = co.stdout.read()
ip_regex = re.compile('((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-4]|2[0-5][0-9]|[01]?[0-9][0-9]?))')
[match[0] for match in ip_regex.findall(ifconfig, re.MULTILINE)]
Though it's a bit late for this answer, I thought someone else may find it useful :-)
PS : It'll return Broadcast addresses and Netmask as well.
hostname -i
and hostname -I
(note the capital i
) an easier alternative to ifconfig
. The capital version returns all addresses, while the lower case returns the "default", which may be 127.0.1.1
(i.e. useless) –
Brake I had to solve the problem "Figure out if an IP address is local or not", and my first thought was to build a list of IPs that were local and then match against it. This is what led me to this question. However, I later realized there is a more straightfoward way to do it: Try to bind on that IP and see if it works.
_local_ip_cache = []
_nonlocal_ip_cache = []
def ip_islocal(ip):
if ip in _local_ip_cache:
return True
if ip in _nonlocal_ip_cache:
return False
s = socket.socket()
try:
try:
s.bind((ip, 0))
except socket.error, e:
if e.args[0] == errno.EADDRNOTAVAIL:
_nonlocal_ip_cache.append(ip)
return False
else:
raise
finally:
s.close()
_local_ip_cache.append(ip)
return True
I know this doesn't answer the question directly, but this should be helpful to anyone trying to solve the related question and who was following the same train of thought. This has the advantage of being a cross-platform solution (I think).
Note: This is not using the standard library, but quite simple.
$ pip install pif
from pif import get_public_ip
get_public_ip()
Here are two solutions, I tried to keep them very simple, and to explain each step.
TLDR;
First solution:
import socket, os
hostname = os.uname()[1]
print(socket.gethostbyname_ex(hostname)[2])
Second solution:
import socket
hostname = socket.gethostname()
print(socket.gethostbyname_ex(hostname)[2])
On my machine, both codes return a list containing the IP addresses:
['127.0.1.1', '192.168.1.47']
Detailed explanation:
First, get the hostname of the local machine by using uname
function from the os
module:
import os
hostname = os.uname()[1]
print(hostname) # Just to display an output
Note that this can also be done by calling the gethostname
function from the socket
module:
import socket
hostname = socket.gethostname()
print(hostname) # Just to display an output
Now, when passing this hostname to the gethostbyname_ex
function from the socket
module, it returns a tuple, the third part of that tuple is a list of the IP addresses:
addresses = socket.gethostbyname_ex(hostname)[2]
print(addresses) # Just to display an output
Note that this was largely inspired by a combination of answers above; I just tried to simplify things and make them as clear as possible.
Ok so this is Windows specific, and requires the installation of the python WMI module, but it seems much less hackish than constantly trying to call an external server. It's just another option, as there are already many good ones, but it might be a good fit for your project.
Import WMI
def getlocalip():
local = wmi.WMI()
for interface in local.Win32_NetworkAdapterConfiguration(IPEnabled=1):
for ip_address in interface.IPAddress:
if ip_address != '0.0.0.0':
localip = ip_address
return localip
>>>getlocalip()
u'xxx.xxx.xxx.xxx'
>>>
By the way, WMI is very powerful... if you are doing any remote admin of window machines you should definitely check out what it can do.
import socket
socket.gethostbyname(socket.getfqdn())
This isn't very Pythonic, but it works reliably on Windows.
def getWinIP(version = 'IPv4'):
import subprocess
if version not in ['IPv4', 'IPv6']:
print 'error - protocol version must be "IPv4" or "IPv6"'
return None
ipconfig = subprocess.check_output('ipconfig')
my_ip = []
for line in ipconfig.split('\n'):
if 'Address' in line and version in line:
my_ip.append(line.split(' : ')[1].strip())
return my_ip
print getWinIP()
Yeah, it's a hack, but at times I don't feel like second-guessing an operating system, and just go ahead and use what's built-in and works.
from netifaces import interfaces, ifaddresses, AF_INET
iplist = [ifaddresses(face)[AF_INET][0]["addr"] for face in interfaces() if AF_INET in ifaddresses(face)]
print(iplist)
['10.8.0.2', '192.168.1.10', '127.0.0.1']
A machine can have multiple network interfaces (including the local loopback 127.0.0.1) you mentioned. As far as the OS is concerned, it's also a "real IP address".
If you want to track all of interfaces, have a look at the following Python package, see: http://alastairs-place.net/netifaces/
I think you can avoid having gethostbyname return 127.0.0.1 if you ommit the loopback entry from your hosts file. (to be verified).
Yet another variant to previous answers, can be saved to an executable script named my-ip-to
:
#!/usr/bin/env python
import sys, socket
if len(sys.argv) > 1:
for remote_host in sys.argv[1:]:
# determine local host ip by outgoing test to another host
# use port 9 (discard protocol - RFC 863) over UDP4
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect((remote_host, 9))
my_ip = s.getsockname()[0]
print(my_ip, flush=True)
else:
import platform
my_name = platform.node()
my_ip = socket.gethostbyname(my_name)
print(my_ip)
it takes any number of remote hosts, and print out local ips to reach them one by one:
$ my-ip-to z.cn g.cn localhost
192.168.11.102
192.168.11.102
127.0.0.1
$
And print best-bet when no arg is given.
$ my-ip-to
192.168.11.102
For a linux env, read the /proc/net/tcp, the second (localaddress) and third (remoteaddress) will give the IPs at hexa format.
Tip: If second column is zeroed (00000000:0000) so its a Listen Port :)
https://github.com/romol0s/python/blob/master/general/functions/getTcpListenIpsByPort.py
https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt
Windows solution, Take it or leave it.
gets only the self ip, on the current active wlan[wireless LAN] ie the computer's ip on the (wifi router or network switch).
note: its not the public ip of the device and does not involve any external requests or packages or public apis.
The core idea is to parse the output of shell command: ipconfig
, or ifconfig on linux. we are using subprocess to acquire the output.
def wlan_ip():
import subprocess
result=subprocess.run('ipconfig',stdout=subprocess.PIPE,text=True).stdout.lower()
scan=0
for i in result.split('\n'):
if 'wireless' in i: #use "wireless" or wireless adapters and "ethernet" for wired connections
scan=1
if scan:
if 'ipv4' in i:
return i.split(':')[1].strip()
print(wlan_ip())
this is what happens after CMD:'ipconfig' :
we get this output, we captured it in python using subprocess output.
C:\Users\dell>ipconfig
Wireless LAN adapter Wi-Fi:
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::f485:4a6a:e7d5:1b1c%4
IPv4 Address. . . . . . . . . . . : 192.168.0.131
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.0.1
and we parsed the string in python, in a manner that selects the wireless adapter's ip on current network.
scan
and replacing three if statements by only one: if 'wireless' in i and 'ipv4' in i:
–
Rollicking 'wireless' and 'ipv4'
simultaneously. have you tried btw? i have tried yours and output was None
. –
Criswell You can do this easily on modern *NIX systems that have the iproute2
utility by calling it via subprocess.run()
as you can output in JSON with the -j
switch and then use the json.loads()
module and method to convert that to a python data structure. The following code displays the first non loopback IP address.
import subprocess
import json
ip = json.loads(subprocess.run('ip -j a'.split(),capture_output=True).stdout.decode())[1]['addr_info'][0]['local']
print(ip)
Alternativly if you had multiple IP's and wanted to find the IP that would be used to connect to a specific destination you could use ip -j route get 8.8.8.8
like this:
import subprocess
import json
ip = json.loads(subprocess.run('ip -j route get 8.8.8.8'.split(),capture_output=True).stdout.decode())[0]['prefsrc']
print(ip)
If your looking for all IP addresses you can iterate through the list of dictionaries returned by ip -j a
import subprocess
import json
list_of_dicts = json.loads(subprocess.run('ip -j a'.split(),capture_output=True).stdout.decode())
for interface in list_of_dicts:
try:print(f"Interface: {interface['ifname']:10} IP: {interface['addr_info'][0]['local']}")
except:pass
Here is a solution based fatal_error’s answer, but that doesn't rely on a try-except
statement.
Tested on macOS, Raspbian OS and Windows 11.
Returns 127.0.0.1
if there is no network connection.
import socket
def get_ip():
"""
Idea from https://mcmap.net/q/63357/-finding-local-ip-addresses-using-python-39-s-stdlib
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0)
# Doesn’t even have to be reachable.
s.connect_ex(("10.254.254.254", 1))
ip = s.getsockname()[0]
ip = "127.0.0.1" if ip == "0.0.0.0" else ip
s.close()
return ip
IP = get_ip()
print(IP)
pyroute2 is a great library that can be used to obtain not just ip addresses but also gateway information and other useful information. The following code can obtain the ipv4 address of any interface.
from pyroute2 import IPRoute
ip = IPRoute()
def get_ipv4_address(intf):
return dict(ip.get_addr(label=intf)[0]['attrs'])['IFA_LOCAL']
print(get_ipv4_address('eth0'))
Simple yet sweet!
def getip():
import socket
hostname= socket.gethostname()
ip=socket.gethostbyname(hostname)
return(ip)
This is very similar to previously posted answers, but I could not find any with this usage of calls. This is what I use for ipv4. For ipv6 change the '.' in to ':' in
import socket
print next(i[4][0] for i in socket.getaddrinfo(
socket.gethostname(), 80) if '127.' not in i[4][0] and '.' in i[4][0]);"
I settled for using the service and/or API of ipfy: https://www.ipify.org.
#!/usr/bin/env python3
from urllib.request import urlopen
def public_ip():
data = urlopen('https://api.ipify.org').read()
return str(data, encoding='utf-8')
print(public_ip())
The response can also be obtained in JSON and JSONP formats.
There's an ipify Python library on Github.
import socket
print(socket.gethostbyname(socket.getfqdn()))
@fatal_error solution should be the accepted answer! this is an implementation of his solution in nodejs in case people need it:
const dgram = require('dgram');
async function get_local_ip() {
const s = new dgram.createSocket('udp4');
return new Promise((resolve, reject) => {
try {
s.connect(1, '8.8.8.8', function () {
const ip = s.address();
s.close();
resolve(ip.address)
});
} catch (e) {
console.error(e);
s.close();
reject(e);
}
})
}
© 2022 - 2024 — McMap. All rights reserved.
ifconfig -a
and use the output from there... – Westleighip addr
is far more suitable (and easier to parse, to boot). – Norlandbind
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. – Auditorium