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