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 |