A year or two ago when I first set up my old laptop as a linux server I created a script that logged into my router, parsed the external ip address, checked that against the ip address it got last time, and emailed me if they were different. That worked great for the intended purpose (telling me when the address of my server changed), but I was thinking recently that I could rewrite it to tell me whenever the external ip address of the computer changes, such as if someone stole one of my linux computers and booted it far enough for my cron job to be able to fire. That depends on the computer being connected to the internet when the script runs, but updating the script was interesting enough to be worth doing even if there’s very little chance of it being overly useful.
I’m building off of code I wrote a while ago, so the parts that work won’t have much commentary on what it took to write them.
Calling Home
The first (and most important part) is the script to notify you when it decides it needs to. I chose email because I expected it to be pretty easy (it was) and because always having an email in my inbox that contained the ip address of my server seemed useful.
A quick search on “python send email” turned up a docs.python.org page with the basics, so that’s might have been where I started. I wanted a general script that I could call from other places, but I didn’t want to include the login info for the server every time so I ended up with this script.
The username, password, and email address are obviously not actually all ‘*’s, but I didn’t particularly want to post my gmail info. The smtpuser
that my version of the script uses is everything before the @ in my gmail address, and the smtppass
has to be a valid password for your account, though interestingly it was willing to accept my last password (my password changed after I wrote the script and it still worked). Giving it an invalid password raised an exception at session.login(smtpuser, smtppass)
with a link to a gmail support page.
The documentation example I linked above used another library for setting up the body of the message, but joining the header lines I have with line breaks works too. The "", # extra line break
comment is a required blank line for it to parse correctly as an email.
Checking your IP
Once your script can notify you, it has to be able to tell when it needs to. My original script logged onto my router (a linksys), opened the status page, and parsed the external ip. That obviously depends on your computer being at home where it’s able to log into the router. A more general solution is to check a website for the ip address it sees you connecting from.
Since I have web hosting and wasn’t sure that sites like whatismyip would like being called regularly from a script I looked up the php to display the external ip of the requesting computer. I don’t really want my site to be hit be any random person looking for a machine-friendly ip address site, so it’s in a passworded section of my site, but here’s the html of my getip.php file:
<html><body> <?php echo $_SERVER['REMOTE_ADDR']; ?> </body></html>
Note: All block code formatting and syntax highlighting is done through code2html.
Since I’m fetching the ip address from an html page behind a password I had to find a way to have python log in. I ended up using urllib2:
uri = "http://192.168.1.1/" username = "********" password = "********" page = "http://192.168.1.1/Status_Router.asp" def get_ip() : pass_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm() pass_mgr.add_password(None, uri, username, password) auth_handler = urllib2.HTTPBasicAuthHandler(pass_mgr) opener = urllib2.build_opener(auth_handler) urllib2.install_opener(opener) handle = urllib2.urlopen(page) site_text = handle.read() match = re.search("var wan_ip = \"([\d\.]+)\";", site_text) #print match.group(1) my_ip = match.group(1) return (time.asctime(), my_ip)
The uri and regex in that snippet are for my linksys router. For the php code earlier in this post I’m matching on "([\d\.]+)