#!/usr/bin/python2.7 """Dynamic DNS script. Expects URLs from routers in the form https://info.colgarra.priv.at/dyndns/dyndns.py?username=&password=&hostname=&myip= """ import re import cgi import pwd from subprocess import call import ipaddr # Configuration PASSWORD = 'hygCithOrs5' ZONE = '.dyn.colgarra.priv.at' DEBUG = False # Just for debugging: if DEBUG: import cgitb cgitb.enable() fields = cgi.FieldStorage() # the following fields are supported by most dyndns providers # if a parameter is not provided, the .getvalue method returns None username = fields.getvalue('username') password = fields.getvalue('password') 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') # Base class for our exceptions class DynDnsError(Exception): pass class AuthError(DynDnsError): returncode = 'badauth' class UsernameMissing(AuthError): pass class UsernameInvalid(AuthError): pass class PasswordMissing(AuthError): pass class PasswordWrong(AuthError): pass class HostnameError(DynDnsError): returncode = 'notfqdn' class HostnameMissing(HostnameError): pass class PasswordWrong(HostnameError): pass class IpError(DynDnsError): returncode = 'badip' # not documented at dyn.com class IpMissing(IpError): pass class IpInvalid(IpError): pass try: # check username if username is None: raise UsernameMissing() try: user_info = pwd.getpwnam(username) except KeyError: raise UsernameInvalid() if user_info.pw_uid < 1000: raise UsernameInvalid() # check password if password is None: raise PasswordMissing() if password != PASSWORD: raise PasswordWrong() # 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() if hostname.endswith(ZONE): hostname = hostname[:-len(ZONE)] # check IP address if myip is None: raise IpMissing() try: ip = ipaddr.IPAddress(myip) # throws an exception if the IP address is not valid except ValueError: raise IpInvalid() if isinstance(ip, ipaddr.IPv4Address): iptype = 'A' elif isinstance(ip, ipaddr.IPv6Address): iptype = 'AAAA' else: raise IpInvalid() # should never happen # access granted print "Content-Type: text/html" print call(['sudo', '/usr/local/bin/nsupdate_dyndns', hostname, myip, iptype]) 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" print print error.returncode