Python写的一个简单DNS服务器实例

因为突然有个邪恶的想法,想在自己的Android平板上面搭建一个DNS服务器,因为平板上之前安装过SL4A和Python的解释器,也想继续学学Python因此,就打算用Python实现了。

在Google上面找了一下,Python实现的DNS,没找到我所希望的答案,因此就决定自己来实现了。

现在所实现的没什么高深的,只是能够对A记录查询进行简单的匹配和回复。

实现的代码如下:

'''
Created on 2012-10-15

@author: RobinTang '''

import socketserver import struct

# DNS Query class SinDNSQuery:     def __init__(self, data):         i = 1         self.name = ''         while True:             d = data[i]             if d == 0:                 break;             if d < 32:                 self.name = self.name + '.'             else:                 self.name = self.name + chr(d)             i = i + 1         self.querybytes = data[0:i + 1]         (self.type, self.classify) = struct.unpack('>HH', data[i + 1:i + 5])         self.len = i + 5     def getbytes(self):         return self.querybytes + struct.pack('>HH', self.type, self.classify)

# DNS Answer RRS # this class is also can be use as Authority RRS or Additional RRS class SinDNSAnswer:     def __init__(self, ip):         self.name = 49164         self.type = 1         self.classify = 1         self.timetolive = 190         self.datalength = 4         self.ip = ip     def getbytes(self):         res = struct.pack('>HHHLH', self.name, self.type, self.classify, self.timetolive, self.datalength)         s = self.ip.split('.')         res = res + struct.pack('BBBB', int(s[0]), int(s[1]), int(s[2]), int(s[3]))         return res

# DNS frame # must initialized by a DNS query frame class SinDNSFrame:     def __init__(self, data):         (self.id, self.flags, self.quests, self.answers, self.author, self.addition) = struct.unpack('>HHHHHH', data[0:12])         self.query = SinDNSQuery(data[12:])     def getname(self):         return self.query.name     def setip(self, ip):         self.answer = SinDNSAnswer(ip)         self.answers = 1         self.flags = 33152     def getbytes(self):         res = struct.pack('>HHHHHH', self.id, self.flags, self.quests, self.answers, self.author, self.addition)         res = res + self.query.getbytes()         if self.answers != 0:             res = res + self.answer.getbytes()         return res # A UDPHandler to handle DNS query class SinDNSUDPHandler(socketserver.BaseRequestHandler):     def handle(self):         data = self.request[0].strip()         dns = SinDNSFrame(data)         socket = self.request[1]         namemap = SinDNSServer.namemap         if(dns.query.type==1):             # If this is query a A record, then response it             name = dns.getname();             if namemap.__contains__(name):                 # If have record, response it                 dns.setip(namemap[name])                 socket.sendto(dns.getbytes(), self.client_address)             elif namemap.__contains__('*'):                 # Response default address                 dns.setip(namemap['*'])                 socket.sendto(dns.getbytes(), self.client_address)             else:                 # ignore it                 socket.sendto(data, self.client_address)         else:             # If this is not query a A record, ignore it             socket.sendto(data, self.client_address)

# DNS Server # It only support A record query # user it, U can create a simple DNS server class SinDNSServer:     def __init__(self, port=53):         SinDNSServer.namemap = {}         self.port = port     def addname(self, name, ip):         SinDNSServer.namemap[name] = ip     def start(self):         HOST, PORT = "0.0.0.0", self.port         server = socketserver.UDPServer((HOST, PORT), SinDNSUDPHandler)         server.serve_forever()

# Now, test it if __name__ == "__main__":     sev = SinDNSServer()     sev.addname('www.aa.com', '192.168.0.1')    # add a A record     sev.addname('www.bb.com', '192.168.0.2')    # add a A record     sev.addname('*', '0.0.0.0') # default address     sev.start() # start DNS server

# Now, U can use "nslookup" command to test it # Such as "nslookup www.aa.com"