root / trunk / twisted / names / client.py

Revision 26656, 28.9 kB (checked in by exarkun, 3 months ago)

Merge deprecate-threadedresolver-3710

Author: cary, exarkun
Reviewer: therve
Fixes: #3710

Deprecate twisted.names.client.ThreadedResolver in favor of
twisted.internet.base.ThreadedResolver.

Line 
1 # -*- test-case-name: twisted.names.test.test_names -*-
2 # Copyright (c) 2001-2008 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Asynchronous client DNS
7
8 The functions exposed in this module can be used for asynchronous name
9 resolution and dns queries.
10
11 If you need to create a resolver with specific requirements, such as needing to
12 do queries against a particular host, the L{createResolver} function will
13 return an C{IResolver}.
14
15 Future plans: Proper nameserver acquisition on Windows/MacOS,
16 better caching, respect timeouts
17
18 @author: Jp Calderone
19 """
20
21 import os
22 import errno
23 import warnings
24
25 from zope.interface import implements
26
27 # Twisted imports
28 from twisted.python.runtime import platform
29 from twisted.internet import error, defer, protocol, interfaces
30 from twisted.python import log, failure
31 from twisted.python.deprecate import getWarningMethod
32 from twisted.names import dns, common
33 from twisted.names.error import DNSFormatError, DNSServerError, DNSNameError
34 from twisted.names.error import DNSNotImplementedError, DNSQueryRefusedError
35 from twisted.names.error import DNSUnknownError
36
37
38 class Resolver(common.ResolverBase):
39     """
40     @ivar _waiting: A C{dict} mapping tuple keys of query name/type/class to
41         Deferreds which will be called back with the result of those queries.
42         This is used to avoid issuing the same query more than once in
43         parallel.  This is more efficient on the network and helps avoid a
44         "birthday paradox" attack by keeping the number of outstanding requests
45         for a particular query fixed at one instead of allowing the attacker to
46         raise it to an arbitrary number.
47
48     @ivar _reactor: A provider of L{IReactorTCP}, L{IReactorUDP}, and
49         L{IReactorTime} which will be used to set up network resources and
50         track timeouts.
51     """
52     implements(interfaces.IResolver)
53
54     index = 0
55     timeout = None
56
57     factory = None
58     servers = None
59     dynServers = ()
60     pending = None
61     connections = None
62
63     resolv = None
64     _lastResolvTime = None
65     _resolvReadInterval = 60
66
67     _errormap = {
68         dns.EFORMAT: DNSFormatError,
69         dns.ESERVER: DNSServerError,
70         dns.ENAME: DNSNameError,
71         dns.ENOTIMP: DNSNotImplementedError,
72         dns.EREFUSED: DNSQueryRefusedError}
73
74     def _getProtocol(self):
75         getWarningMethod()(
76             "Resolver.protocol is deprecated; use Resolver.queryUDP instead.",
77             PendingDeprecationWarning,
78             stacklevel=0)
79         self.protocol = dns.DNSDatagramProtocol(self)
80         return self.protocol
81     protocol = property(_getProtocol)
82
83
84     def __init__(self, resolv=None, servers=None, timeout=(1, 3, 11, 45)):
85         """
86         Construct a resolver which will query domain name servers listed in
87         the C{resolv.conf(5)}-format file given by C{resolv} as well as
88         those in the given C{servers} list.  Servers are queried in a
89         round-robin fashion.  If given, C{resolv} is periodically checked
90         for modification and re-parsed if it is noticed to have changed.
91
92         @type servers: C{list} of C{(str, int)} or C{None}
93         @param servers: If not None, interpreted as a list of (host, port)
94             pairs specifying addresses of domain name servers to attempt to use
95             for this lookup.  Host addresses should be in IPv4 dotted-quad
96             form.  If specified, overrides C{resolv}.
97
98         @type resolv: C{str}
99         @param resolv: Filename to read and parse as a resolver(5)
100             configuration file.
101
102         @type timeout: Sequence of C{int}
103         @param timeout: Default number of seconds after which to reissue the
104             query.  When the last timeout expires, the query is considered
105             failed.
106
107         @raise ValueError: Raised if no nameserver addresses can be found.
108         """
109         common.ResolverBase.__init__(self)
110         from twisted.internet import reactor
111         self._reactor = reactor
112
113         self.timeout = timeout
114
115         if servers is None:
116             self.servers = []
117         else:
118             self.servers = servers
119
120         self.resolv = resolv
121
122         if not len(self.servers) and not resolv:
123             raise ValueError, "No nameservers specified"
124
125         self.factory = DNSClientFactory(self, timeout)
126         self.factory.noisy = 0   # Be quiet by default
127
128         self.connections = []
129         self.pending = []
130
131         self._waiting = {}
132
133         self.maybeParseConfig()
134
135
136     def __getstate__(self):
137         d = self.__dict__.copy()
138         d['connections'] = []
139         d['_parseCall'] = None
140         return d
141
142
143     def __setstate__(self, state):
144         self.__dict__.update(state)
145         self.maybeParseConfig()
146
147
148     def maybeParseConfig(self):
149         if self.resolv is None:
150             # Don't try to parse it, don't set up a call loop
151             return
152
153         try:
154             resolvConf = file(self.resolv)
155         except IOError, e:
156             if e.errno == errno.ENOENT:
157                 # Missing resolv.conf is treated the same as an empty resolv.conf
158                 self.parseConfig(())
159             else:
160                 raise
161         else:
162             mtime = os.fstat(resolvConf.fileno()).st_mtime
163             if mtime != self._lastResolvTime:
164                 log.msg('%s changed, reparsing' % (self.resolv,))
165                 self._lastResolvTime = mtime
166                 self.parseConfig(resolvConf)
167
168         # Check again in a little while
169         self._parseCall = self._reactor.callLater(
170             self._resolvReadInterval, self.maybeParseConfig)
171
172
173     def parseConfig(self, resolvConf):
174         servers = []
175         for L in resolvConf:
176             L = L.strip()
177             if L.startswith('nameserver'):
178                 resolver = (L.split()[1], dns.PORT)
179                 servers.append(resolver)
180                 log.msg("Resolver added %r to server list" % (resolver,))
181             elif L.startswith('domain'):
182                 try:
183                     self.domain = L.split()[1]
184                 except IndexError:
185                     self.domain = ''
186                 self.search = None
187             elif L.startswith('search'):
188                 try:
189                     self.search = L.split()[1:]
190                 except IndexError:
191                     self.search = ''
192                 self.domain = None
193         if not servers:
194             servers.append(('127.0.0.1', dns.PORT))
195         self.dynServers = servers
196
197
198     def pickServer(self):
199         """
200         Return the address of a nameserver.
201
202         TODO: Weight servers for response time so faster ones can be
203         preferred.
204         """
205         if not self.servers and not self.dynServers:
206             return None
207         serverL = len(self.servers)
208         dynL = len(self.dynServers)
209
210         self.index += 1
211         self.index %= (serverL + dynL)
212         if self.index < serverL:
213             return self.servers[self.index]
214         else:
215             return self.dynServers[self.index - serverL]
216
217
218     def _connectedProtocol(self):
219         """
220         Return a new L{DNSDatagramProtocol} bound to a randomly selected port
221         number.
222         """
223         if 'protocol' in self.__dict__:
224             # Some code previously asked for or set the deprecated `protocol`
225             # attribute, so it probably expects that object to be used for
226             # queries.  Give it back and skip the super awesome source port
227             # randomization logic.  This is actually a really good reason to
228             # remove this deprecated backward compatibility as soon as
229             # possible. -exarkun
230             return self.protocol
231         proto = dns.DNSDatagramProtocol(self)
232         while True:
233             try:
234                 self._reactor.listenUDP(dns.randomSource(), proto)
235             except error.CannotListenError:
236                 pass
237             else:
238                 return proto
239
240
241     def connectionMade(self, protocol):
242         self.connections.append(protocol)
243         for (d, q, t) in self.pending:
244             self.queryTCP(q, t).chainDeferred(d)
245         del self.pending[:]
246
247
248     def messageReceived(self, message, protocol, address = None):
249         log.msg("Unexpected message (%d) received from %r" % (message.id, address))
250
251
252     def _query(self, *args):
253         """
254         Get a new L{DNSDatagramProtocol} instance from L{_connectedProtocol},
255         issue a query to it using C{*args}, and arrange for it to be
256         disconnected from its transport after the query completes.
257
258         @param *args: Positional arguments to be passed to
259             L{DNSDatagramProtocol.query}.
260
261         @return: A L{Deferred} which will be called back with the result of the
262             query.
263         """
264         protocol = self._connectedProtocol()
265         d = protocol.query(*args)
266         def cbQueried(result):
267             protocol.transport.stopListening()
268             return result
269         d.addBoth(cbQueried)
270         return d
271
272
273     def queryUDP(self, queries, timeout = None):
274         """
275         Make a number of DNS queries via UDP.
276
277         @type queries: A C{list} of C{dns.Query} instances
278         @param queries: The queries to make.
279
280         @type timeout: Sequence of C{int}
281         @param timeout: Number of seconds after which to reissue the query.
282         When the last timeout expires, the query is considered failed.
283
284         @rtype: C{Deferred}
285         @raise C{twisted.internet.defer.TimeoutError}: When the query times
286         out.
287         """
288         if timeout is None:
289             timeout = self.timeout
290
291         addresses = self.servers + list(self.dynServers)
292         if not addresses:
293             return defer.fail(IOError("No domain name servers available"))
294
295         # Make sure we go through servers in the list in the order they were
296         # specified.
297         addresses.reverse()
298
299         used = addresses.pop()
300         d = self._query(used, queries, timeout[0])
301         d.addErrback(self._reissue, addresses, [used], queries, timeout)
302         return d
303
304
305     def _reissue(self, reason, addressesLeft, addressesUsed, query, timeout):
306         reason.trap(dns.DNSQueryTimeoutError)
307
308         # If there are no servers left to be tried, adjust the timeout
309         # to the next longest timeout period and move all the
310         # "used" addresses back to the list of addresses to try.
311         if not addressesLeft:
312             addressesLeft = addressesUsed
313             addressesLeft.reverse()
314             addressesUsed = []
315             timeout = timeout[1:]
316
317         # If all timeout values have been used this query has failed.  Tell the
318         # protocol we're giving up on it and return a terminal timeout failure
319         # to our caller.
320         if not timeout:
321             return failure.Failure(defer.TimeoutError(query))
322
323         # Get an address to try.  Take it out of the list of addresses
324         # to try and put it ino the list of already tried addresses.
325         address = addressesLeft.pop()
326         addressesUsed.append(address)
327
328         # Issue a query to a server.  Use the current timeout.  Add this
329         # function as a timeout errback in case another retry is required.
330         d = self._query(address, query, timeout[0], reason.value.id)
331         d.addErrback(self._reissue, addressesLeft, addressesUsed, query, timeout)
332         return d
333
334
335     def queryTCP(self, queries, timeout = 10):
336         """
337         Make a number of DNS queries via TCP.
338
339         @type queries: Any non-zero number of C{dns.Query} instances
340         @param queries: The queries to make.
341
342         @type timeout: C{int}
343         @param timeout: The number of seconds after which to fail.
344
345         @rtype: C{Deferred}
346         """
347         if not len(self.connections):
348             address = self.pickServer()
349             if address is None:
350                 return defer.fail(IOError("No domain name servers available"))
351             host, port = address
352             self._reactor.connectTCP(host, port, self.factory)
353             self.pending.append((defer.Deferred(), queries, timeout))
354             return self.pending[-1][0]
355         else:
356             return self.connections[0].query(queries, timeout)
357
358
359     def filterAnswers(self, message):
360         """
361         Extract results from the given message.
362
363         If the message was truncated, re-attempt the query over TCP and return
364         a Deferred which will fire with the results of that query.
365
366         If the message's result code is not L{dns.OK}, return a Failure
367         indicating the type of error which occurred.
368
369         Otherwise, return a three-tuple of lists containing the results from
370         the answers section, the authority section, and the additional section.
371         """
372         if message.trunc:
373             return self.queryTCP(message.queries).addCallback(self.filterAnswers)
374         if message.rCode != dns.OK:
375             return failure.Failure(self._errormap.get(message.rCode, DNSUnknownError)(message))
376         return (message.answers, message.authority, message.additional)
377
378
379     def _lookup(self, name, cls, type, timeout):
380         """
381         Build a L{dns.Query} for the given parameters and dispatch it via UDP.
382
383         If this query is already outstanding, it will not be re-issued.
384         Instead, when the outstanding query receives a response, that response
385         will be re-used for this query as well.
386
387         @type name: C{str}
388         @type type: C{int}
389         @type cls: C{int}
390
391         @return: A L{Deferred} which fires with a three-tuple giving the
392             answer, authority, and additional sections of the response or with
393             a L{Failure} if the response code is anything other than C{dns.OK}.
394         """
395         key = (name, type, cls)
396         waiting = self._waiting.get(key)
397         if waiting is None:
398             self._waiting[key] = []
399             d = self.queryUDP([dns.Query(name, type, cls)], timeout)
400             def cbResult(result):
401                 for d in self._waiting.pop(key):
402                     d.callback(result)
403                 return result
404             d.addCallback(self.filterAnswers)
405             d.addBoth(cbResult)
406         else:
407             d = defer.Deferred()
408             waiting.append(d)
409         return d
410
411
412     # This one doesn't ever belong on UDP
413     def lookupZone(self, name, timeout = 10):
414         """
415         Perform an AXFR request. This is quite different from usual
416         DNS requests. See http://cr.yp.to/djbdns/axfr-notes.html for
417         more information.
418         """
419         address = self.pickServer()
420         if address is None:
421             return defer.fail(IOError('No domain name servers available'))
422         host, port = address
423         d = defer.Deferred()
424         controller = AXFRController(name, d)
425         factory = DNSClientFactory(controller, timeout)
426         factory.noisy = False #stfu
427
428         connector = self._reactor.connectTCP(host, port, factory)
429         controller.timeoutCall = self._reactor.callLater(
430             timeout or 10, self._timeoutZone, d, controller,
431             connector, timeout or 10)
432         return d.addCallback(self._cbLookupZone, connector)
433
434     def _timeoutZone(self, d, controller, connector, seconds):
435         connector.disconnect()
436         controller.timeoutCall = None
437         controller.deferred = None
438         d.errback(error.TimeoutError("Zone lookup timed out after %d seconds" % (seconds,)))
439
440     def _cbLookupZone(self, result, connector):
441         connector.disconnect()
442         return (result, [], [])
443
444
445 class AXFRController:
446     timeoutCall = None
447
448     def __init__(self, name, deferred):
449         self.name = name
450         self.deferred = deferred
451         self.soa = None
452         self.records = []
453
454     def connectionMade(self, protocol):
455         # dig saids recursion-desired to 0, so I will too
456         message = dns.Message(protocol.pickID(), recDes=0)
457         message.queries = [dns.Query(self.name, dns.AXFR, dns.IN)]
458         protocol.writeMessage(message)
459
460
461     def connectionLost(self, protocol):
462         # XXX Do something here - see #3428
463         pass
464
465
466     def messageReceived(self, message, protocol):
467         # Caveat: We have to handle two cases: All records are in 1
468         # message, or all records are in N messages.
469
470         # According to http://cr.yp.to/djbdns/axfr-notes.html,
471         # 'authority' and 'additional' are always empty, and only
472         # 'answers' is present.
473         self.records.extend(message.answers)
474         if not self.records:
475             return
476         if not self.soa:
477             if self.records[0].type == dns.SOA:
478                 #print "first SOA!"
479                 self.soa = self.records[0]
480         if len(self.records) > 1 and self.records[-1].type == dns.SOA:
481             #print "It's the second SOA! We're done."
482             if self.timeoutCall is not None:
483                 self.timeoutCall.cancel()
484                 self.timeoutCall = None
485             if self.deferred is not None:
486                 self.deferred.callback(self.records)
487                 self.deferred = None
488
489
490
491 from twisted.internet.base import ThreadedResolver as _ThreadedResolverImpl
492
493 class ThreadedResolver(_ThreadedResolverImpl):
494     def __init__(self, reactor=None):
495         if reactor is None:
496             from twisted.internet import reactor
497         _ThreadedResolverImpl.__init__(self, reactor)
498         warnings.warn(
499             "twisted.names.client.ThreadedResolver is deprecated since "
500             "Twisted 9.0, use twisted.internet.base.ThreadedResolver "
501             "instead.",
502             category=DeprecationWarning, stacklevel=2)
503
504 class DNSClientFactory(protocol.ClientFactory):
505     def __init__(self, controller, timeout = 10):
506         self.controller = controller
507         self.timeout = timeout
508
509
510     def clientConnectionLost(self, connector, reason):
511         pass
512
513
514     def buildProtocol(self, addr):
515         p = dns.DNSProtocol(self.controller)
516         p.factory = self
517         return p
518
519
520
521 def createResolver(servers=None, resolvconf=None, hosts=None):
522     """
523     Create and return a Resolver.
524
525     @type servers: C{list} of C{(str, int)} or C{None}
526     @param servers: If not C{None}, interpreted as a list of addresses of
527     domain name servers to attempt to use.  Addresses should be in dotted-quad
528     form.
529
530     @type resolvconf: C{str} or C{None}
531     @param resolvconf: If not C{None}, on posix systems will be interpreted as
532     an alternate resolv.conf to use. Will do nothing on windows systems. If
533     C{None}, /etc/resolv.conf will be used.
534
535     @type hosts: C{str} or C{None}
536     @param hosts: If not C{None}, an alternate hosts file to use. If C{None}
537     on posix systems, /etc/hosts will be used. On windows, C:\windows\hosts
538     will be used.
539
540     @rtype: C{IResolver}
541     """
542     from twisted.names import resolve, cache, root, hosts as hostsModule
543     if platform.getType() == 'posix':
544         if resolvconf is None:
545             resolvconf = '/etc/resolv.conf'
546         if hosts is None:
547             hosts = '/etc/hosts'
548         theResolver = Resolver(resolvconf, servers)
549         hostResolver = hostsModule.Resolver(hosts)
550     else:
551         if hosts is None:
552             hosts = r'c:\windows\hosts'
553         from twisted.internet import reactor
554         bootstrap = _ThreadedResolverImpl(reactor)
555         hostResolver = hostsModule.Resolver(hosts)
556         theResolver = root.bootstrap(bootstrap)
557
558     L = [hostResolver, cache.CacheResolver(), theResolver]
559     return resolve.ResolverChain(L)
560
561 theResolver = None
562 def getResolver():
563     """
564     Get a Resolver instance.
565
566     Create twisted.names.client.theResolver if it is C{None}, and then return
567     that value.
568
569     @rtype: C{IResolver}
570     """
571     global theResolver
572     if theResolver is None:
573         try:
574             theResolver = createResolver()
575         except ValueError:
576             theResolver = createResolver(servers=[('127.0.0.1', 53)])
577     return theResolver
578
579 def getHostByName(name, timeout=None, effort=10):
580     """
581     Resolve a name to a valid ipv4 or ipv6 address.
582
583     Will errback with C{DNSQueryTimeoutError} on a timeout, C{DomainError} or
584     C{AuthoritativeDomainError} (or subclasses) on other errors.
585
586     @type name: C{str}
587     @param name: DNS name to resolve.
588
589     @type timeout: Sequence of C{int}
590     @param timeout: Number of seconds after which to reissue the query.
591     When the last timeout expires, the query is considered failed.
592
593     @type effort: C{int}
594     @param effort: How many times CNAME and NS records to follow while
595     resolving this name.
596
597     @rtype: C{Deferred}
598     """
599     return getResolver().getHostByName(name, timeout, effort)
600
601 def lookupAddress(name, timeout=None):
602     """
603     Perform an A record lookup.
604
605     @type name: C{str}
606     @param name: DNS name to resolve.
607
608     @type timeout: Sequence of C{int}
609     @param timeout: Number of seconds after which to reissue the query.
610     When the last timeout expires, the query is considered failed.
611
612     @rtype: C{Deferred}
613     """
614     return getResolver().lookupAddress(name, timeout)
615
616 def lookupIPV6Address(name, timeout=None):
617     """
618     Perform an AAAA record lookup.
619
620     @type name: C{str}
621     @param name: DNS name to resolve.
622
623     @type timeout: Sequence of C{int}
624     @param timeout: Number of seconds after which to reissue the query.
625     When the last timeout expires, the query is considered failed.
626
627     @rtype: C{Deferred}
628     """
629     return getResolver().lookupIPV6Address(name, timeout)
630
631 def lookupAddress6(name, timeout=None):
632     """
633     Perform an A6 record lookup.
634
635     @type name: C{str}
636     @param name: DNS name to resolve.
637
638     @type timeout: Sequence of C{int}
639     @param timeout: Number of seconds after which to reissue the query.
640     When the last timeout expires, the query is considered failed.
641
642     @rtype: C{Deferred}
643     """
644     return getResolver().lookupAddress6(name, timeout)
645
646 def lookupMailExchange(name, timeout=None):
647     """
648     Perform an MX record lookup.
649
650     @type name: C{str}
651     @param name: DNS name to resolve.
652
653     @type timeout: Sequence of C{int}
654     @param timeout: Number of seconds after which to reissue the query.
655     When the last timeout expires, the query is considered failed.
656
657     @rtype: C{Deferred}
658     """
659     return getResolver().lookupMailExchange(name, timeout)
660
661 def lookupNameservers(name, timeout=None):
662     """
663     Perform an NS record lookup.
664
665     @type name: C{str}
666     @param name: DNS name to resolve.
667
668     @type timeout: Sequence of C{int}
669     @param timeout: Number of seconds after which to reissue the query.
670     When the last timeout expires, the query is considered failed.
671
672     @rtype: C{Deferred}
673     """
674     return getResolver().lookupNameservers(name, timeout)
675
676 def lookupCanonicalName(name, timeout=None):
677     """
678     Perform a CNAME record lookup.
679
680     @type name: C{str}
681     @param name: DNS name to resolve.
682
683     @type timeout: Sequence of C{int}
684     @param timeout: Number of seconds after which to reissue the query.
685     When the last timeout expires, the query is considered failed.
686
687     @rtype: C{Deferred}
688     """
689     return getResolver().lookupCanonicalName(name, timeout)
690
691 def lookupMailBox(name, timeout=None):
692     """
693     Perform an MB record lookup.
694
695     @type name: C{str}
696     @param name: DNS name to resolve.
697
698     @type timeout: Sequence of C{int}
699     @param timeout: Number of seconds after which to reissue the query.
700     When the last timeout expires, the query is considered failed.
701
702     @rtype: C{Deferred}
703     """
704     return getResolver().lookupMailBox(name, timeout)
705
706 def lookupMailGroup(name, timeout=None):
707     """
708     Perform an MG record lookup.
709
710     @type name: C{str}
711     @param name: DNS name to resolve.
712
713     @type timeout: Sequence of C{int}
714     @param timeout: Number of seconds after which to reissue the query.
715     When the last timeout expires, the query is considered failed.
716
717     @rtype: C{Deferred}
718     """
719     return getResolver().lookupMailGroup(name, timeout)
720
721 def lookupMailRename(name, timeout=None):
722     """
723     Perform an MR record lookup.
724
725     @type name: C{str}
726     @param name: DNS name to resolve.
727
728     @type timeout: Sequence of C{int}
729     @param timeout: Number of seconds after which to reissue the query.
730     When the last timeout expires, the query is considered failed.
731
732     @rtype: C{Deferred}
733     """
734     return getResolver().lookupMailRename(name, timeout)
735
736 def lookupPointer(name, timeout=None):
737     """
738     Perform a PTR record lookup.
739
740     @type name: C{str}
741     @param name: DNS name to resolve.
742
743     @type timeout: Sequence of C{int}
744     @param timeout: Number of seconds after which to reissue the query.
745     When the last timeout expires, the query is considered failed.
746
747     @rtype: C{Deferred}
748     """
749     return getResolver().lookupPointer(name, timeout)
750
751 def lookupAuthority(name, timeout=None):
752     """
753     Perform an SOA record lookup.
754
755     @type name: C{str}
756     @param name: DNS name to resolve.
757
758     @type timeout: Sequence of C{int}
759     @param timeout: Number of seconds after which to reissue the query.
760     When the last timeout expires, the query is considered failed.
761
762     @rtype: C{Deferred}
763     """
764     return getResolver().lookupAuthority(name, timeout)
765
766 def lookupNull(name, timeout=None):
767     """
768     Perform a NULL record lookup.
769
770     @type name: C{str}
771     @param name: DNS name to resolve.
772
773     @type timeout: Sequence of C{int}
774     @param timeout: Number of seconds after which to reissue the query.
775     When the last timeout expires, the query is considered failed.
776
777     @rtype: C{Deferred}
778     """
779     return getResolver().lookupNull(name, timeout)
780
781 def lookupWellKnownServices(name, timeout=None):
782     """
783     Perform a WKS record lookup.
784
785     @type name: C{str}
786     @param name: DNS name to resolve.
787
788     @type timeout: Sequence of C{int}
789     @param timeout: Number of seconds after which to reissue the query.
790     When the last timeout expires, the query is considered failed.
791
792     @rtype: C{Deferred}
793     """
794     return getResolver().lookupWellKnownServices(name, timeout)
795
796 def lookupService(name, timeout=None):
797     """
798     Perform an SRV record lookup.
799
800     @type name: C{str}
801     @param name: DNS name to resolve.
802
803     @type timeout: Sequence of C{int}
804     @param timeout: Number of seconds after which to reissue the query.
805     When the last timeout expires, the query is considered failed.
806
807     @rtype: C{Deferred}
808     """
809     return getResolver().lookupService(name, timeout)
810
811 def lookupHostInfo(name, timeout=None):
812     """
813     Perform a HINFO record lookup.
814
815     @type name: C{str}
816     @param name: DNS name to resolve.
817
818     @type timeout: Sequence of C{int}
819     @param timeout: Number of seconds after which to reissue the query.
820     When the last timeout expires, the query is considered failed.
821
822     @rtype: C{Deferred}
823     """
824     return getResolver().lookupHostInfo(name, timeout)
825
826 def lookupMailboxInfo(name, timeout=None):
827     """
828     Perform an MINFO record lookup.
829
830     @type name: C{str}
831     @param name: DNS name to resolve.
832
833     @type timeout: Sequence of C{int}
834     @param timeout: Number of seconds after which to reissue the query.
835     When the last timeout expires, the query is considered failed.
836
837     @rtype: C{Deferred}
838     """
839     return getResolver().lookupMailboxInfo(name, timeout)
840
841 def lookupText(name, timeout=None):
842     """
843     Perform a TXT record lookup.
844
845     @type name: C{str}
846     @param name: DNS name to resolve.
847
848     @type timeout: Sequence of C{int}
849     @param timeout: Number of seconds after which to reissue the query.
850     When the last timeout expires, the query is considered failed.
851
852     @rtype: C{Deferred}
853     """
854     return getResolver().lookupText(name, timeout)
855
856 def lookupResponsibility(name, timeout=None):
857     """
858     Perform an RP record lookup.
859
860     @type name: C{str}
861     @param name: DNS name to resolve.
862
863     @type timeout: Sequence of C{int}
864     @param timeout: Number of seconds after which to reissue the query.
865     When the last timeout expires, the query is considered failed.
866
867     @rtype: C{Deferred}
868     """
869     return getResolver().lookupResponsibility(name, timeout)
870
871 def lookupAFSDatabase(name, timeout=None):
872     """
873     Perform an AFSDB record lookup.
874
875     @type name: C{str}
876     @param name: DNS name to resolve.
877
878     @type timeout: Sequence of C{int}
879     @param timeout: Number of seconds after which to reissue the query.
880     When the last timeout expires, the query is considered failed.
881
882     @rtype: C{Deferred}
883     """
884     return getResolver().lookupAFSDatabase(name, timeout)
885
886 def lookupZone(name, timeout=None):
887     """
888     Perform an AXFR record lookup.
889
890     @type name: C{str}
891     @param name: DNS name to resolve.
892
893     @type timeout: C{int}
894     @param timeout: When this timeout expires, the query is considered failed.
895
896     @rtype: C{Deferred}
897     """
898     # XXX: timeout here is not a list of ints, it is a single int.
899     return getResolver().lookupZone(name, timeout)
900
901 def lookupAllRecords(name, timeout=None):
902     """
903     ALL_RECORD lookup.
904
905     @type name: C{str}
906     @param name: DNS name to resolve.
907
908     @type timeout: Sequence of C{int}
909     @param timeout: Number of seconds after which to reissue the query.
910     When the last timeout expires, the query is considered failed.
911
912     @rtype: C{Deferred}
913     """
914     return getResolver().lookupAllRecords(name, timeout)
915
916
917
918 def lookupNamingAuthorityPointer(name, timeout=None):
919     """
920     NAPTR lookup.
921
922     @type name: C{str}
923     @param name: DNS name to resolve.
924
925     @type timeout: Sequence of C{int}
926     @param timeout: Number of seconds after which to reissue the query.
927         When the last timeout expires, the query is considered failed.
928
929     @rtype: C{Deferred}
930     """
931     return getResolver().lookupNamingAuthorityPointer(name, timeout)
Note: See TracBrowser for help on using the browser.