TODO
import sys
import os
import random
import string
import re
ZONE_SERVER = {}
ZONE_KEY = {}
SERVER_KEY = {}
TTL_DEFAULT = 3600
NSUPDATE_PATH = "/usr/bin/nsupdate"
ZONE_SERVER['default'] = "127.0.0.1"
SERVER_KEY['127.0.0.1'] = "/var/named/named.keys"
_rnd_chars = string.ascii_letters+string.digits
_rnd_chars_len = len(_rnd_chars)
def rndstr(len):
retval = ""
while len > 0:
retval += _rnd_chars[random.randint(0, _rnd_chars_len-1)]
len -= 1
return retval
def mktmpsomething(prefix, randchars, createfunc):
old_umask = os.umask(0077)
tries = 5
while tries > 0:
dirname = prefix + rndstr(randchars)
try:
createfunc(dirname)
break
except OSError, e:
if e.errno != errno.EEXIST:
os.umask(old_umask)
raise
tries -= 1
os.umask(old_umask)
return dirname
def mktmpdir(prefix = "/tmp/tmpdir-", randchars = 10):
return mktmpsomething(prefix, randchars, os.mkdir)
def mktmpfile(prefix = "/tmp/tmpfile-", randchars = 20):
createfunc = lambda filename : os.close(os.open(filename, os.O_CREAT | os.O_EXCL))
return mktmpsomething(prefix, randchars, createfunc)
def parse_key(key_file):
try:
key = open(key_file, "r").read()
pat = re.compile('key\s+(\w+)\s*{.*secret\s+[\'"]([^\'"]+)[\'"]', re.DOTALL | re.MULTILINE)
result = ":".join(pat.search(key).groups())
return result
except Exception, e:
sys.stderr.write("Can parse a key from %s: %s\n" % (key_file, e))
sys.exit(1)
def run_nsupdate(zone, args_in, mode):
"""
run_nsupdate(zone, args, mode)
zone is either forward or reverse DNS zone
args dict must have 'hostfqdn' and 'ipv4' members
mode is either 'forward' or 'reverse'
"""
args = args_in.copy()
args['zone'] = zone
args['tmpfilename'] = mktmpfile()
tmpfile = open(args['tmpfilename'], "w")
args['server'] = None
if ZONE_SERVER.has_key(zone):
args['server'] = ZONE_SERVER[zone]
elif ZONE_SERVER.has_key('default'):
args['server'] = ZONE_SERVER['default']
args['key'] = None
args['key_param'] = None
if ZONE_KEY.has_key(zone):
args['key'] = ZONE_KEY[zone]
elif SERVER_KEY.has_key(args['server']):
args['key'] = SERVER_KEY[args['server']]
if args['key']:
if os.path.isfile(args['key']):
args['key'] = parse_key(args['key'])
args['key_param'] = "-y"
if args['server']:
tmpfile.write("server %(server)s\n" % args)
tmpfile.write("zone %(zone)s\n" % args)
if mode == 'forward':
tmpfile.write("update delete %(hostfqdn)s.\n" % args)
tmpfile.write("update add %(hostfqdn)s. %(ttl)s IN A %(ipv4)s\n" % args)
elif mode == 'reverse':
tmpfile.write("update delete %(reverse_ipv4)s.\n" % args)
tmpfile.write("update add %(reverse_ipv4)s. %(ttl)s IN PTR %(hostfqdn)s.\n" % args)
tmpfile.write("show\n")
tmpfile.write("send\n")
tmpfile.close()
args['key_arg'] = args['key'] and "%(key_param)s %(key)s" % args or ""
command = "%(nsupdate)s %(key_arg)s %(tmpfilename)s" % args
print "Command: ", command
ret = os.system(command)
os.remove(args['tmpfilename'])
if __name__ == "__main__":
if len(sys.argv) < 3:
sys.stderr.write("Usage: %s <hostfqdn> <ipv4-addr>\n" % sys.argv[0])
sys.stderr.write("E.g.: %s server.example.net 192.0.2.1\n" % sys.argv[0])
sys.exit(1)
hostfqdn = sys.argv[1]
ipv4 = sys.argv[2]
host_parts = hostfqdn.split(".", 1)
ipv4_parts = ipv4.split(".")
if len(host_parts) != 2:
sys.stderr.write("Hostname '%s' is not fully qualified. Append your domain please.\n" % hostfqdn)
sys.exit(1)
if len(ipv4_parts) != 4:
sys.stderr.write("Invalid IPv4 address: %s\n" % ipv4)
sys.exit(1)
try:
ipv4_parts = [int(nibble) for nibble in ipv4_parts]
except ValueError:
sys.stderr.write("Invalid IPv4 address: %s\n" % ipv4)
sys.exit(1)
zone_fwd = host_parts[1]
zone_rev = "%d.%d.%d.in-addr.arpa" % (ipv4_parts[2], ipv4_parts[1], ipv4_parts[0])
args = {}
args['hostfqdn'] = hostfqdn
args['host'] = host_parts[1]
args['ipv4'] = ipv4
args['reverse_ipv4'] = "%d.%s" % (ipv4_parts[3], zone_rev)
args['ttl'] = TTL_DEFAULT
args['nsupdate'] = NSUPDATE_PATH
run_nsupdate(zone_fwd, args, 'forward')
run_nsupdate(zone_rev, args, 'reverse')