1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """DNS stub resolver.
17
18 @var default_resolver: The default resolver object
19 @type default_resolver: dns.resolver.Resolver object"""
20
21 import socket
22 import sys
23 import time
24 import random
25
26 try:
27 import threading as _threading
28 except ImportError:
29 import dummy_threading as _threading
30
31 import dns.exception
32 import dns.flags
33 import dns.ipv4
34 import dns.ipv6
35 import dns.message
36 import dns.name
37 import dns.query
38 import dns.rcode
39 import dns.rdataclass
40 import dns.rdatatype
41 import dns.reversename
42 import dns.tsig
43 from ._compat import xrange, string_types
44
45 if sys.platform == 'win32':
46 try:
47 import winreg as _winreg
48 except ImportError:
49 import _winreg
50
51 -class NXDOMAIN(dns.exception.DNSException):
52
53 """The DNS query name does not exist."""
54 supp_kwargs = set(['qnames', 'responses'])
55 fmt = None
56
57 - def _check_kwargs(self, qnames, responses=None):
58 if not isinstance(qnames, (list, tuple, set)):
59 raise AttributeError("qnames must be a list, tuple or set")
60 if len(qnames) == 0:
61 raise AttributeError("qnames must contain at least one element")
62 if responses is None:
63 responses = {}
64 elif not isinstance(responses, dict):
65 raise AttributeError("responses must be a dict(qname=response)")
66 kwargs = dict(qnames=qnames, responses=responses)
67 return kwargs
68
70 if 'qnames' not in self.kwargs:
71 return super(NXDOMAIN, self).__str__()
72 qnames = self.kwargs['qnames']
73 if len(qnames) > 1:
74 msg = 'None of DNS query names exist'
75 else:
76 msg = self.__doc__[:-1]
77 qnames = ', '.join(map(str, qnames))
78 return "%s: %s" % (msg, qnames)
79
80 - def canonical_name(self):
81 if not 'qnames' in self.kwargs:
82 raise TypeError("parametrized exception required")
83 IN = dns.rdataclass.IN
84 CNAME = dns.rdatatype.CNAME
85 cname = None
86 for qname in self.kwargs['qnames']:
87 response = self.kwargs['responses'][qname]
88 for answer in response.answer:
89 if answer.rdtype != CNAME or answer.rdclass != IN:
90 continue
91 cname = answer.items[0].target.to_text()
92 if cname is not None:
93 return dns.name.from_text(cname)
94 return self.kwargs['qnames'][0]
95 canonical_name = property(canonical_name, doc=(
96 "Return the unresolved canonical name."))
97
98 - def __add__(self, e_nx):
99 """Augment by results from another NXDOMAIN exception."""
100 qnames0 = list(self.kwargs.get('qnames', []))
101 responses0 = dict(self.kwargs.get('responses', {}))
102 responses1 = e_nx.kwargs.get('responses', {})
103 for qname1 in e_nx.kwargs.get('qnames', []):
104 if qname1 not in qnames0:
105 qnames0.append(qname1)
106 if qname1 in responses1:
107 responses0[qname1] = responses1[qname1]
108 return NXDOMAIN(qnames=qnames0, responses=responses0)
109
110
111 -class YXDOMAIN(dns.exception.DNSException):
112
113 """The DNS query name is too long after DNAME substitution."""
114
115
116
117
118
119 Timeout = dns.exception.Timeout
120
121
122 -class NoAnswer(dns.exception.DNSException):
123
124 """The DNS response does not contain an answer to the question."""
125 fmt = 'The DNS response does not contain an answer ' + \
126 'to the question: {query}'
127 supp_kwargs = set(['response'])
128
132
133
135
136 """All nameservers failed to answer the query.
137
138 errors: list of servers and respective errors
139 The type of errors is
140 [(server ip address, any object convertible to string)].
141 Non-empty errors list will add explanatory message ()
142 """
143
144 msg = "All nameservers failed to answer the query."
145 fmt = "%s {query}: {errors}" % msg[:-1]
146 supp_kwargs = set(['request', 'errors'])
147
149 srv_msgs = []
150 for err in kwargs['errors']:
151 srv_msgs.append('Server %s %s port %s answered %s' % (err[0],
152 'TCP' if err[1] else 'UDP', err[2], err[3]))
153 return super(NoNameservers, self)._fmt_kwargs(
154 query=kwargs['request'].question, errors='; '.join(srv_msgs))
155
156
158
159 """An absolute domain name is required but a relative name was provided."""
160
161
163
164 """There is no SOA RR at the DNS root name. This should never happen!"""
165
166
170
171
173
174 """DNS stub resolver answer
175
176 Instances of this class bundle up the result of a successful DNS
177 resolution.
178
179 For convenience, the answer object implements much of the sequence
180 protocol, forwarding to its rrset. E.g. "for a in answer" is
181 equivalent to "for a in answer.rrset", "answer[i]" is equivalent
182 to "answer.rrset[i]", and "answer[i:j]" is equivalent to
183 "answer.rrset[i:j]".
184
185 Note that CNAMEs or DNAMEs in the response may mean that answer
186 node's name might not be the query name.
187
188 @ivar qname: The query name
189 @type qname: dns.name.Name object
190 @ivar rdtype: The query type
191 @type rdtype: int
192 @ivar rdclass: The query class
193 @type rdclass: int
194 @ivar response: The response message
195 @type response: dns.message.Message object
196 @ivar rrset: The answer
197 @type rrset: dns.rrset.RRset object
198 @ivar expiration: The time when the answer expires
199 @type expiration: float (seconds since the epoch)
200 @ivar canonical_name: The canonical name of the query name
201 @type canonical_name: dns.name.Name object
202 """
203
204 - def __init__(self, qname, rdtype, rdclass, response,
205 raise_on_no_answer=True):
206 self.qname = qname
207 self.rdtype = rdtype
208 self.rdclass = rdclass
209 self.response = response
210 min_ttl = -1
211 rrset = None
212 for count in xrange(0, 15):
213 try:
214 rrset = response.find_rrset(response.answer, qname,
215 rdclass, rdtype)
216 if min_ttl == -1 or rrset.ttl < min_ttl:
217 min_ttl = rrset.ttl
218 break
219 except KeyError:
220 if rdtype != dns.rdatatype.CNAME:
221 try:
222 crrset = response.find_rrset(response.answer,
223 qname,
224 rdclass,
225 dns.rdatatype.CNAME)
226 if min_ttl == -1 or crrset.ttl < min_ttl:
227 min_ttl = crrset.ttl
228 for rd in crrset:
229 qname = rd.target
230 break
231 continue
232 except KeyError:
233 if raise_on_no_answer:
234 raise NoAnswer(response=response)
235 if raise_on_no_answer:
236 raise NoAnswer(response=response)
237 if rrset is None and raise_on_no_answer:
238 raise NoAnswer(response=response)
239 self.canonical_name = qname
240 self.rrset = rrset
241 if rrset is None:
242 while 1:
243
244
245 try:
246 srrset = response.find_rrset(response.authority, qname,
247 rdclass, dns.rdatatype.SOA)
248 if min_ttl == -1 or srrset.ttl < min_ttl:
249 min_ttl = srrset.ttl
250 if srrset[0].minimum < min_ttl:
251 min_ttl = srrset[0].minimum
252 break
253 except KeyError:
254 try:
255 qname = qname.parent()
256 except dns.name.NoParent:
257 break
258 self.expiration = time.time() + min_ttl
259
261 if attr == 'name':
262 return self.rrset.name
263 elif attr == 'ttl':
264 return self.rrset.ttl
265 elif attr == 'covers':
266 return self.rrset.covers
267 elif attr == 'rdclass':
268 return self.rrset.rdclass
269 elif attr == 'rdtype':
270 return self.rrset.rdtype
271 else:
272 raise AttributeError(attr)
273
276
278 return self.rrset and iter(self.rrset) or iter(tuple())
279
282
285
286
288
289 """Simple DNS answer cache.
290
291 @ivar data: A dictionary of cached data
292 @type data: dict
293 @ivar cleaning_interval: The number of seconds between cleanings. The
294 default is 300 (5 minutes).
295 @type cleaning_interval: float
296 @ivar next_cleaning: The time the cache should next be cleaned (in seconds
297 since the epoch.)
298 @type next_cleaning: float
299 """
300
301 - def __init__(self, cleaning_interval=300.0):
302 """Initialize a DNS cache.
303
304 @param cleaning_interval: the number of seconds between periodic
305 cleanings. The default is 300.0
306 @type cleaning_interval: float.
307 """
308
309 self.data = {}
310 self.cleaning_interval = cleaning_interval
311 self.next_cleaning = time.time() + self.cleaning_interval
312 self.lock = _threading.Lock()
313
315 """Clean the cache if it's time to do so."""
316
317 now = time.time()
318 if self.next_cleaning <= now:
319 keys_to_delete = []
320 for (k, v) in self.data.items():
321 if v.expiration <= now:
322 keys_to_delete.append(k)
323 for k in keys_to_delete:
324 del self.data[k]
325 now = time.time()
326 self.next_cleaning = now + self.cleaning_interval
327
328 - def get(self, key):
329 """Get the answer associated with I{key}. Returns None if
330 no answer is cached for the key.
331 @param key: the key
332 @type key: (dns.name.Name, int, int) tuple whose values are the
333 query name, rdtype, and rdclass.
334 @rtype: dns.resolver.Answer object or None
335 """
336
337 try:
338 self.lock.acquire()
339 self._maybe_clean()
340 v = self.data.get(key)
341 if v is None or v.expiration <= time.time():
342 return None
343 return v
344 finally:
345 self.lock.release()
346
347 - def put(self, key, value):
348 """Associate key and value in the cache.
349 @param key: the key
350 @type key: (dns.name.Name, int, int) tuple whose values are the
351 query name, rdtype, and rdclass.
352 @param value: The answer being cached
353 @type value: dns.resolver.Answer object
354 """
355
356 try:
357 self.lock.acquire()
358 self._maybe_clean()
359 self.data[key] = value
360 finally:
361 self.lock.release()
362
363 - def flush(self, key=None):
364 """Flush the cache.
365
366 If I{key} is specified, only that item is flushed. Otherwise
367 the entire cache is flushed.
368
369 @param key: the key to flush
370 @type key: (dns.name.Name, int, int) tuple or None
371 """
372
373 try:
374 self.lock.acquire()
375 if key is not None:
376 if key in self.data:
377 del self.data[key]
378 else:
379 self.data = {}
380 self.next_cleaning = time.time() + self.cleaning_interval
381 finally:
382 self.lock.release()
383
384
386
387 """LRUCache node.
388 """
389
395
401
407
409 self.next.prev = self.prev
410 self.prev.next = self.next
411
412
414
415 """Bounded least-recently-used DNS answer cache.
416
417 This cache is better than the simple cache (above) if you're
418 running a web crawler or other process that does a lot of
419 resolutions. The LRUCache has a maximum number of nodes, and when
420 it is full, the least-recently used node is removed to make space
421 for a new one.
422
423 @ivar data: A dictionary of cached data
424 @type data: dict
425 @ivar sentinel: sentinel node for circular doubly linked list of nodes
426 @type sentinel: LRUCacheNode object
427 @ivar max_size: The maximum number of nodes
428 @type max_size: int
429 """
430
432 """Initialize a DNS cache.
433
434 @param max_size: The maximum number of nodes to cache; the default is
435 100,000. Must be greater than 1.
436 @type max_size: int
437 """
438 self.data = {}
439 self.set_max_size(max_size)
440 self.sentinel = LRUCacheNode(None, None)
441 self.lock = _threading.Lock()
442
444 if max_size < 1:
445 max_size = 1
446 self.max_size = max_size
447
448 - def get(self, key):
449 """Get the answer associated with I{key}. Returns None if
450 no answer is cached for the key.
451 @param key: the key
452 @type key: (dns.name.Name, int, int) tuple whose values are the
453 query name, rdtype, and rdclass.
454 @rtype: dns.resolver.Answer object or None
455 """
456 try:
457 self.lock.acquire()
458 node = self.data.get(key)
459 if node is None:
460 return None
461
462
463 node.unlink()
464 if node.value.expiration <= time.time():
465 del self.data[node.key]
466 return None
467 node.link_after(self.sentinel)
468 return node.value
469 finally:
470 self.lock.release()
471
472 - def put(self, key, value):
473 """Associate key and value in the cache.
474 @param key: the key
475 @type key: (dns.name.Name, int, int) tuple whose values are the
476 query name, rdtype, and rdclass.
477 @param value: The answer being cached
478 @type value: dns.resolver.Answer object
479 """
480 try:
481 self.lock.acquire()
482 node = self.data.get(key)
483 if node is not None:
484 node.unlink()
485 del self.data[node.key]
486 while len(self.data) >= self.max_size:
487 node = self.sentinel.prev
488 node.unlink()
489 del self.data[node.key]
490 node = LRUCacheNode(key, value)
491 node.link_after(self.sentinel)
492 self.data[key] = node
493 finally:
494 self.lock.release()
495
496 - def flush(self, key=None):
497 """Flush the cache.
498
499 If I{key} is specified, only that item is flushed. Otherwise
500 the entire cache is flushed.
501
502 @param key: the key to flush
503 @type key: (dns.name.Name, int, int) tuple or None
504 """
505 try:
506 self.lock.acquire()
507 if key is not None:
508 node = self.data.get(key)
509 if node is not None:
510 node.unlink()
511 del self.data[node.key]
512 else:
513 node = self.sentinel.next
514 while node != self.sentinel:
515 next = node.next
516 node.prev = None
517 node.next = None
518 node = next
519 self.data = {}
520 finally:
521 self.lock.release()
522
523
525
526 """DNS stub resolver
527
528 @ivar domain: The domain of this host
529 @type domain: dns.name.Name object
530 @ivar nameservers: A list of nameservers to query. Each nameserver is
531 a string which contains the IP address of a nameserver.
532 @type nameservers: list of strings
533 @ivar search: The search list. If the query name is a relative name,
534 the resolver will construct an absolute query name by appending the search
535 names one by one to the query name.
536 @type search: list of dns.name.Name objects
537 @ivar port: The port to which to send queries. The default is 53.
538 @type port: int
539 @ivar timeout: The number of seconds to wait for a response from a
540 server, before timing out.
541 @type timeout: float
542 @ivar lifetime: The total number of seconds to spend trying to get an
543 answer to the question. If the lifetime expires, a Timeout exception
544 will occur.
545 @type lifetime: float
546 @ivar keyring: The TSIG keyring to use. The default is None.
547 @type keyring: dict
548 @ivar keyname: The TSIG keyname to use. The default is None.
549 @type keyname: dns.name.Name object
550 @ivar keyalgorithm: The TSIG key algorithm to use. The default is
551 dns.tsig.default_algorithm.
552 @type keyalgorithm: string
553 @ivar edns: The EDNS level to use. The default is -1, no Edns.
554 @type edns: int
555 @ivar ednsflags: The EDNS flags
556 @type ednsflags: int
557 @ivar payload: The EDNS payload size. The default is 0.
558 @type payload: int
559 @ivar flags: The message flags to use. The default is None (i.e. not
560 overwritten)
561 @type flags: int
562 @ivar cache: The cache to use. The default is None.
563 @type cache: dns.resolver.Cache object
564 @ivar retry_servfail: should we retry a nameserver if it says SERVFAIL?
565 The default is 'false'.
566 @type retry_servfail: bool
567 """
568
569 - def __init__(self, filename='/etc/resolv.conf', configure=True):
570 """Initialize a resolver instance.
571
572 @param filename: The filename of a configuration file in
573 standard /etc/resolv.conf format. This parameter is meaningful
574 only when I{configure} is true and the platform is POSIX.
575 @type filename: string or file object
576 @param configure: If True (the default), the resolver instance
577 is configured in the normal fashion for the operating system
578 the resolver is running on. (I.e. a /etc/resolv.conf file on
579 POSIX systems and from the registry on Windows systems.)
580 @type configure: bool"""
581
582 self.domain = None
583 self.nameservers = None
584 self.nameserver_ports = None
585 self.port = None
586 self.search = None
587 self.timeout = None
588 self.lifetime = None
589 self.keyring = None
590 self.keyname = None
591 self.keyalgorithm = None
592 self.edns = None
593 self.ednsflags = None
594 self.payload = None
595 self.cache = None
596 self.flags = None
597 self.retry_servfail = False
598 self.rotate = False
599
600 self.reset()
601 if configure:
602 if sys.platform == 'win32':
603 self.read_registry()
604 elif filename:
605 self.read_resolv_conf(filename)
606
608 """Reset all resolver configuration to the defaults."""
609 self.domain = \
610 dns.name.Name(dns.name.from_text(socket.gethostname())[1:])
611 if len(self.domain) == 0:
612 self.domain = dns.name.root
613 self.nameservers = []
614 self.nameserver_ports = {}
615 self.port = 53
616 self.search = []
617 self.timeout = 2.0
618 self.lifetime = 30.0
619 self.keyring = None
620 self.keyname = None
621 self.keyalgorithm = dns.tsig.default_algorithm
622 self.edns = -1
623 self.ednsflags = 0
624 self.payload = 0
625 self.cache = None
626 self.flags = None
627 self.retry_servfail = False
628 self.rotate = False
629
631 """Process f as a file in the /etc/resolv.conf format. If f is
632 a string, it is used as the name of the file to open; otherwise it
633 is treated as the file itself."""
634 if isinstance(f, string_types):
635 try:
636 f = open(f, 'r')
637 except IOError:
638
639
640 self.nameservers = ['127.0.0.1']
641 return
642 want_close = True
643 else:
644 want_close = False
645 try:
646 for l in f:
647 if len(l) == 0 or l[0] == '#' or l[0] == ';':
648 continue
649 tokens = l.split()
650
651
652 if len(tokens) < 2:
653 continue
654
655 if tokens[0] == 'nameserver':
656 self.nameservers.append(tokens[1])
657 elif tokens[0] == 'domain':
658 self.domain = dns.name.from_text(tokens[1])
659 elif tokens[0] == 'search':
660 for suffix in tokens[1:]:
661 self.search.append(dns.name.from_text(suffix))
662 elif tokens[0] == 'options':
663 if 'rotate' in tokens[1:]:
664 self.rotate = True
665 finally:
666 if want_close:
667 f.close()
668 if len(self.nameservers) == 0:
669 self.nameservers.append('127.0.0.1')
670
672
673
674
675
676
677 if entry.find(' ') >= 0:
678 split_char = ' '
679 elif entry.find(',') >= 0:
680 split_char = ','
681 else:
682
683 split_char = ' '
684 return split_char
685
687 """Configure a NameServer registry entry."""
688
689 nameservers = str(nameservers)
690 split_char = self._determine_split_char(nameservers)
691 ns_list = nameservers.split(split_char)
692 for ns in ns_list:
693 if ns not in self.nameservers:
694 self.nameservers.append(ns)
695
696 - def _config_win32_domain(self, domain):
697 """Configure a Domain registry entry."""
698
699 self.domain = dns.name.from_text(str(domain))
700
702 """Configure a Search registry entry."""
703
704 search = str(search)
705 split_char = self._determine_split_char(search)
706 search_list = search.split(split_char)
707 for s in search_list:
708 if s not in self.search:
709 self.search.append(dns.name.from_text(s))
710
712 """Extract DNS info from a registry key."""
713 try:
714 servers, rtype = _winreg.QueryValueEx(key, 'NameServer')
715 except WindowsError:
716 servers = None
717 if servers:
718 self._config_win32_nameservers(servers)
719 try:
720 dom, rtype = _winreg.QueryValueEx(key, 'Domain')
721 if dom:
722 self._config_win32_domain(dom)
723 except WindowsError:
724 pass
725 else:
726 try:
727 servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer')
728 except WindowsError:
729 servers = None
730 if servers:
731 self._config_win32_nameservers(servers)
732 try:
733 dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain')
734 if dom:
735 self._config_win32_domain(dom)
736 except WindowsError:
737 pass
738 try:
739 search, rtype = _winreg.QueryValueEx(key, 'SearchList')
740 except WindowsError:
741 search = None
742 if search:
743 self._config_win32_search(search)
744
746 """Extract resolver configuration from the Windows registry."""
747 lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
748 want_scan = False
749 try:
750 try:
751
752 tcp_params = _winreg.OpenKey(lm,
753 r'SYSTEM\CurrentControlSet'
754 r'\Services\Tcpip\Parameters')
755 want_scan = True
756 except EnvironmentError:
757
758 tcp_params = _winreg.OpenKey(lm,
759 r'SYSTEM\CurrentControlSet'
760 r'\Services\VxD\MSTCP')
761 try:
762 self._config_win32_fromkey(tcp_params)
763 finally:
764 tcp_params.Close()
765 if want_scan:
766 interfaces = _winreg.OpenKey(lm,
767 r'SYSTEM\CurrentControlSet'
768 r'\Services\Tcpip\Parameters'
769 r'\Interfaces')
770 try:
771 i = 0
772 while True:
773 try:
774 guid = _winreg.EnumKey(interfaces, i)
775 i += 1
776 key = _winreg.OpenKey(interfaces, guid)
777 if not self._win32_is_nic_enabled(lm, guid, key):
778 continue
779 try:
780 self._config_win32_fromkey(key)
781 finally:
782 key.Close()
783 except EnvironmentError:
784 break
785 finally:
786 interfaces.Close()
787 finally:
788 lm.Close()
789
791
792
793
794
795
796 try:
797
798
799 connection_key = _winreg.OpenKey(
800 lm,
801 r'SYSTEM\CurrentControlSet\Control\Network'
802 r'\{4D36E972-E325-11CE-BFC1-08002BE10318}'
803 r'\%s\Connection' % guid)
804
805 try:
806
807 (pnp_id, ttype) = _winreg.QueryValueEx(
808 connection_key, 'PnpInstanceID')
809
810 if ttype != _winreg.REG_SZ:
811 raise ValueError
812
813 device_key = _winreg.OpenKey(
814 lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id)
815
816 try:
817
818 (flags, ttype) = _winreg.QueryValueEx(
819 device_key, 'ConfigFlags')
820
821 if ttype != _winreg.REG_DWORD:
822 raise ValueError
823
824
825
826 return not flags & 0x1
827
828 finally:
829 device_key.Close()
830 finally:
831 connection_key.Close()
832 except (EnvironmentError, ValueError):
833
834
835
836
837
838 try:
839 (nte, ttype) = _winreg.QueryValueEx(interface_key,
840 'NTEContextList')
841 return nte is not None
842 except WindowsError:
843 return False
844
846 now = time.time()
847 duration = now - start
848 if duration < 0:
849 if duration < -1:
850
851 raise Timeout(timeout=duration)
852 else:
853
854
855
856 now = start
857 if duration >= self.lifetime:
858 raise Timeout(timeout=duration)
859 return min(self.lifetime - duration, self.timeout)
860
863 """Query nameservers to find the answer to the question.
864
865 The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects
866 of the appropriate type, or strings that can be converted into objects
867 of the appropriate type. E.g. For I{rdtype} the integer 2 and the
868 the string 'NS' both mean to query for records with DNS rdata type NS.
869
870 @param qname: the query name
871 @type qname: dns.name.Name object or string
872 @param rdtype: the query type
873 @type rdtype: int or string
874 @param rdclass: the query class
875 @type rdclass: int or string
876 @param tcp: use TCP to make the query (default is False).
877 @type tcp: bool
878 @param source: bind to this IP address (defaults to machine default
879 IP).
880 @type source: IP address in dotted quad notation
881 @param raise_on_no_answer: raise NoAnswer if there's no answer
882 (defaults is True).
883 @type raise_on_no_answer: bool
884 @param source_port: The port from which to send the message.
885 The default is 0.
886 @type source_port: int
887 @rtype: dns.resolver.Answer instance
888 @raises Timeout: no answers could be found in the specified lifetime
889 @raises NXDOMAIN: the query name does not exist
890 @raises YXDOMAIN: the query name is too long after DNAME substitution
891 @raises NoAnswer: the response did not contain an answer and
892 raise_on_no_answer is True.
893 @raises NoNameservers: no non-broken nameservers are available to
894 answer the question."""
895
896 if isinstance(qname, string_types):
897 qname = dns.name.from_text(qname, None)
898 if isinstance(rdtype, string_types):
899 rdtype = dns.rdatatype.from_text(rdtype)
900 if dns.rdatatype.is_metatype(rdtype):
901 raise NoMetaqueries
902 if isinstance(rdclass, string_types):
903 rdclass = dns.rdataclass.from_text(rdclass)
904 if dns.rdataclass.is_metaclass(rdclass):
905 raise NoMetaqueries
906 qnames_to_try = []
907 if qname.is_absolute():
908 qnames_to_try.append(qname)
909 else:
910 if len(qname) > 1:
911 qnames_to_try.append(qname.concatenate(dns.name.root))
912 if self.search:
913 for suffix in self.search:
914 qnames_to_try.append(qname.concatenate(suffix))
915 else:
916 qnames_to_try.append(qname.concatenate(self.domain))
917 all_nxdomain = True
918 nxdomain_responses = {}
919 start = time.time()
920 _qname = None
921 for _qname in qnames_to_try:
922 if self.cache:
923 answer = self.cache.get((_qname, rdtype, rdclass))
924 if answer is not None:
925 if answer.rrset is None and raise_on_no_answer:
926 raise NoAnswer(response=answer.response)
927 else:
928 return answer
929 request = dns.message.make_query(_qname, rdtype, rdclass)
930 if self.keyname is not None:
931 request.use_tsig(self.keyring, self.keyname,
932 algorithm=self.keyalgorithm)
933 request.use_edns(self.edns, self.ednsflags, self.payload)
934 if self.flags is not None:
935 request.flags = self.flags
936 response = None
937
938
939
940 nameservers = self.nameservers[:]
941 errors = []
942 if self.rotate:
943 random.shuffle(nameservers)
944 backoff = 0.10
945 while response is None:
946 if len(nameservers) == 0:
947 raise NoNameservers(request=request, errors=errors)
948 for nameserver in nameservers[:]:
949 timeout = self._compute_timeout(start)
950 port = self.nameserver_ports.get(nameserver, self.port)
951 try:
952 tcp_attempt = tcp
953 if tcp:
954 response = dns.query.tcp(request, nameserver,
955 timeout, port,
956 source=source,
957 source_port=source_port)
958 else:
959 response = dns.query.udp(request, nameserver,
960 timeout, port,
961 source=source,
962 source_port=source_port)
963 if response.flags & dns.flags.TC:
964
965 tcp_attempt = True
966 timeout = self._compute_timeout(start)
967 response = \
968 dns.query.tcp(request, nameserver,
969 timeout, port,
970 source=source,
971 source_port=source_port)
972 except (socket.error, dns.exception.Timeout) as ex:
973
974
975
976
977 errors.append((nameserver, tcp_attempt, port, ex,
978 response))
979 response = None
980 continue
981 except dns.query.UnexpectedSource as ex:
982
983
984
985 errors.append((nameserver, tcp_attempt, port, ex,
986 response))
987 response = None
988 continue
989 except dns.exception.FormError as ex:
990
991
992
993
994
995 nameservers.remove(nameserver)
996 errors.append((nameserver, tcp_attempt, port, ex,
997 response))
998 response = None
999 continue
1000 except EOFError as ex:
1001
1002
1003
1004
1005
1006
1007 nameservers.remove(nameserver)
1008 errors.append((nameserver, tcp_attempt, port, ex,
1009 response))
1010 response = None
1011 continue
1012 rcode = response.rcode()
1013 if rcode == dns.rcode.YXDOMAIN:
1014 ex = YXDOMAIN()
1015 errors.append((nameserver, tcp_attempt, port, ex,
1016 response))
1017 raise ex
1018 if rcode == dns.rcode.NOERROR or \
1019 rcode == dns.rcode.NXDOMAIN:
1020 break
1021
1022
1023
1024
1025
1026 if rcode != dns.rcode.SERVFAIL or not self.retry_servfail:
1027 nameservers.remove(nameserver)
1028 errors.append((nameserver, tcp_attempt, port,
1029 dns.rcode.to_text(rcode), response))
1030 response = None
1031 if response is not None:
1032 break
1033
1034
1035
1036 if len(nameservers) > 0:
1037
1038
1039
1040
1041 timeout = self._compute_timeout(start)
1042 sleep_time = min(timeout, backoff)
1043 backoff *= 2
1044 time.sleep(sleep_time)
1045 if response.rcode() == dns.rcode.NXDOMAIN:
1046 nxdomain_responses[_qname] = response
1047 continue
1048 all_nxdomain = False
1049 break
1050 if all_nxdomain:
1051 raise NXDOMAIN(qnames=qnames_to_try, responses=nxdomain_responses)
1052 answer = Answer(_qname, rdtype, rdclass, response,
1053 raise_on_no_answer)
1054 if self.cache:
1055 self.cache.put((_qname, rdtype, rdclass), answer)
1056 return answer
1057
1060 """Add a TSIG signature to the query.
1061
1062 @param keyring: The TSIG keyring to use; defaults to None.
1063 @type keyring: dict
1064 @param keyname: The name of the TSIG key to use; defaults to None.
1065 The key must be defined in the keyring. If a keyring is specified
1066 but a keyname is not, then the key used will be the first key in the
1067 keyring. Note that the order of keys in a dictionary is not defined,
1068 so applications should supply a keyname when a keyring is used, unless
1069 they know the keyring contains only one key.
1070 @param algorithm: The TSIG key algorithm to use. The default
1071 is dns.tsig.default_algorithm.
1072 @type algorithm: string"""
1073 self.keyring = keyring
1074 if keyname is None:
1075 self.keyname = list(self.keyring.keys())[0]
1076 else:
1077 self.keyname = keyname
1078 self.keyalgorithm = algorithm
1079
1080 - def use_edns(self, edns, ednsflags, payload):
1081 """Configure Edns.
1082
1083 @param edns: The EDNS level to use. The default is -1, no Edns.
1084 @type edns: int
1085 @param ednsflags: The EDNS flags
1086 @type ednsflags: int
1087 @param payload: The EDNS payload size. The default is 0.
1088 @type payload: int"""
1089
1090 if edns is None:
1091 edns = -1
1092 self.edns = edns
1093 self.ednsflags = ednsflags
1094 self.payload = payload
1095
1097 """Overrides the default flags with your own
1098
1099 @param flags: The flags to overwrite the default with
1100 @type flags: int"""
1101 self.flags = flags
1102
1103 default_resolver = None
1104
1105
1111
1112
1120
1121
1125 """Query nameservers to find the answer to the question.
1126
1127 This is a convenience function that uses the default resolver
1128 object to make the query.
1129 @see: L{dns.resolver.Resolver.query} for more information on the
1130 parameters."""
1131 return get_default_resolver().query(qname, rdtype, rdclass, tcp, source,
1132 raise_on_no_answer, source_port)
1133
1134
1166
1167
1168
1169
1170
1171
1172 _protocols_for_socktype = {
1173 socket.SOCK_DGRAM: [socket.SOL_UDP],
1174 socket.SOCK_STREAM: [socket.SOL_TCP],
1175 }
1176
1177 _resolver = None
1178 _original_getaddrinfo = socket.getaddrinfo
1179 _original_getnameinfo = socket.getnameinfo
1180 _original_getfqdn = socket.getfqdn
1181 _original_gethostbyname = socket.gethostbyname
1182 _original_gethostbyname_ex = socket.gethostbyname_ex
1183 _original_gethostbyaddr = socket.gethostbyaddr
1184
1185
1186 -def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0,
1187 proto=0, flags=0):
1188 if flags & (socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) != 0:
1189 raise NotImplementedError
1190 if host is None and service is None:
1191 raise socket.gaierror(socket.EAI_NONAME)
1192 v6addrs = []
1193 v4addrs = []
1194 canonical_name = None
1195 try:
1196
1197 if host is None:
1198 canonical_name = 'localhost'
1199 if flags & socket.AI_PASSIVE != 0:
1200 v6addrs.append('::')
1201 v4addrs.append('0.0.0.0')
1202 else:
1203 v6addrs.append('::1')
1204 v4addrs.append('127.0.0.1')
1205 else:
1206 parts = host.split('%')
1207 if len(parts) == 2:
1208 ahost = parts[0]
1209 else:
1210 ahost = host
1211 addr = dns.ipv6.inet_aton(ahost)
1212 v6addrs.append(host)
1213 canonical_name = host
1214 except Exception:
1215 try:
1216
1217 addr = dns.ipv4.inet_aton(host)
1218 v4addrs.append(host)
1219 canonical_name = host
1220 except Exception:
1221 if flags & socket.AI_NUMERICHOST == 0:
1222 try:
1223 if family == socket.AF_INET6 or family == socket.AF_UNSPEC:
1224 v6 = _resolver.query(host, dns.rdatatype.AAAA,
1225 raise_on_no_answer=False)
1226
1227
1228 host = v6.qname
1229 canonical_name = v6.canonical_name.to_text(True)
1230 if v6.rrset is not None:
1231 for rdata in v6.rrset:
1232 v6addrs.append(rdata.address)
1233 if family == socket.AF_INET or family == socket.AF_UNSPEC:
1234 v4 = _resolver.query(host, dns.rdatatype.A,
1235 raise_on_no_answer=False)
1236 host = v4.qname
1237 canonical_name = v4.canonical_name.to_text(True)
1238 if v4.rrset is not None:
1239 for rdata in v4.rrset:
1240 v4addrs.append(rdata.address)
1241 except dns.resolver.NXDOMAIN:
1242 raise socket.gaierror(socket.EAI_NONAME)
1243 except:
1244 raise socket.gaierror(socket.EAI_SYSTEM)
1245 port = None
1246 try:
1247
1248 if service is None:
1249 port = 0
1250 else:
1251 port = int(service)
1252 except Exception:
1253 if flags & socket.AI_NUMERICSERV == 0:
1254 try:
1255 port = socket.getservbyname(service)
1256 except Exception:
1257 pass
1258 if port is None:
1259 raise socket.gaierror(socket.EAI_NONAME)
1260 tuples = []
1261 if socktype == 0:
1262 socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM]
1263 else:
1264 socktypes = [socktype]
1265 if flags & socket.AI_CANONNAME != 0:
1266 cname = canonical_name
1267 else:
1268 cname = ''
1269 if family == socket.AF_INET6 or family == socket.AF_UNSPEC:
1270 for addr in v6addrs:
1271 for socktype in socktypes:
1272 for proto in _protocols_for_socktype[socktype]:
1273 tuples.append((socket.AF_INET6, socktype, proto,
1274 cname, (addr, port, 0, 0)))
1275 if family == socket.AF_INET or family == socket.AF_UNSPEC:
1276 for addr in v4addrs:
1277 for socktype in socktypes:
1278 for proto in _protocols_for_socktype[socktype]:
1279 tuples.append((socket.AF_INET, socktype, proto,
1280 cname, (addr, port)))
1281 if len(tuples) == 0:
1282 raise socket.gaierror(socket.EAI_NONAME)
1283 return tuples
1284
1285
1324
1325
1327 if name is None:
1328 name = socket.gethostname()
1329 try:
1330 return _getnameinfo(_getaddrinfo(name, 80)[0][4])[0]
1331 except Exception:
1332 return name
1333
1334
1336 return _gethostbyname_ex(name)[2][0]
1337
1338
1340 aliases = []
1341 addresses = []
1342 tuples = _getaddrinfo(name, 0, socket.AF_INET, socket.SOCK_STREAM,
1343 socket.SOL_TCP, socket.AI_CANONNAME)
1344 canonical = tuples[0][3]
1345 for item in tuples:
1346 addresses.append(item[4][0])
1347
1348 return (canonical, aliases, addresses)
1349
1350
1352 try:
1353 dns.ipv6.inet_aton(ip)
1354 sockaddr = (ip, 80, 0, 0)
1355 family = socket.AF_INET6
1356 except Exception:
1357 sockaddr = (ip, 80)
1358 family = socket.AF_INET
1359 (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD)
1360 aliases = []
1361 addresses = []
1362 tuples = _getaddrinfo(name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP,
1363 socket.AI_CANONNAME)
1364 canonical = tuples[0][3]
1365 for item in tuples:
1366 addresses.append(item[4][0])
1367
1368 return (canonical, aliases, addresses)
1369
1370
1372 """Override the system resolver routines in the socket module with
1373 versions which use dnspython's resolver.
1374
1375 This can be useful in testing situations where you want to control
1376 the resolution behavior of python code without having to change
1377 the system's resolver settings (e.g. /etc/resolv.conf).
1378
1379 The resolver to use may be specified; if it's not, the default
1380 resolver will be used.
1381
1382 @param resolver: the resolver to use
1383 @type resolver: dns.resolver.Resolver object or None
1384 """
1385 if resolver is None:
1386 resolver = get_default_resolver()
1387 global _resolver
1388 _resolver = resolver
1389 socket.getaddrinfo = _getaddrinfo
1390 socket.getnameinfo = _getnameinfo
1391 socket.getfqdn = _getfqdn
1392 socket.gethostbyname = _gethostbyname
1393 socket.gethostbyname_ex = _gethostbyname_ex
1394 socket.gethostbyaddr = _gethostbyaddr
1395
1396
1398 """Undo the effects of override_system_resolver().
1399 """
1400 global _resolver
1401 _resolver = None
1402 socket.getaddrinfo = _original_getaddrinfo
1403 socket.getnameinfo = _original_getnameinfo
1404 socket.getfqdn = _original_getfqdn
1405 socket.gethostbyname = _original_gethostbyname
1406 socket.gethostbyname_ex = _original_gethostbyname_ex
1407 socket.gethostbyaddr = _original_gethostbyaddr
1408