#!/usr/bin/python

"""
bindupdate - utility which reads the entries in /etc/hosts
and automatically reconfigures 'bind' to work with these
entries. End those gethostbyname() blues!

HOW TO USE - READ CAREFULLY!!!

 * Carefully edit the 3 variables below, then run
   this script as root.

 * Script will generate all the needed files, and stick an
   include statement into the main named.conf file.

Don't forget to restart bind each time you run this script.

Test it by typing 'host domainname' where 'domainname' is
one of your domains listed in /etc/hosts.

Credit, blame, donations, letterbombs etc to:
 David McNab <david@rebirthing.co.nz>

"""

# ABSOLUTE location of the main bind config file
bind_conffile = "/etc/bind/named.conf"

# A directory into which to write files derived from /etc/hosts
dir_prefix = "/etc/bind" # no trailing slash, please

# Prefix to prepend to generated filenames
fn_prefix = "ETCHOSTS"

# you shouldn't need to change anything below this line
# ----------------------------------------------------

import re
import os

# Suck up /etc/hosts

fd = open("/etc/hosts", "r")
hostsbuf = fd.read()
fd.close()

sp = re.compile("\s+")
hosts = hostsbuf.split("\n")

domains = {}

for i in hosts:
	if i != '' and i[0].isdigit():
		flds = sp.split(i)
		ip = flds.pop(0)
		for f in flds:
			if f and f != 'localhost':
				domains[f] = ip

#print domains

# Delete any old generated files
os.system("rm -f %s/%s_*" % (dir_prefix, fn_prefix))

# Create main include'd file, and populate with zone defs
fdZ = open("%s/%s_MYZONES" % (dir_prefix, fn_prefix), "w")
for d in domains:
	fdZ.write("zone \"%s\" {\n" % d)
	fdZ.write("  type master;\n")
	fdZ.write("  file \"%s/%s_%s\";\n" % (dir_prefix, fn_prefix, d))
	fdZ.write("};\n\n");

	# Create one file per /etc/hosts domain, and fill
	# it with bind's esoteric geek-assed syntax
	fdD = open("%s/%s_%s" % (dir_prefix, fn_prefix, d), "w")
	fdD.write("$TTL 604000\n")
	fdD.write("@ IN SOA %s. root.%s. (\n" % (d, d))
	fdD.write("  1       ; serial\n")
	fdD.write("  604800  ; refresh\n")
	fdD.write("  86400   ; retry\n")
	fdD.write("  2419200 ; expire\n")
	fdD.write("  604800  ; fail\n")
	fdD.write(")\n");
	fdD.write("@ IN NS %s.\n" % d)
	fdD.write("@ IN A %s\n" % domains[d])
	fdD.close()
	print "Added %s => %s" % (d, domains[d])

fdZ.close()

# Stick an include statement into main bind config
# file, if it's not there already

fdB = open(bind_conffile, "r")
fdBcont = fdB.readlines()
fdB.close()

incStmt = "include \"%s/%s_MYZONES\";" % (dir_prefix, fn_prefix)
incStmtLen = len(incStmt)

found = 0
for s in fdBcont:
	if s[0:incStmtLen] == incStmt:
		found = 1

if not found:
	# Stick an include statement into bind config file
	print "Adding include statement to %s" % bind_conffile
	fdB = open(bind_conffile, "a")
	fdB.write("\n\n// Include records derived from /etc/hosts by bindupdate utility\n")
	fdB.write("// Get your copy of bindupdate from www.freenet.org.nz/downloads/bindupdate.py\n")
	fdB.write(incStmt)
	fdB.write("\n")
	fdB.close()
