The previous days have been doing the company's DNS scheduler, but due to poor performance, the scheme was eventually discarded. 2.5 months of painstaking efforts, do not want to waste, so changed, the trade secret related parts removed, became a public DNS server. In fact, the simple point, is a can do DNS resolution and reply to the program (nonsense, DNS server is not to do this). function is relatively simple, only do a address and CNAME resolution, security does not involve, performance has not been tested, because itself is a toy, measured performance is meaningless (theoretically, if using pypy words, the level of the general machine can run to more than 10,000 of the QPS). This procedure draws lessons from Isnowfy Classmate's procedure (related blog: http://www.isnowfy.com/introduction-to-gevent/, Github:https://github.com/isnowfy/dns), in this respect. Let's introduce the program. First, the basic idea of the server is to open a UDP server to receive the request, waiting for the packet to be received. If the received packet is a DNS packet, the DNS packet is parsed, the domain name is queried in the database, and the corresponding DNS reply packet is constructed, and finally returned. However, this scheme is a single-threaded receive-and-parse-and-answer process with low efficiency. So I modified this: The received package is uniformly put into a cache, and then open a number of threads to fetch data, parallel processing. Each of the threads takes a package for parsing and answering. However, according to the xiā (cāi) I know, the domain name that is frequently visited only then, the same domain name should return the same reply packet, then the parsing of all packets is rather idiotic. So I opened another cache--an LRU cache. For the principle and usage of the LRU cache, you can see my previous blog http://www.cnblogs.com/anpengapple/p/5565461.html. In this way, after acquiring a DNS package, you can find it in the LRU cache first, find the query, and return directly (before remembering the replacement ID), without querying and then parsing, answering, and depositing the LRU cache. Throughout this process, I used: ①gevent used to open the association; ②gevent. Queue is used as a cache queue for receiving packets, ③dnslib libraries are used to parse DNS packets, ④PYLRU libraries are used for LRU caches, and ⑤ uses only a simple text file as a database. The overall program flow is as follows: # 0, start the UDP service.
classDNSServer (object): @staticmethoddefstart ():#cache queue, received requests are put here first, then take data processing from hereDnsserver.deq_cache = Queue (maxsize=deq_size)ifDeq_size > 0ElseQueue ()#LRU Cache, using the least recently used override principleDnsserver.dns_cache =Pylru.lrucache (lru_size)#start the process, loop through the cache queuegevent.spawn (_init_cache_queue)#start the DNS server Print 'Start DNS Server at%s:%d\n'%(IP, port) dns_server=socketserver.udpserver ((IP, port), Dnshandler) Dns_server.serve_forever ()
# 1, receive the request packet, into the cache queue.
class Dnshandler (Socketserver.baserequesthandler): def handle (self): # if the cache queue is not full, put the received packets into the cache queue (the packets are discarded directly) if not DNSServer.deq_cache.full (): # Cache Queue Save tuple: (Request package, request address, sock) DNSServer.deq_cache.put ((Self.request[0], self.client_address, self.request[1]))
# 2. Fetch data from the cache queue.
def _init_cache_queue (): while True: = DNSServer.deq_cache.get () gevent.spawn (handler, data, addr, sock)
# 3, if the request is a DNS packet, resolve its query domain name.
=try: = dnslib. Dnsrecord.parse (data)except Exception as E: print'nota DNS packet.\n', E
# 4, determine if it exists in the LRU cache. If present, proceed 5; otherwise, proceed to 6.
Response =if response: # Goto 5Else: # Goto 6
# 5, obtain the reply data of this DNS in the LRU cache, replace the ID with the ID of this DNS query, and then return to the client.
Response[:2] = data[:2]sock.sendto (response, addr)
# 6, from the database to find the answer to this DNS, encapsulated into a DNS packet, stored in the LRU cache, and then returned to the client.
Answers, SOA = query (str (QName). Rstrip ('. ' == answer_dns.pack () sock.sendto (Answer_dns.pack (), addr)
Anyway, probably the process is the sauce aunt. I added a few data to the "database" to do the experiment (the first is SOA): Then test: Dig ccc.apple.tree @dns-ip-p Dns-port Get results, success analysis, vomit ~ There is a point to note, As a database text file if it is written under Windows, get Linux under the use of, there may be a newline character disgusting people problems. Specific situations and solutions see: http://www.cnblogs.com/anpengapple/p/5664235.html the CSV file used here is for illustrative purposes only,There are no performance and safety considerations. Improvements can be considered:
First, the content is loaded into memory when the server is opened, so that lrucache can be removed;
Second, use a database such as Redis or MySQL;
Third, pay attention to the validation of data, such as judging the IP of the regular, domain name content and so on.
In fact, as a DNS server, this program lacks a lot, can only be used as a model for reference, or a toy to play. It's about the sauce. Using Python as a DNS server is a joke. Complete code I put on GitHub above, address: Https://github.com/anpengapple/apple_dns, interested students can take to play, there are views of students can mention, anyway I will not change. My lazy cancer is over-heavy. PostScript: (1) Our decision to give up powerdns, change into bind embrace. While the performance of the second quarter was largely ruined, it was excellent to use bind. After all, bind with a lot of people, even if there is a problem can have a place to ask questions. And, Powerdns, I'm almost cornered. (2) recently found a website reprinted my several blog, the first is still very happy, indicating that I write something is still more useful, got the approval of others, but feel a little strange, reproduced not notice me, even reproduced the words did not appear, this makes me a little dissatisfied. So declare my blog now there is only one, address in: After http://www.cnblogs.com/anpengapple/if the other blog or the public number or something, I will also in this blog to inform. (3) A bored classmate can help me test the QPS, remember to add good data in the database, but also useful pypy to run. Test tool Queryperf Use see: Http://www.cnblogs.com/anpengapple/p/5211557.html,pypy installation and use see: http://www.cnblogs.com/ Anpengapple/p/5586678.html
Build a DNS server from Python