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