Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Discovering public IP programmatically

I'm behind a router, I need a simple command to discover my public ip (instead of googling what's my ip and clicking one the results)

Are there any standard protocols for this? I've heard about STUN but I don't know how can I use it?

P.S. I'm planning on writing a short python script to do it

like image 497
hasen Avatar asked Mar 05 '09 03:03

hasen


People also ask

How do I find public IP address programmatically?

getByIndex(int index) Get a network interface given its index. getByInetAddress(InetAddress addr) Convenience method to search for a network interface that has the specified Internet Protocol (IP) address bound to it. getByName(String name) Searches for the network interface with the specified name.


1 Answers

This may be the easiest way. Parse the output of the following commands:

  1. run a traceroute to find a router that is less than 3 hops out from your machine.
  2. run ping with the option to record the source route and parse the output. The first IP address in the recorded route is your public one.

For example, I am on a Windows machine, but the same idea should work from unix too.

> tracert -d www.yahoo.com  Tracing route to www-real.wa1.b.yahoo.com [69.147.76.15] over a maximum of 30 hops:    1    <1 ms    <1 ms    <1 ms  192.168.14.203   2     *        *        *     Request timed out.   3     8 ms     8 ms     9 ms  68.85.228.121   4     8 ms     8 ms     9 ms  68.86.165.234   5    10 ms     9 ms     9 ms  68.86.165.237   6    11 ms    10 ms    10 ms  68.86.165.242 

The 68.85.228.121 is a Comcast (my provider) router. We can ping that:

> ping -r 9 68.85.228.121 -n 1  Pinging 68.85.228.121 with 32 bytes of data:  Reply from 68.85.228.121: bytes=32 time=10ms TTL=253     Route: 66.176.38.51 ->            68.85.228.121 ->            68.85.228.121 ->            192.168.14.203 

Voila! The 66.176.38.51 is my public IP.

Python code to do this (hopefully works for py2 or py3):

#!/usr/bin/env python  def natIpAddr():   # Find next visible host out from us to the internet   hostList = []   resp, rc = execute("tracert -w 100 -h 3 -d 8.8.8.8") # Remove '-w 100 -h d' if this fails    for ln in resp.split('\n'):     if len(ln)>0 and ln[-1]=='\r': ln = ln[:-1]  # Remove trailing CR     if len(ln)==0: continue     tok = ln.strip().split(' ')[-1].split('.') # Does last token look like a dotted IP address?     if len(tok)!=4: continue     hostList.append('.'.join(tok))     if len(hostList)>1: break  # If we found a second host, bail        if len(hostList)<2:     print("!!tracert didn't work, try removing '-w 100 -h 3' options")     # Those options were to speed up tracert results    else:     resp, rc = execute("ping -r 9 "+hostList[1]+" -n 1")     ii = resp.find("Route: ")     if ii>0: return resp[ii+7:].split(' ')[0]   return none        def execute(cmd, showErr=True, returnStr=True):   import subprocess   if type(cmd)==str:     cmd = cmd.split(' ')   # Remove ' ' tokens caused by multiple spaces in str                cmd = [xx for xx in cmd if xx!='']   proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)   out, err = proc.communicate()   if type(out)==bytes:  # Needed for python 3 (stupid python)     out = out.decode()     try:       err = err.decode()     except Exception as ex:        err = "!!--"+str(type(ex))+"--!!"      if showErr and len(err)>0:     out += err   if returnStr and str(type(out))=="<type 'unicode'>":     # Trying to make 'out' be an ASCII string whether in py2 or py3, sigh.     out = out.encode()  # Convert UNICODE (u'xxx') to string   return out, proc.returncode   if __name__ == "__main__":   print("(This could take 30 sec)")   print(natIpAddr()) 

Use it from the command line (on Windows) or from a python program:

import natIpAddr myip = natIpAddr.natIpAddr() print(myip) 
like image 150
Carlos A. Ibarra Avatar answered Oct 14 '22 07:10

Carlos A. Ibarra