Suddenly there was an evil idea, and I wanted to build a DNS server on my Android tablet. Because SL4A and Python interpreters were installed on the tablet, I also wanted to continue learning Python, it is intended to be implemented in Python.
I found the DNS implemented by Python on Google and did not find the desired answer, so I decided to implement it myself.
The current implementation is nothing advanced, but it is able to perform simple matching and reply to A record query.
The implementation code is as follows:
Copy codeThe Code is as follows:
'''
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 used 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 ('bbbbbb', 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"