1
# -*- test-case-name: twisted.names.test.test_names -*-
2
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3
# See LICENSE for details.
9
API Stability: Unstable
12
- Better config file format maybe
13
- Make sure to differentiate between different classes
14
- notice truncation bit
16
Important: No additional processing is done on some of the record types.
17
This violates the most basic RFC and is just plain annoying
18
for resolvers to deal with. Fix it.
20
@author: U{Jp Calderone <mailto:exarkun@twistedmatrix.com>}
23
from __future__ import nested_scopes
27
from twisted.internet import protocol
28
from twisted.names import dns
29
from twisted.python import log
33
class DNSServerFactory(protocol.ServerFactory):
34
protocol = dns.DNSProtocol
37
def __init__(self, authorities = None, caches = None, clients = None, verbose = 0):
39
if authorities is not None:
40
resolvers.extend(authorities)
41
if caches is not None:
42
resolvers.extend(caches)
43
if clients is not None:
44
resolvers.extend(clients)
46
self.canRecurse = not not clients
47
self.resolver = resolve.ResolverChain(resolvers)
48
self.verbose = verbose
50
self.cache = caches[-1]
53
def buildProtocol(self, addr):
54
p = self.protocol(self)
58
def connectionMade(self, protocol):
62
def sendReply(self, protocol, message, address):
64
s = ' '.join([str(a.payload) for a in message.answers])
65
auth = ' '.join([str(a.payload) for a in message.authority])
66
add = ' '.join([str(a.payload) for a in message.additional])
68
log.msg("Replying with no answers")
70
log.msg("Answers are " + s)
71
log.msg("Authority is " + auth)
72
log.msg("Additional is " + add)
75
protocol.writeMessage(message)
77
protocol.writeMessage(message, address)
80
log.msg("Processed query in %0.3f seconds" % (time.time() - message.timeReceived))
83
def gotResolverResponse(self, (ans, auth, add), protocol, message, address):
84
message.rCode = dns.OK
87
if x.isAuthoritative():
90
message.authority = auth
91
message.additional = add
92
self.sendReply(protocol, message, address)
94
l = len(ans) + len(auth) + len(add)
96
log.msg("Lookup found %d record%s" % (l, l != 1 and "s" or ""))
99
self.cache.cacheResult(
100
message.queries[0], (ans, auth, add)
104
def gotResolverError(self, failure, protocol, message, address):
105
if failure.check(dns.DomainError, dns.AuthoritativeDomainError):
106
message.rCode = dns.ENAME
108
message.rCode = dns.ESERVER
111
self.sendReply(protocol, message, address)
113
log.msg("Lookup failed")
116
def handleQuery(self, message, protocol, address):
117
# Discard all but the first query! HOO-AAH HOOOOO-AAAAH
118
# (no other servers implement multi-query messages, so we won't either)
119
query = message.queries[0]
121
return self.resolver.query(query).addCallback(
122
self.gotResolverResponse, protocol, message, address
124
self.gotResolverError, protocol, message, address
128
def handleInverseQuery(self, message, protocol, address):
129
message.rCode = dns.ENOTIMP
130
self.sendReply(protocol, message, address)
132
log.msg("Inverse query from %r" % (address,))
135
def handleStatus(self, message, protocol, address):
136
message.rCode = dns.ENOTIMP
137
self.sendReply(protocol, message, address)
139
log.msg("Status request from %r" % (address,))
142
def handleNotify(self, message, protocol, address):
143
message.rCode = dns.ENOTIMP
144
self.sendReply(protocol, message, address)
146
log.msg("Notify message from %r" % (address,))
149
def handleOther(self, message, protocol, address):
150
message.rCode = dns.ENOTIMP
151
self.sendReply(protocol, message, address)
153
log.msg("Unknown op code (%d) from %r" % (message.opCode, address))
156
def messageReceived(self, message, proto, address = None):
157
message.timeReceived = time.time()
161
s = ' '.join([str(q) for q in message.queries])
162
elif self.verbose > 0:
163
s = ' '.join([dns.QUERY_TYPES.get(q.type, 'UNKNOWN') for q in message.queries])
166
log.msg("Empty query from %r" % ((address or proto.transport.getPeer()),))
168
log.msg("%s query from %r" % (s, address or proto.transport.getPeer()))
170
message.recAv = self.canRecurse
173
if not self.allowQuery(message, proto, address):
174
message.rCode = dns.EREFUSED
175
self.sendReply(proto, message, address)
176
elif message.opCode == dns.OP_QUERY:
177
self.handleQuery(message, proto, address)
178
elif message.opCode == dns.OP_INVERSE:
179
self.handleInverseQuery(message, proto, address)
180
elif message.opCode == dns.OP_STATUS:
181
self.handleStatus(message, proto, address)
182
elif message.opCode == dns.OP_NOTIFY:
183
self.handleNotify(message, proto, address)
185
self.handleOther(message, proto, address)
188
def allowQuery(self, message, protocol, address):
189
# Allow anything but empty queries
190
return len(message.queries)