1 #!/usr/bin/env python
   2 import sys
   3 import time
   4 import datetime
   5 import threading
   6 import traceback
   7 import SocketServer
   8 from sets import Set
   9 
  10 import dnslib
  11 from dnslib import QTYPE, SOA, NS, A, AAAA, MX, CNAME
  12 from dnslib import DNSRecord, DNSHeader, RR, RCODE
  13 
  14 z = 'd.qmail.jp.'
  15 IP= '192.168.10.7'
  16 TTL = 60 * 5
  17 PORT = 5053
  18 #---------------- read zone -----------------------
  19 zone ={}  #Dict;  key is a domain name
  20           #value: Dict for rtype
  21                # value: RRSet
  22 
  23 zonetxt = open('zone.txt').read()
  24 print(zonetxt)
  25 print '-----'
  26 zonerr= RR.fromZone(zonetxt)
  27 for rr in zonerr:
  28   name = str(rr.rname)
  29   if not(name in zone) :
  30      zone[name] = {}   # make empty node
  31   if not(rr.rtype in zone[name]): 
  32      zone[name][rr.rtype] = Set([])  # empty query type
  33   zone[name][rr.rtype].add(rr)
  34 # -----
  35 for name in zone:
  36   print name, zone[name]
  37 print '-----'
  38 #-----
  39 for rrs in zone:
  40   print (zone[rrs])
  41 
  42 print '--------------------------------'
  43 
  44 rrs = zone[z]  # zone apex node
  45 if QTYPE.SOA in rrs:
  46    soa_record = rrs[QTYPE.SOA].pop()
  47 print 'SOA= ', soa_record
  48 
  49 #------
  50 IP= '192.168.10.7'
  51 TTL = 60 * 5
  52 PORT = 5053
  53 ServerIP = '192.168.10.7'
  54 
  55 def dns_response(packet):
  56     query = DNSRecord.parse(packet)
  57     print '--- query ---' 
  58     print query
  59     print '------------'
  60 
  61     reply = DNSRecord(DNSHeader(id=query.header.id, qr=1, aa=1), q=query.q)
  62     reply  #debug print
  63     qname = query.q.qname
  64     qtype = query.q.qtype
  65     qt = QTYPE[qtype]
  66     qn = str(qname).lower()
  67 
  68     if qn in zone :
  69        print zone[qn]
  70        if qtype in zone[qn]:
  71          for rr in zone[qn][qtype]: #rrset
  72            print 'found RRSet', rr
  73            reply.add_answer(rr)
  74        else:
  75          if QTYPE.CNAME in zone[qn] :
  76             print 'CNAME found.'
  77             print zone[qn][QTYPE.CNAME]
  78             for rr in zone[qn][QTYPE.CNAME]:
  79               reply.add_answer(RR(qname, QTYPE.CNAME, ttl=TTL, rdata=rr.rdata))
  80 
  81        #    reply.add_answer(RR(qname, QTYPE.NS, ttl=TTL, rdata=rdata)
  82        #NoData response here
  83        #    reply.add_auth(RR(D, QTYPE.NS, ttl=TTL, rdata=rdata))
  84     else:  # NXDomain
  85        if not (qn.endswith('.' + z)): return
  86        reply.add_auth(soa_record)
  87        #NoData response here may be
  88        reply.header.rcode = getattr(RCODE,'NXDOMAIN')
  89 
  90     print "---- Reply:\n", reply
  91     return reply.pack()
  92 
  93 
  94 class BaseRequestHandler(SocketServer.BaseRequestHandler):
  95 
  96     def get_data(self):
  97         raise NotImplementedError
  98 
  99     def send_data(self, data):
 100         raise NotImplementedError
 101 
 102     def handle(self):
 103         now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')
 104         print "\n\n%s request %s (%s %s):" % (self.__class__.__name__[:3], now, 
 105 self.client_address[0],
 106                                                self.client_address[1])
 107         try:
 108             data = self.get_data()
 109             print len(data), data.encode('hex')  # repr(data).replace('\\x', '')
 110 [1:-1]
 111             self.send_data(dns_response(data))
 112         except Exception:
 113             traceback.print_exc(file=sys.stderr)
 114 
 115 
 116 class UDPRequestHandler(BaseRequestHandler):
 117 
 118     def get_data(self):
 119         return self.request[0].strip()
 120 
 121     def send_data(self, data):
 122         return self.request[1].sendto(data, self.client_address)
 123 
 124 
 125 if __name__ == '__main__':
 126     print "Starting nameserver..."
 127 
 128     servers = [
 129         SocketServer.ThreadingUDPServer((ServerIP, PORT), UDPRequestHandler),
 130        # SocketServer.ThreadingTCPServer((ServerIP, PORT), TCPRequestHandler),
 131     ]
 132     for s in servers:
 133         thread = threading.Thread(target=s.serve_forever)  # that thread will st
 134 art one more thread for each request
 135         thread.daemon = True  # exit the server thread when the main thread term
 136 inates
 137         thread.start()
 138         print "%s server loop running in thread: %s" % (s.RequestHandlerClass.__
 139 name__[:3], thread.name)
 140 
 141     try:
 142         while 1:
 143             time.sleep(1)
 144             sys.stderr.flush()
 145             sys.stdout.flush()
 146 
 147     except KeyboardInterrupt:
 148         pass
 149     finally:
 150         for s in servers:
 151             s.shutdown()
 152