#!/usr/bin/python -u import sys, os, time import random class DNSLookup(object): """Handle PowerDNS pipe-backend domain name lookups.""" ttl = 30 def __init__(self, query): """parse DNS query and produce lookup result. query: a sequence containing the DNS query as per PowerDNS manual appendix A: http://downloads.powerdns.com/documentation/html/backends-detail.html#PIPEBACKEND-PROTOCOL """ (_type, qname, qclass, qtype, _id, ip) = query self.has_result = False # has a DNS query response qname_lower = qname.lower() """List of servers to round-robin""" servers = ['192.168.1.201','192.168.1.202'] server = random.choice(servers) self.results = [] if (qtype == 'A' or qtype == 'ANY') and qname_lower == 'test.domain.org': self.results.append('DATA\t%s\t%s\tA\t%d\t-1\t%s' % (qname, qclass, DNSLookup.ttl, server)) self.has_result = True elif qtype == 'SOA' and qname_lower == 'test.domain.org': self.results.append('DATA\t%s\t%s\t%s\t3600\t-1\tns1.test.soa\tadmin.test.soa\t2014032110\t10800\t3600\t604800\t3600' % (qname, qclass, qtype)) self.has_result = True def str_result(self): """return string result suitable for pipe-backend output to PowerDNS.""" if self.has_result: return '\n'.join(self.results) else: return '' class Logger(object): def __init__(self): pid = os.getpid() self.logfile = '/tmp/backend.log' """self.logfile = '/tmp/backend-%d.log' % pid""" def write(self, msg): logline = '%s|%s\n' % (time.asctime(), msg) f = file(self.logfile, 'a') f.write(logline) f.close() def debug_log(msg): logger.write(msg) class PowerDNSbackend(object): """The main PowerDNS pipe backend process.""" def __init__(self, filein, fileout): """initialise and run PowerDNS pipe backend process.""" self.filein = filein self.fileout = fileout self._process_requests() # main program loop def _process_requests(self): """main program loop""" first_time = True while 1: rawline = self.filein.readline() if rawline == '': debug_log('EOF') return # EOF detected line = rawline.rstrip() debug_log('received from pdns:%s' % line) if first_time: if line == 'HELO\t1': self._fprint('OK\tPython backend firing up') else: self._fprint('FAIL') debug_log('HELO input not received - execution aborted') rawline = self.filein.readline() # as per docs - read another line before aborting debug_log('calling sys.exit()') sys.exit(1) first_time = False else: query = line.split('\t') if len(query) != 6: self._fprint('LOG\tPowerDNS sent unparseable line') self._fprint('FAIL') else: debug_log('Performing DNSLookup(%s)' % repr(query)) lookup = DNSLookup(query) if lookup.has_result: pdns_result = lookup.str_result() self._fprint(pdns_result) debug_log('DNSLookup result(%s)' % pdns_result) self._fprint('END') def _fprint(self, message): """Print the given message with newline and flushing.""" self.fileout.write(message + '\n') self.fileout.flush() debug_log('sent to pdns:%s' % message) if __name__ == '__main__': logger = Logger() infile = sys.stdin #sys.stdout.close() #outfile = os.fdopen(1, 'w', 1) outfile = sys.stdout try: PowerDNSbackend(infile, outfile) except: debug_log('execution failure:' + str(sys.exc_info()[0])) raise