Python - Get localhost IP [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding local IP addresses using Python's stdlib
To get my localhost IP address I do socket.gethostbyname(socket.gethostname()). But it gives me the answer 127.0.0.1.
If I do an_existing_socket.getsockname()[0] I get the answer 0.0.0.0.
I need my 'real' ip address (for instance 192.168.x.x) to modify a configuration file. How could I get it?

I generally use this code:
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, struct.pack('256s',
ifname[:15]))[20:24])
def get_lan_ip():
ip = socket.gethostbyname(socket.gethostname())
if ip.startswith("127.") and os.name != "nt":
interfaces = [
"eth0",
"eth1",
"eth2",
"wlan0",
"wlan1",
"wifi0",
"ath0",
"ath1",
"ppp0",
]
for ifname in interfaces:
try:
ip = get_interface_ip(ifname)
break
except IOError:
pass
return ip
I don't know it's origin, but it works on Linux/Windows.
Edit:
This code is used by smerlin in this stackoverflow question.

There is a nifty module you can use. Its called netifaces. Just do a pip install netifaces into a virtualenv for testing and try the following code:
import netifaces
interfaces = netifaces.interfaces()
for i in interfaces:
if i == 'lo':
continue
iface = netifaces.ifaddresses(i).get(netifaces.AF_INET)
if iface != None:
for j in iface:
print j['addr']
It all depends on your environment. If you only have one interface with one IP address attached to it, you can simply do:
netifaces.ifaddresses('eth0')[netifaces.AF_INET][0]['addr']
If you are behind a NAT and want to know your public IP address, you can use something like:
import urllib2
ret = urllib2.urlopen('https://icanhazip.com/')
print ret.read()
Hope this helps.

Related

How to get local ip address python?

There's a code I found in internet that says it gives my machines local network IP address:
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
but the IP it returns is 192.168.94.2 but my IP address in WIFI network is actually 192.168.1.107
How can I only get wifi network local IP address with only python?
I want it to work for windows,linux and macos.
You can use this code:
import socket
hostname = socket.getfqdn()
print("IP Address:",socket.gethostbyname_ex(hostname)[2][1])
or this to get public ip:
import requests
import json
print(json.loads(requests.get("https://ip.seeip.org/jsonip?").text)["ip"])
Here's code from the whatismyip Python module that can grab it from public websites:
import urllib.request
IP_WEBSITES = (
'https://ipinfo.io/ip',
'https://ipecho.net/plain',
'https://api.ipify.org',
'https://ipaddr.site',
'https://icanhazip.com',
'https://ident.me',
'https://curlmyip.net',
)
def getIp():
for ipWebsite in IP_WEBSITES:
try:
response = urllib.request.urlopen(ipWebsite)
charsets = response.info().get_charsets()
if len(charsets) == 0 or charsets[0] is None:
charset = 'utf-8' # Use utf-8 by default
else:
charset = charsets[0]
userIp = response.read().decode(charset).strip()
return userIp
except:
pass # Network error, just continue on to next website.
# Either all of the websites are down or returned invalid response
# (unlikely) or you are disconnected from the internet.
return None
print(getIp())
Or you can install pip install whatismyip and then call whatismyip.whatismyip().

Socket.py has no attribute AF_INET

