1
# -*- test-case-name: twisted.names.test -*-
2
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
Base functionality useful to various parts of Twisted Names.
11
from twisted.names import dns
12
from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError
13
from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError
14
from twisted.names.error import DNSUnknownError
16
from twisted.internet import defer, error
17
from twisted.python import failure
19
EMPTY_RESULT = (), (), ()
23
L{ResolverBase} is a base class for L{IResolver} implementations which
24
deals with a lot of the boilerplate of implementing all of the lookup
27
@cvar _errormap: A C{dict} mapping DNS protocol failure response codes
28
to exception classes which will be used to represent those failures.
31
dns.EFORMAT: DNSFormatError,
32
dns.ESERVER: DNSServerError,
33
dns.ENAME: DNSNameError,
34
dns.ENOTIMP: DNSNotImplementedError,
35
dns.EREFUSED: DNSQueryRefusedError}
40
self.typeToMethod = {}
41
for (k, v) in typeToMethod.items():
42
self.typeToMethod[k] = getattr(self, v)
45
def exceptionForCode(self, responseCode):
47
Convert a response code (one of the possible values of
48
L{dns.Message.rCode} to an exception instance representing it.
52
return self._errormap.get(responseCode, DNSUnknownError)
55
def query(self, query, timeout = None):
57
return self.typeToMethod[query.type](str(query.name), timeout)
59
return defer.fail(failure.Failure(NotImplementedError(str(self.__class__) + " " + str(query.type))))
61
def _lookup(self, name, cls, type, timeout):
62
return defer.fail(NotImplementedError("ResolverBase._lookup"))
64
def lookupAddress(self, name, timeout = None):
66
@see: twisted.names.client.lookupAddress
68
return self._lookup(name, dns.IN, dns.A, timeout)
70
def lookupIPV6Address(self, name, timeout = None):
72
@see: twisted.names.client.lookupIPV6Address
74
return self._lookup(name, dns.IN, dns.AAAA, timeout)
76
def lookupAddress6(self, name, timeout = None):
78
@see: twisted.names.client.lookupAddress6
80
return self._lookup(name, dns.IN, dns.A6, timeout)
82
def lookupMailExchange(self, name, timeout = None):
84
@see: twisted.names.client.lookupMailExchange
86
return self._lookup(name, dns.IN, dns.MX, timeout)
88
def lookupNameservers(self, name, timeout = None):
90
@see: twisted.names.client.lookupNameservers
92
return self._lookup(name, dns.IN, dns.NS, timeout)
94
def lookupCanonicalName(self, name, timeout = None):
96
@see: twisted.names.client.lookupCanonicalName
98
return self._lookup(name, dns.IN, dns.CNAME, timeout)
100
def lookupMailBox(self, name, timeout = None):
102
@see: twisted.names.client.lookupMailBox
104
return self._lookup(name, dns.IN, dns.MB, timeout)
106
def lookupMailGroup(self, name, timeout = None):
108
@see: twisted.names.client.lookupMailGroup
110
return self._lookup(name, dns.IN, dns.MG, timeout)
112
def lookupMailRename(self, name, timeout = None):
114
@see: twisted.names.client.lookupMailRename
116
return self._lookup(name, dns.IN, dns.MR, timeout)
118
def lookupPointer(self, name, timeout = None):
120
@see: twisted.names.client.lookupPointer
122
return self._lookup(name, dns.IN, dns.PTR, timeout)
124
def lookupAuthority(self, name, timeout = None):
126
@see: twisted.names.client.lookupAuthority
128
return self._lookup(name, dns.IN, dns.SOA, timeout)
130
def lookupNull(self, name, timeout = None):
132
@see: twisted.names.client.lookupNull
134
return self._lookup(name, dns.IN, dns.NULL, timeout)
136
def lookupWellKnownServices(self, name, timeout = None):
138
@see: twisted.names.client.lookupWellKnownServices
140
return self._lookup(name, dns.IN, dns.WKS, timeout)
142
def lookupService(self, name, timeout = None):
144
@see: twisted.names.client.lookupService
146
return self._lookup(name, dns.IN, dns.SRV, timeout)
148
def lookupHostInfo(self, name, timeout = None):
150
@see: twisted.names.client.lookupHostInfo
152
return self._lookup(name, dns.IN, dns.HINFO, timeout)
154
def lookupMailboxInfo(self, name, timeout = None):
156
@see: twisted.names.client.lookupMailboxInfo
158
return self._lookup(name, dns.IN, dns.MINFO, timeout)
160
def lookupText(self, name, timeout = None):
162
@see: twisted.names.client.lookupText
164
return self._lookup(name, dns.IN, dns.TXT, timeout)
166
def lookupResponsibility(self, name, timeout = None):
168
@see: twisted.names.client.lookupResponsibility
170
return self._lookup(name, dns.IN, dns.RP, timeout)
172
def lookupAFSDatabase(self, name, timeout = None):
174
@see: twisted.names.client.lookupAFSDatabase
176
return self._lookup(name, dns.IN, dns.AFSDB, timeout)
178
def lookupZone(self, name, timeout = None):
180
@see: twisted.names.client.lookupZone
182
return self._lookup(name, dns.IN, dns.AXFR, timeout)
185
def lookupNamingAuthorityPointer(self, name, timeout=None):
187
@see: twisted.names.client.lookupNamingAuthorityPointer
189
return self._lookup(name, dns.IN, dns.NAPTR, timeout)
192
def lookupAllRecords(self, name, timeout = None):
194
@see: twisted.names.client.lookupAllRecords
196
return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout)
198
def getHostByName(self, name, timeout = None, effort = 10):
200
@see: twisted.names.client.getHostByName
202
# XXX - respect timeout
203
return self.lookupAllRecords(name, timeout
204
).addCallback(self._cbRecords, name, effort
207
def _cbRecords(self, (ans, auth, add), name, effort):
208
result = extractRecord(self, dns.Name(name), ans + auth + add, effort)
210
raise error.DNSLookupError(name)
213
def extractRecord(resolver, name, answers, level = 10):
216
if hasattr(socket, 'inet_ntop'):
218
if r.name == name and r.type == dns.A6:
219
return socket.inet_ntop(socket.AF_INET6, r.payload.address)
221
if r.name == name and r.type == dns.AAAA:
222
return socket.inet_ntop(socket.AF_INET6, r.payload.address)
224
if r.name == name and r.type == dns.A:
225
return socket.inet_ntop(socket.AF_INET, r.payload.address)
227
if r.name == name and r.type == dns.CNAME:
228
result = extractRecord(resolver, r.payload.name, answers, level - 1)
230
return resolver.getHostByName(str(r.payload.name), effort=level-1)
232
# No answers, but maybe there's a hint at who we should be asking about this
235
from twisted.names import client
236
r = client.Resolver(servers=[(str(r.payload.name), dns.PORT)])
237
return r.lookupAddress(str(name)
238
).addCallback(lambda (ans, auth, add): extractRecord(r, name, ans + auth + add, level - 1)
239
).addBoth(lambda passthrough: (r.protocol.transport.stopListening(), passthrough)[1])
242
dns.A: 'lookupAddress',
243
dns.AAAA: 'lookupIPV6Address',
244
dns.A6: 'lookupAddress6',
245
dns.NS: 'lookupNameservers',
246
dns.CNAME: 'lookupCanonicalName',
247
dns.SOA: 'lookupAuthority',
248
dns.MB: 'lookupMailBox',
249
dns.MG: 'lookupMailGroup',
250
dns.MR: 'lookupMailRename',
251
dns.NULL: 'lookupNull',
252
dns.WKS: 'lookupWellKnownServices',
253
dns.PTR: 'lookupPointer',
254
dns.HINFO: 'lookupHostInfo',
255
dns.MINFO: 'lookupMailboxInfo',
256
dns.MX: 'lookupMailExchange',
257
dns.TXT: 'lookupText',
259
dns.RP: 'lookupResponsibility',
260
dns.AFSDB: 'lookupAFSDatabase',
261
dns.SRV: 'lookupService',
262
dns.NAPTR: 'lookupNamingAuthorityPointer',
263
dns.AXFR: 'lookupZone',
264
dns.ALL_RECORDS: 'lookupAllRecords',