#!/usr/bin/python """Dynamic DNS script. Expects URLs from routers in the form http://dyndns.colgarra.priv.at/nic/update?hostname=&myip= """ import os import re import cgi from subprocess import call import ipaddr # Configuration DEBUG = False # Just for debugging: if DEBUG: import cgitb cgitb.enable() # Base class for our exceptions class DynDnsError(Exception): pass class HostnameError(DynDnsError): returncode = 'notfqdn' class HostnameMissing(HostnameError): pass class PasswordWrong(HostnameError): pass class MyipError(DynDnsError): returncode = 'badip' # not documented at dyn.com class MyipMissing(MyipError): pass class MyipInvalid(MyipError): pass class OfflineInvalid(DynDnsError): returncode = 'badparam' # not documented at dyn.com class NsupdateError(DynDnsError): returncode = 'nohost' fields = cgi.FieldStorage() # the following fields are supported by most dyndns providers # if a parameter is not provided, the .getvalue method returns None hostname = fields.getvalue('hostname') myip = fields.getvalue('myip') wildcard = fields.getvalue('wildcard') mx = fields.getvalue('mx') backmx = fields.getvalue('backmx') offline = fields.getvalue('offline') system = fields.getvalue('system') url = fields.getvalue('url') try: # check hostname if hostname is None: raise HostnameMissing() if re.match(r'[-0-9a-z]+(\.[-0-9a-z]+)*$', hostname) is None: raise HostnameInvalid() # strip zone hostname = hostname.strip() # check offline if offline is None or offline.lower() == 'no': offline = False elif offline.lower() == 'yes': offline = True else: raise OfflineInvalid() # check IP address if not offline: if myip is None: # try HTTP_X_FORWARDED_FOR myip = os.environ.get('HTTP_X_FORWARDED_FOR') if not myip: # empty string if not present # try REMOTE_ADDR myip = os.environ.get('REMOTE_ADDR') if not myip: # empty string if not present raise MyipMissing() if not myip is None: try: ipaddr.IPAddress(myip) # throws an exception if the IP address is not valid except ValueError: raise MyipInvalid() # update bind call_params = ['sudo', 'tdyndns_update'] if offline: call_params.append('--delete') if myip is not None: call_params.extend(['--ip', myip]) call_params.append(hostname) retcode = call(call_params) if retcode != 0: raise NsupdateError() # return success print "Content-Type: text/html" print print "good" # Note: we should return 'nochg' in case the IP has not changed, however we don't know yet. except DynDnsError as error: print "Content-Type: text/html" print "Status: 200 OK" print print error.returncode