1 # -*- test-case-name: twisted.names.test -*-
2 # Copyright (c) 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 lookupSenderPolicy(self, name, timeout = None):
168 @see: twisted.names.client.lookupSenderPolicy
170 return self._lookup(name, dns.IN, dns.SPF, timeout)
172 def lookupResponsibility(self, name, timeout = None):
174 @see: twisted.names.client.lookupResponsibility
176 return self._lookup(name, dns.IN, dns.RP, timeout)
178 def lookupAFSDatabase(self, name, timeout = None):
180 @see: twisted.names.client.lookupAFSDatabase
182 return self._lookup(name, dns.IN, dns.AFSDB, timeout)
184 def lookupZone(self, name, timeout = None):
186 @see: twisted.names.client.lookupZone
188 return self._lookup(name, dns.IN, dns.AXFR, timeout)
191 def lookupNamingAuthorityPointer(self, name, timeout=None):
193 @see: twisted.names.client.lookupNamingAuthorityPointer
195 return self._lookup(name, dns.IN, dns.NAPTR, timeout)
198 def lookupAllRecords(self, name, timeout = None):
200 @see: twisted.names.client.lookupAllRecords
202 return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout)
204 def getHostByName(self, name, timeout = None, effort = 10):
206 @see: twisted.names.client.getHostByName
208 # XXX - respect timeout
209 return self.lookupAllRecords(name, timeout
210 ).addCallback(self._cbRecords, name, effort
213 def _cbRecords(self, (ans, auth, add), name, effort):
214 result = extractRecord(self, dns.Name(name), ans + auth + add, effort)
216 raise error.DNSLookupError(name)
220 def extractRecord(resolver, name, answers, level=10):
223 if hasattr(socket, 'inet_ntop'):
225 if r.name == name and r.type == dns.A6:
226 return socket.inet_ntop(socket.AF_INET6, r.payload.address)
228 if r.name == name and r.type == dns.AAAA:
229 return socket.inet_ntop(socket.AF_INET6, r.payload.address)
231 if r.name == name and r.type == dns.A:
232 return socket.inet_ntop(socket.AF_INET, r.payload.address)
234 if r.name == name and r.type == dns.CNAME:
235 result = extractRecord(
236 resolver, r.payload.name, answers, level - 1)
238 return resolver.getHostByName(
239 str(r.payload.name), effort=level - 1)
241 # No answers, but maybe there's a hint at who we should be asking about
245 from twisted.names import client
246 r = client.Resolver(servers=[(str(r.payload.name), dns.PORT)])
247 return r.lookupAddress(str(name)
249 lambda (ans, auth, add):
250 extractRecord(r, name, ans + auth + add, level - 1))
254 dns.A: 'lookupAddress',
255 dns.AAAA: 'lookupIPV6Address',
256 dns.A6: 'lookupAddress6',
257 dns.NS: 'lookupNameservers',
258 dns.CNAME: 'lookupCanonicalName',
259 dns.SOA: 'lookupAuthority',
260 dns.MB: 'lookupMailBox',
261 dns.MG: 'lookupMailGroup',
262 dns.MR: 'lookupMailRename',
263 dns.NULL: 'lookupNull',
264 dns.WKS: 'lookupWellKnownServices',
265 dns.PTR: 'lookupPointer',
266 dns.HINFO: 'lookupHostInfo',
267 dns.MINFO: 'lookupMailboxInfo',
268 dns.MX: 'lookupMailExchange',
269 dns.TXT: 'lookupText',
270 dns.SPF: 'lookupSenderPolicy',
272 dns.RP: 'lookupResponsibility',
273 dns.AFSDB: 'lookupAFSDatabase',
274 dns.SRV: 'lookupService',
275 dns.NAPTR: 'lookupNamingAuthorityPointer',
276 dns.AXFR: 'lookupZone',
277 dns.ALL_RECORDS: 'lookupAllRecords',