| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: twisted.names.test.test_names -*- | |
| 2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
| 3 # See LICENSE for details. | |
| 4 | |
| 5 | |
| 6 """ | |
| 7 Async DNS server | |
| 8 | |
| 9 Future plans: | |
| 10 - Better config file format maybe | |
| 11 - Make sure to differentiate between different classes | |
| 12 - notice truncation bit | |
| 13 | |
| 14 Important: No additional processing is done on some of the record types. | |
| 15 This violates the most basic RFC and is just plain annoying | |
| 16 for resolvers to deal with. Fix it. | |
| 17 | |
| 18 @author: U{Jp Calderone <mailto:exarkun@twistedmatrix.com>} | |
| 19 """ | |
| 20 | |
| 21 from __future__ import nested_scopes | |
| 22 import time | |
| 23 | |
| 24 # Twisted imports | |
| 25 from twisted.internet import protocol | |
| 26 from twisted.names import dns | |
| 27 from twisted.python import log | |
| 28 | |
| 29 import resolve | |
| 30 | |
| 31 class DNSServerFactory(protocol.ServerFactory): | |
| 32 protocol = dns.DNSProtocol | |
| 33 cache = None | |
| 34 | |
| 35 def __init__(self, authorities = None, caches = None, clients = None, verbos
e = 0): | |
| 36 resolvers = [] | |
| 37 if authorities is not None: | |
| 38 resolvers.extend(authorities) | |
| 39 if caches is not None: | |
| 40 resolvers.extend(caches) | |
| 41 if clients is not None: | |
| 42 resolvers.extend(clients) | |
| 43 | |
| 44 self.canRecurse = not not clients | |
| 45 self.resolver = resolve.ResolverChain(resolvers) | |
| 46 self.verbose = verbose | |
| 47 if caches: | |
| 48 self.cache = caches[-1] | |
| 49 | |
| 50 | |
| 51 def buildProtocol(self, addr): | |
| 52 p = self.protocol(self) | |
| 53 p.factory = self | |
| 54 return p | |
| 55 | |
| 56 def connectionMade(self, protocol): | |
| 57 pass | |
| 58 | |
| 59 | |
| 60 def sendReply(self, protocol, message, address): | |
| 61 if self.verbose > 1: | |
| 62 s = ' '.join([str(a.payload) for a in message.answers]) | |
| 63 auth = ' '.join([str(a.payload) for a in message.authority]) | |
| 64 add = ' '.join([str(a.payload) for a in message.additional]) | |
| 65 if not s: | |
| 66 log.msg("Replying with no answers") | |
| 67 else: | |
| 68 log.msg("Answers are " + s) | |
| 69 log.msg("Authority is " + auth) | |
| 70 log.msg("Additional is " + add) | |
| 71 | |
| 72 if address is None: | |
| 73 protocol.writeMessage(message) | |
| 74 else: | |
| 75 protocol.writeMessage(message, address) | |
| 76 | |
| 77 if self.verbose > 1: | |
| 78 log.msg("Processed query in %0.3f seconds" % (time.time() - message.
timeReceived)) | |
| 79 | |
| 80 | |
| 81 def gotResolverResponse(self, (ans, auth, add), protocol, message, address): | |
| 82 message.rCode = dns.OK | |
| 83 message.answers = ans | |
| 84 for x in ans: | |
| 85 if x.isAuthoritative(): | |
| 86 message.auth = 1 | |
| 87 break | |
| 88 message.authority = auth | |
| 89 message.additional = add | |
| 90 self.sendReply(protocol, message, address) | |
| 91 | |
| 92 l = len(ans) + len(auth) + len(add) | |
| 93 if self.verbose: | |
| 94 log.msg("Lookup found %d record%s" % (l, l != 1 and "s" or "")) | |
| 95 | |
| 96 if self.cache and l: | |
| 97 self.cache.cacheResult( | |
| 98 message.queries[0], (ans, auth, add) | |
| 99 ) | |
| 100 | |
| 101 | |
| 102 def gotResolverError(self, failure, protocol, message, address): | |
| 103 if failure.check(dns.DomainError, dns.AuthoritativeDomainError): | |
| 104 message.rCode = dns.ENAME | |
| 105 else: | |
| 106 message.rCode = dns.ESERVER | |
| 107 log.err(failure) | |
| 108 | |
| 109 self.sendReply(protocol, message, address) | |
| 110 if self.verbose: | |
| 111 log.msg("Lookup failed") | |
| 112 | |
| 113 | |
| 114 def handleQuery(self, message, protocol, address): | |
| 115 # Discard all but the first query! HOO-AAH HOOOOO-AAAAH | |
| 116 # (no other servers implement multi-query messages, so we won't either) | |
| 117 query = message.queries[0] | |
| 118 | |
| 119 return self.resolver.query(query).addCallback( | |
| 120 self.gotResolverResponse, protocol, message, address | |
| 121 ).addErrback( | |
| 122 self.gotResolverError, protocol, message, address | |
| 123 ) | |
| 124 | |
| 125 | |
| 126 def handleInverseQuery(self, message, protocol, address): | |
| 127 message.rCode = dns.ENOTIMP | |
| 128 self.sendReply(protocol, message, address) | |
| 129 if self.verbose: | |
| 130 log.msg("Inverse query from %r" % (address,)) | |
| 131 | |
| 132 | |
| 133 def handleStatus(self, message, protocol, address): | |
| 134 message.rCode = dns.ENOTIMP | |
| 135 self.sendReply(protocol, message, address) | |
| 136 if self.verbose: | |
| 137 log.msg("Status request from %r" % (address,)) | |
| 138 | |
| 139 | |
| 140 def handleNotify(self, message, protocol, address): | |
| 141 message.rCode = dns.ENOTIMP | |
| 142 self.sendReply(protocol, message, address) | |
| 143 if self.verbose: | |
| 144 log.msg("Notify message from %r" % (address,)) | |
| 145 | |
| 146 | |
| 147 def handleOther(self, message, protocol, address): | |
| 148 message.rCode = dns.ENOTIMP | |
| 149 self.sendReply(protocol, message, address) | |
| 150 if self.verbose: | |
| 151 log.msg("Unknown op code (%d) from %r" % (message.opCode, address)) | |
| 152 | |
| 153 | |
| 154 def messageReceived(self, message, proto, address = None): | |
| 155 message.timeReceived = time.time() | |
| 156 | |
| 157 if self.verbose: | |
| 158 if self.verbose > 1: | |
| 159 s = ' '.join([str(q) for q in message.queries]) | |
| 160 elif self.verbose > 0: | |
| 161 s = ' '.join([dns.QUERY_TYPES.get(q.type, 'UNKNOWN') for q in me
ssage.queries]) | |
| 162 | |
| 163 if not len(s): | |
| 164 log.msg("Empty query from %r" % ((address or proto.transport.get
Peer()),)) | |
| 165 else: | |
| 166 log.msg("%s query from %r" % (s, address or proto.transport.getP
eer())) | |
| 167 | |
| 168 message.recAv = self.canRecurse | |
| 169 message.answer = 1 | |
| 170 | |
| 171 if not self.allowQuery(message, proto, address): | |
| 172 message.rCode = dns.EREFUSED | |
| 173 self.sendReply(proto, message, address) | |
| 174 elif message.opCode == dns.OP_QUERY: | |
| 175 self.handleQuery(message, proto, address) | |
| 176 elif message.opCode == dns.OP_INVERSE: | |
| 177 self.handleInverseQuery(message, proto, address) | |
| 178 elif message.opCode == dns.OP_STATUS: | |
| 179 self.handleStatus(message, proto, address) | |
| 180 elif message.opCode == dns.OP_NOTIFY: | |
| 181 self.handleNotify(message, proto, address) | |
| 182 else: | |
| 183 self.handleOther(message, proto, address) | |
| 184 | |
| 185 | |
| 186 def allowQuery(self, message, protocol, address): | |
| 187 # Allow anything but empty queries | |
| 188 return len(message.queries) | |
| OLD | NEW |