Get Public IP address from Shell or Python

Both the shell and Python methods get public IPv4 and IPv6 addresses. This is good for checking a VPN by verifying the computer IP is in the organization’s VPN IP address range. These scripts use the “reflector” method, which I have found to be more reliable on complex networks.

I typically use the shell method.

Shell

Optionally, specify the network interface with curl --interface eth0 option.

Bash shell script “getIP.sh” 

url=('https://ident.me' 'https://api.ipify.org')

for u in ${url[@]}; do
  curl -6 -s -m 2 $u && break
done

for u in ${url[@]}; do
  curl -4 -s -m 2 $u && break
done

Python

Python script “getIP.py 

#!/usr/bin/env python
"""
gets interface IPv4 and IPv6 public addresses using libCURL
This uses the "reflector" method, which I feel is more reliable for finding public-facing IP addresses,
WITH THE CAVEAT that man-in-the-middle, etc. attacks can defeat the reflector method.
"""
from ipaddress import ip_address
import pycurl
from io import BytesIO

urls = ['https://ident.me', # ipv6 and ipv4
        'https://api.ipify.org'] # ipv4 only
length=45 #http://stackoverflow.com/questions/166132/maximum-length-of-the-textual-representation-of-an-ipv6-address

def getip(interface=None):
    for url in urls:
        addr = []
        for ipv in (pycurl.IPRESOLVE_V4,pycurl.IPRESOLVE_V6):
            buffer = BytesIO() # must clear like this
            C = pycurl.Curl()
            if interface:
                C.setopt(pycurl.INTERFACE,interface)
            C.setopt(C.URL, url)
            C.setopt(pycurl.IPRESOLVE, ipv)
            C.setopt(C.WRITEDATA, buffer)
            try:
                C.perform()
                result = buffer.getvalue()
                try: #validate response
                    addr.append(ip_address(result.decode('utf8')))
                except ValueError:
                    pass
            except pycurl.error:
                pass
            finally:
                C.close()

        if len(addr)>1: #IPv4 and IPv6 found
            break

    return addr

if __name__ == '__main__':
    import signal
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    
    from argparse import ArgumentParser
    p = ArgumentParser()
    p.add_argument('-i','--iface',help='network interface to use')
    p = p.parse_args()

    addr = getip(p.iface)
    print(addr)

Leave a Comment