Working Around Dynamic IPs

Uncategorized

It took me a while, but I think I’ve finally figured out how to automatically update the IP address of your domain name.

The script I recommend at the end of the page will have your domain password in it! You should protect dat noise. See my post on basic passwords for Apache servers.

Recap

Let’s review the context. I set up a website server on my home desktop, and then I set up a script that emails me when my IP changes. I had to do this because I have a normal internet subscription, so my ISP might change my IP address occasionally.

That was fine because I didn’t have a domain name. So if I wanted to access my website from the Internet, I checked my emails to see what my home desktop’s IP address was most recently, and I plugged that number into my browser.

Along Came an Angel

Thereafter, an amazing human being bought me my very own domain name, absentstills.com. The domain name is operated by a company called eNom. I went to the eNom configuration page and set it so that http://www.absentstills.com, abc.absentstills.com, and wwx.absentstills.com all point to my IP address.

Wonderful! Now typing in absentstills.com from anywhere in the world brought you to my website.

The problem still remained, however, that anytime my ISP changed my IP address, I would have to go manually re-configure the settings at eNom’s website to point to my new IP address. We can do better than that.

Dynamic DNS IP Updating is a PITA

What should be a really simple task is actually surprisingly annoying.

In order to make this work, the company hosting your domain name has to provide this service. Luckily, eNom does. The idea is that you submit commands to a website called http://dynamic.name-services.com/ in the extension of the URL. For instance, if you enter into your browser the URL

https://dynamic.name-services.com/interface.asp?command=setdnshost&zone=your-domain-name.com&domainpassword=my-domain-password&address=192.0.123.56

then you are asking eNom to ‘setdnshost’ of ‘your-domain-name.com’ to ‘192.0.123.56’. After this command is processed, your-domain-name.com will point to whatever is at the IP address 192.0.123.56.

Sounds easy enough. In fact, Sean Schertell over at DataFly.Net already concocted a python script to do this. It’s pretty easy to use, and his post describes the instructions quite well.

The only caveat I have is to change the ip_check_url to http://ifconfig.me/ip, since the one he uses doesn’t seem to work anymore (the post is a few years old). Since ifconfig can be intermittent in responding to your requests, I put the update request into a while-try-except loop:

    # Compare our recently saved IP to our current real IP
    recent_ip = read_file(ip_text_file)

    # Keep trying until ifconfig works
    current_ip = ""
    while True:
        try:
            current_ip = read_url(ip_check_url)
#            print "%s" % current_ip
            break
        except:
            print "IfConfig Failed, Trying Again"

So that’s it, right? What’s so hard about all this?

Well, when I set up the script and ran it, nothing really worked. Except it did. Let me explain.

It seems that the issue lies in delays between your script running, eNom receiving the message, eNom actually updating your IP address, and your updated IP address propagating through the Internet.

So let’s say you try to debug the program. You manually set you IP address incorrectly at access.enom.com and try to reset it using your script. The script tells you that the command was submitted correctly, but your eNom configuration page still shows the incorrect IP address.

This is because eNom hasn’t processed your request yet, even though it has received it successfully. Of course, if you don’t know this, then you’ll spend the next half hour debugging and trying to fix your script, or you’ll give up and reset the IP manually. And then nothing will work and you will get frustrated. And then, eventually, the original command will get processed, and everything will work for no apparent reason.

So to save you this trouble, here is my modified version of Sean’s script. If I notice that it isn’t working as expected, I will update the code here. Don’t try and debug it yourself unless you have a lot of patience, or you know something I don’t.

#!/usr/local/bin/python

##############################################
# update_enom.py by: Sean Schertell, DataFly.Net
# Modified by Martin Magill, 17/01/2015
# ------------------------
# A simple python script to update your dynamic DNS IP for domains registered with Enom.
# 
# Requirements:
# - You have a domain registered with Enom, nameservers are set to Enom's (true by default), and you've set a domain password
# - Your client machine runs python
# - You know how to configure a cron job to periodically run this script (every 5 mins recommended)
#
# Cron example to run every 5 minutes, and log output messages:
# */5 * * * * python /var/www/update_ip.py >> /var/www/ip_log.txt
# Access your cron jobs by sudo crontab -e, and then add that line to the end of the file.

##############################################
# Configure
##############################################

ip_check_url = 'http://ifconfig.me/ip'   # URL which returns current IP as text only
ip_text_file = '/var/www/protected/ip.txt'         # Text file to store recent ip file
domain       = 'www.your-domain-name.com'        # Enom registered domain to be altered
password     = 'your-password'           # Domain password

##############################################

import urllib2, os

def read_url(url):
    return urllib2.urlopen(url).read()

def read_file(path):
    return open(path, 'r').read()

def parse_enom_response(enom_response):
    enom_response_dict = {}
    for param in  enom_response.split('\n'):
        if '=' in param:
            try:
                key, val = param.split('=')
                enom_response_dict[key] = val.strip()
            except: pass
    return enom_response_dict

def save_new_ip(current_ip):
    return open(ip_text_file, 'w').write(current_ip)

def update_enom():    
    # First, ensure that the ip_text_file exists
    if not os.path.exists(ip_text_file):
        open(ip_text_file, 'w').close() 

    # Compare our recently saved IP to our current real IP
    recent_ip = read_file(ip_text_file)

    # Keep trying until ifconfig works
    current_ip = ""
    while True:
        try:
            current_ip = read_url(ip_check_url)
#            print "%s" % current_ip
            break
        except:
            print "IfConfig Failed, Trying Again"

    # Do they match?
    if recent_ip == current_ip:
        print "URLs match"
        return # IP address has not changed since last update

    # No match, so let's try to update Enom
    settings = {'domain': domain, 'password': password, 'current_ip': current_ip}
    enom_update_url = 'https://dynamic.name-services.com/interface.asp?command=setdnshost&zone=%(domain)s&domainpassword=%(password)s&address=%(current_ip)s' % settings
#    print "%s" % enom_update_url
    enom_response = read_url(enom_update_url)

    # Any errors?
    response_vals = parse_enom_response(enom_response)

    if not response_vals['ErrCount'] == '0':    
        raise Exception('*** FAILED TO UPDATE! Here is the response from Enom:\n' + enom_response)

    # Okay then, lets save the new ip
    save_new_ip(current_ip)
    return    
##############################################

update_enom()
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s