I am trying to create a simple HTTP Client and I'm having trouble creating a simple socket. I use PyCharm and it highlights the AF_INET attribute of socket.py as non-existent and my script also crashes at runtime when it tries to get the AF_INET property. I checked my imports and I'm sure I have them right. Thanks!
import re
import socket
def getAddress():
address = input('Please enter a http address and a port (example: http://httpbin.org):\n')
parseAddress(address)
def parseAddress(address):
urlMatch = re.compile(r'^(.*:)//([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$')
searchResult = urlMatch.match(address)
host = searchResult.group(2)
port = '80'
portTest = searchResult.group(3)
if portTest is not None:
port = portTest.replace(':', '')
connectToServer(host, port)
def connectToServer(host, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#s.bind((host, port))
#s.send('HTTP REQUEST')
#response = s.recv()
#print(response)
I also checked for any files named socket.py and there aren't any in my project structure. Also when I ctrl+click the socket import it points me to the right file in the Python install folder :(

Python socket gethostbyname() returns only one IP address

I'm doing some simple experiments using Python socket, where I've a HOSTNAME which resolves with two IP addresses but when I use, socket.gethostbyname('demo.sample.com') I'm getting only one IP address. Why is it showing that way? Is there any other way I can get multiple IP addresses?
EDIT - 1
I got it guys, instead of gethostbyname('demo.sample.com') I tried gethostbyname_ex('demo.sample.com') It gives the result as I expected.
From the documentation it is visible that:
gethostbyname returns only a single IPv4 address. And to cite: See gethostbyname_ex() for a more complete interface.
gethostbyname_ex will return multiple IPv4 address, but check out the usage. And to cite: gethostbyname_ex() does not support IPv6 name resolution, and getaddrinfo() should be used instead for IPv4/v6 dual stack support.
getaddrinfo will return all IPv4 and IPv6 addresses, but check out the usage.
I found a solution here, which returns the internal network IP:
import socket
def ip_addr(hostIP=None):
if hostIP is None or hostIP == 'auto':
hostIP = 'ip'
if hostIP == 'dns':
hostIP = socket.getfqdn()
elif hostIP == 'ip':
from socket import gaierror
try:
hostIP = socket.gethostbyname(socket.getfqdn())
except gaierror:
logger.warn('gethostbyname(socket.getfqdn()) failed... trying on hostname()')
hostIP = socket.gethostbyname(socket.gethostname())
if hostIP.startswith("127."):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# doesn't have to be reachable
s.connect(('10.255.255.255', 1))
hostIP = s.getsockname()[0]
return hostIP
if __name__ == '__main__':
print('%s' % ip_addr())

Checking for IP addresses

Are there any existing libraries to parse a string as an ipv4 or ipv6 address, or at least identify whether a string is an IP address (of either sort)?
Yes, there is ipaddr module, that can you help to check if a string is a IPv4/IPv6 address, and to detect its version.
import ipaddr
import sys
try:
ip = ipaddr.IPAddress(sys.argv[1])
print '%s is a correct IP%s address.' % (ip, ip.version)
except ValueError:
print 'address/netmask is invalid: %s' % sys.argv[1]
except:
print 'Usage : %s ip' % sys.argv[0]
But this is not a standard module, so it is not always possible to use it.
You also try using the standard socket module:
import socket
try:
socket.inet_aton(addr)
print "ipv4 address"
except socket.error:
print "not ipv4 address"
For IPv6 addresses you must use socket.inet_pton(socket.AF_INET6, address).
I also want to note, that inet_aton will try to convert (and really convert it) addresses like 10, 127 and so on, which do not look like IP addresses.
For IPv4, you can use
socket.inet_aton(some_string)
If it throws an exception, some_string is not a valid ip address
For IPv6, you can use:
socket.inet_pton(socket.AF_INET6, some_string)
Again, it throws an exception, if some_string is not a valid address.
IPv4 + IPv6 solution relying only on standard library. Returns 4 or 6 or raises ValueError.
try:
# Python 3.3+
import ipaddress
def ip_kind(addr):
return ipaddress.ip_address(addr).version
except ImportError:
# Fallback
import socket
def ip_kind(addr):
try:
socket.inet_aton(addr)
return 4
except socket.error: pass
try:
socket.inet_pton(socket.AF_INET6, addr)
return 6
except socket.error: pass
raise ValueError(addr)
You can use the netaddr library. It has valid_ipv4/valid_ipv6 methods:
import netaddr
if netaddr.valid_ipv4(str_ip) is True:
print("IP is IPv4")
else:
if netaddr.valid_ipv6(str_ip) is True:
print("IP is IPv6")
Try
apt-get install python-ipaddr
or get the source code from here
I prefer ip_interface because it handles situations both with and without prefix mask, for example, both "10.1.1.1/24" as well as simply "10.1.1.1". Needless to say, works for both v4 as well as v6
from ipaddress import ip_interface
ip_interface("10.1.1.1/24").ip
ip_interface("10.1.1.1/24").ip.version
ip_interface("10.1.1.1").ip
ip_interface("10.1.1.1").ip.version
ipaddr -- Google's IP address manipulation package.
Note that a proposal to include a revised version of the package in the Python standard library has recently been accepted (see PEP 3144).
If you know for sure that the address is valid and only trying to decide whether it is ipv4 or ipv6, wouldn't it be sufficient to do just:
if ":" in address:
print("Ipv6")
else:
print("Ipv4")

Find my Ip address in python [duplicate]

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?
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.

Categories

Resources