I recently came across a requirement in a project where I had to, in Python, programmatically extract all available public IPs on available interfaces on the machine the code would run. I looked around and settled with the following snippet of code that uses the built-in, standard socket
Python module:
import socket
ip_list = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")]
While this piece of code does find a public IP listening on any of the available interfaces, its restriction lies in not being able to return all public IPs on interfaces: It gives back just one IP.
This wasn’t clearly sufficient. I looked around again, and this time, found a third-party Python module called pynetinfo. This module could make possible working with different network device settings.
I rearranged the code around pynetinfo
and produced this:
def get_inet_ips():
try:
import netinfo
except ImportError:
return None
else:
inetIPs = []
for interface in netinfo.list_active_devs():
if not interface.startswith('lo'):
ip = netinfo.get_ip(interface)
inetIPs.append(ip)
return inetIPs
The code above loops through all available and active interfaces on the system, fetching and storing their IP in a simple datastructure. That got me all of the IPs available to a machine, excluding the loopback one, which the code was set to discard.
But that wasn’t it. There was a slight problem. Not all the active interfaces on the system had public IPs. Some had private, local LAN IPs in the 192.168.0.0/16
and 10.0.0.0/8
subnets. The code above was returning all the IPs it could find, including public and private ones.
I then found the netaddr third-party Python module which provided a Pythonic means of manipulating network addresses. I modified my code to use the netaddr
module and got the following to boot with:
def get_inet_ips():
try:
import netinfo
from netaddr import IPAddress, AddrFormatError
except ImportError:
return None
else:
inetIPs = []
for interface in netinfo.list_active_devs():
if not interface.startswith('lo'):
ip = netinfo.get_ip(interface)
try:
ip_address = IPAddress(ip)
except AddrFormatError:
continue
else:
# If the IP is not private, use it.
if not ip_address.is_private():
inetIPs.append(ip)
return inetIPs
The netaddr.IPAddress.is_private()
method in the code above determines whether the given IP is part of any of the defined private networks.
Admittedly, there is much room for improvement in the code above. I can only hope that if it doesn’t help, then at the very least it serves as an interesting read.
Pingback: Get all public interface IPs on a system using Python | Tea Break