Package dns :: Module resolver
[hide private]
[frames] | no frames]

Source Code for Module dns.resolver

   1  # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 
   2   
   3  # Copyright (C) 2003-2017 Nominum, Inc. 
   4  # 
   5  # Permission to use, copy, modify, and distribute this software and its 
   6  # documentation for any purpose with or without fee is hereby granted, 
   7  # provided that the above copyright notice and this permission notice 
   8  # appear in all copies. 
   9  # 
  10  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 
  11  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
  12  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 
  13  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
  14  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
  15  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
  16  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
  17   
  18  """DNS stub resolver.""" 
  19   
  20  import socket 
  21  import sys 
  22  import time 
  23  import random 
  24   
  25  try: 
  26      import threading as _threading 
  27  except ImportError: 
  28      import dummy_threading as _threading 
  29   
  30  import dns.exception 
  31  import dns.flags 
  32  import dns.ipv4 
  33  import dns.ipv6 
  34  import dns.message 
  35  import dns.name 
  36  import dns.query 
  37  import dns.rcode 
  38  import dns.rdataclass 
  39  import dns.rdatatype 
  40  import dns.reversename 
  41  import dns.tsig 
  42  from ._compat import xrange, string_types 
  43   
  44  if sys.platform == 'win32': 
  45      try: 
  46          import winreg as _winreg 
  47      except ImportError: 
  48          import _winreg  # pylint: disable=import-error 
  49   
50 -class NXDOMAIN(dns.exception.DNSException):
51 """The DNS query name does not exist.""" 52 supp_kwargs = {'qnames', 'responses'} 53 fmt = None # we have our own __str__ implementation 54
55 - def _check_kwargs(self, qnames, responses=None):
56 if not isinstance(qnames, (list, tuple, set)): 57 raise AttributeError("qnames must be a list, tuple or set") 58 if len(qnames) == 0: 59 raise AttributeError("qnames must contain at least one element") 60 if responses is None: 61 responses = {} 62 elif not isinstance(responses, dict): 63 raise AttributeError("responses must be a dict(qname=response)") 64 kwargs = dict(qnames=qnames, responses=responses) 65 return kwargs
66
67 - def __str__(self):
68 if 'qnames' not in self.kwargs: 69 return super(NXDOMAIN, self).__str__() 70 qnames = self.kwargs['qnames'] 71 if len(qnames) > 1: 72 msg = 'None of DNS query names exist' 73 else: 74 msg = 'The DNS query name does not exist' 75 qnames = ', '.join(map(str, qnames)) 76 return "{}: {}".format(msg, qnames)
77
78 - def canonical_name(self):
79 if not 'qnames' in self.kwargs: 80 raise TypeError("parametrized exception required") 81 IN = dns.rdataclass.IN 82 CNAME = dns.rdatatype.CNAME 83 cname = None 84 for qname in self.kwargs['qnames']: 85 response = self.kwargs['responses'][qname] 86 for answer in response.answer: 87 if answer.rdtype != CNAME or answer.rdclass != IN: 88 continue 89 cname = answer.items[0].target.to_text() 90 if cname is not None: 91 return dns.name.from_text(cname) 92 return self.kwargs['qnames'][0]
93 canonical_name = property(canonical_name, doc=( 94 "Return the unresolved canonical name.")) 95
96 - def __add__(self, e_nx):
97 """Augment by results from another NXDOMAIN exception.""" 98 qnames0 = list(self.kwargs.get('qnames', [])) 99 responses0 = dict(self.kwargs.get('responses', {})) 100 responses1 = e_nx.kwargs.get('responses', {}) 101 for qname1 in e_nx.kwargs.get('qnames', []): 102 if qname1 not in qnames0: 103 qnames0.append(qname1) 104 if qname1 in responses1: 105 responses0[qname1] = responses1[qname1] 106 return NXDOMAIN(qnames=qnames0, responses=responses0)
107
108 - def qnames(self):
109 """All of the names that were tried. 110 111 Returns a list of ``dns.name.Name``. 112 """ 113 return self.kwargs['qnames']
114
115 - def responses(self):
116 """A map from queried names to their NXDOMAIN responses. 117 118 Returns a dict mapping a ``dns.name.Name`` to a 119 ``dns.message.Message``. 120 """ 121 return self.kwargs['responses']
122
123 - def response(self, qname):
124 """The response for query *qname*. 125 126 Returns a ``dns.message.Message``. 127 """ 128 return self.kwargs['responses'][qname]
129 130
131 -class YXDOMAIN(dns.exception.DNSException):
132 """The DNS query name is too long after DNAME substitution."""
133 134 # The definition of the Timeout exception has moved from here to the 135 # dns.exception module. We keep dns.resolver.Timeout defined for 136 # backwards compatibility. 137 138 Timeout = dns.exception.Timeout 139 140
141 -class NoAnswer(dns.exception.DNSException):
142 """The DNS response does not contain an answer to the question.""" 143 fmt = 'The DNS response does not contain an answer ' + \ 144 'to the question: {query}' 145 supp_kwargs = {'response'} 146
147 - def _fmt_kwargs(self, **kwargs):
148 return super(NoAnswer, self)._fmt_kwargs( 149 query=kwargs['response'].question)
150 151
152 -class NoNameservers(dns.exception.DNSException):
153 """All nameservers failed to answer the query. 154 155 errors: list of servers and respective errors 156 The type of errors is 157 [(server IP address, any object convertible to string)]. 158 Non-empty errors list will add explanatory message () 159 """ 160 161 msg = "All nameservers failed to answer the query." 162 fmt = "%s {query}: {errors}" % msg[:-1] 163 supp_kwargs = {'request', 'errors'} 164
165 - def _fmt_kwargs(self, **kwargs):
166 srv_msgs = [] 167 for err in kwargs['errors']: 168 srv_msgs.append('Server {} {} port {} answered {}'.format(err[0], 169 'TCP' if err[1] else 'UDP', err[2], err[3])) 170 return super(NoNameservers, self)._fmt_kwargs( 171 query=kwargs['request'].question, errors='; '.join(srv_msgs))
172 173
174 -class NotAbsolute(dns.exception.DNSException):
175 """An absolute domain name is required but a relative name was provided."""
176 177
178 -class NoRootSOA(dns.exception.DNSException):
179 """There is no SOA RR at the DNS root name. This should never happen!"""
180 181
182 -class NoMetaqueries(dns.exception.DNSException):
183 """DNS metaqueries are not allowed."""
184 185
186 -class Answer(object):
187 """DNS stub resolver answer. 188 189 Instances of this class bundle up the result of a successful DNS 190 resolution. 191 192 For convenience, the answer object implements much of the sequence 193 protocol, forwarding to its ``rrset`` attribute. E.g. 194 ``for a in answer`` is equivalent to ``for a in answer.rrset``. 195 ``answer[i]`` is equivalent to ``answer.rrset[i]``, and 196 ``answer[i:j]`` is equivalent to ``answer.rrset[i:j]``. 197 198 Note that CNAMEs or DNAMEs in the response may mean that answer 199 RRset's name might not be the query name. 200 """ 201
202 - def __init__(self, qname, rdtype, rdclass, response, 203 raise_on_no_answer=True):
204 self.qname = qname 205 self.rdtype = rdtype 206 self.rdclass = rdclass 207 self.response = response 208 min_ttl = -1 209 rrset = None 210 for count in xrange(0, 15): 211 try: 212 rrset = response.find_rrset(response.answer, qname, 213 rdclass, rdtype) 214 if min_ttl == -1 or rrset.ttl < min_ttl: 215 min_ttl = rrset.ttl 216 break 217 except KeyError: 218 if rdtype != dns.rdatatype.CNAME: 219 try: 220 crrset = response.find_rrset(response.answer, 221 qname, 222 rdclass, 223 dns.rdatatype.CNAME) 224 if min_ttl == -1 or crrset.ttl < min_ttl: 225 min_ttl = crrset.ttl 226 for rd in crrset: 227 qname = rd.target 228 break 229 continue 230 except KeyError: 231 if raise_on_no_answer: 232 raise NoAnswer(response=response) 233 if raise_on_no_answer: 234 raise NoAnswer(response=response) 235 if rrset is None and raise_on_no_answer: 236 raise NoAnswer(response=response) 237 self.canonical_name = qname 238 self.rrset = rrset 239 if rrset is None: 240 while 1: 241 # Look for a SOA RR whose owner name is a superdomain 242 # of qname. 243 try: 244 srrset = response.find_rrset(response.authority, qname, 245 rdclass, dns.rdatatype.SOA) 246 if min_ttl == -1 or srrset.ttl < min_ttl: 247 min_ttl = srrset.ttl 248 if srrset[0].minimum < min_ttl: 249 min_ttl = srrset[0].minimum 250 break 251 except KeyError: 252 try: 253 qname = qname.parent() 254 except dns.name.NoParent: 255 break 256 self.expiration = time.time() + min_ttl
257
258 - def __getattr__(self, attr):
259 if attr == 'name': 260 return self.rrset.name 261 elif attr == 'ttl': 262 return self.rrset.ttl 263 elif attr == 'covers': 264 return self.rrset.covers 265 elif attr == 'rdclass': 266 return self.rrset.rdclass 267 elif attr == 'rdtype': 268 return self.rrset.rdtype 269 else: 270 raise AttributeError(attr)
271
272 - def __len__(self):
273 return self.rrset and len(self.rrset) or 0
274
275 - def __iter__(self):
276 return self.rrset and iter(self.rrset) or iter(tuple())
277
278 - def __getitem__(self, i):
279 if self.rrset is None: 280 raise IndexError 281 return self.rrset[i]
282
283 - def __delitem__(self, i):
284 if self.rrset is None: 285 raise IndexError 286 del self.rrset[i]
287 288
289 -class Cache(object):
290 """Simple thread-safe DNS answer cache.""" 291
292 - def __init__(self, cleaning_interval=300.0):
293 """*cleaning_interval*, a ``float`` is the number of seconds between 294 periodic cleanings. 295 """ 296 297 self.data = {} 298 self.cleaning_interval = cleaning_interval 299 self.next_cleaning = time.time() + self.cleaning_interval 300 self.lock = _threading.Lock()
301
302 - def _maybe_clean(self):
303 """Clean the cache if it's time to do so.""" 304 305 now = time.time() 306 if self.next_cleaning <= now: 307 keys_to_delete = [] 308 for (k, v) in self.data.items(): 309 if v.expiration <= now: 310 keys_to_delete.append(k) 311 for k in keys_to_delete: 312 del self.data[k] 313 now = time.time() 314 self.next_cleaning = now + self.cleaning_interval
315
316 - def get(self, key):
317 """Get the answer associated with *key*. 318 319 Returns None if no answer is cached for the key. 320 321 *key*, a ``(dns.name.Name, int, int)`` tuple whose values are the 322 query name, rdtype, and rdclass respectively. 323 324 Returns a ``dns.resolver.Answer`` or ``None``. 325 """ 326 327 try: 328 self.lock.acquire() 329 self._maybe_clean() 330 v = self.data.get(key) 331 if v is None or v.expiration <= time.time(): 332 return None 333 return v 334 finally: 335 self.lock.release()
336
337 - def put(self, key, value):
338 """Associate key and value in the cache. 339 340 *key*, a ``(dns.name.Name, int, int)`` tuple whose values are the 341 query name, rdtype, and rdclass respectively. 342 343 *value*, a ``dns.resolver.Answer``, the answer. 344 """ 345 346 try: 347 self.lock.acquire() 348 self._maybe_clean() 349 self.data[key] = value 350 finally: 351 self.lock.release()
352
353 - def flush(self, key=None):
354 """Flush the cache. 355 356 If *key* is not ``None``, only that item is flushed. Otherwise 357 the entire cache is flushed. 358 359 *key*, a ``(dns.name.Name, int, int)`` tuple whose values are the 360 query name, rdtype, and rdclass respectively. 361 """ 362 363 try: 364 self.lock.acquire() 365 if key is not None: 366 if key in self.data: 367 del self.data[key] 368 else: 369 self.data = {} 370 self.next_cleaning = time.time() + self.cleaning_interval 371 finally: 372 self.lock.release()
373 374
375 -class LRUCacheNode(object):
376 """LRUCache node.""" 377
378 - def __init__(self, key, value):
379 self.key = key 380 self.value = value 381 self.prev = self 382 self.next = self
383 389 395
399 400
401 -class LRUCache(object):
402 """Thread-safe, bounded, least-recently-used DNS answer cache. 403 404 This cache is better than the simple cache (above) if you're 405 running a web crawler or other process that does a lot of 406 resolutions. The LRUCache has a maximum number of nodes, and when 407 it is full, the least-recently used node is removed to make space 408 for a new one. 409 """ 410
411 - def __init__(self, max_size=100000):
412 """*max_size*, an ``int``, is the maximum number of nodes to cache; 413 it must be greater than 0. 414 """ 415 416 self.data = {} 417 self.set_max_size(max_size) 418 self.sentinel = LRUCacheNode(None, None) 419 self.lock = _threading.Lock()
420
421 - def set_max_size(self, max_size):
422 if max_size < 1: 423 max_size = 1 424 self.max_size = max_size
425
426 - def get(self, key):
427 """Get the answer associated with *key*. 428 429 Returns None if no answer is cached for the key. 430 431 *key*, a ``(dns.name.Name, int, int)`` tuple whose values are the 432 query name, rdtype, and rdclass respectively. 433 434 Returns a ``dns.resolver.Answer`` or ``None``. 435 """ 436 437 try: 438 self.lock.acquire() 439 node = self.data.get(key) 440 if node is None: 441 return None 442 # Unlink because we're either going to move the node to the front 443 # of the LRU list or we're going to free it. 444 node.unlink() 445 if node.value.expiration <= time.time(): 446 del self.data[node.key] 447 return None 448 node.link_after(self.sentinel) 449 return node.value 450 finally: 451 self.lock.release()
452
453 - def put(self, key, value):
454 """Associate key and value in the cache. 455 456 *key*, a ``(dns.name.Name, int, int)`` tuple whose values are the 457 query name, rdtype, and rdclass respectively. 458 459 *value*, a ``dns.resolver.Answer``, the answer. 460 """ 461 462 try: 463 self.lock.acquire() 464 node = self.data.get(key) 465 if node is not None: 466 node.unlink() 467 del self.data[node.key] 468 while len(self.data) >= self.max_size: 469 node = self.sentinel.prev 470 node.unlink() 471 del self.data[node.key] 472 node = LRUCacheNode(key, value) 473 node.link_after(self.sentinel) 474 self.data[key] = node 475 finally: 476 self.lock.release()
477
478 - def flush(self, key=None):
479 """Flush the cache. 480 481 If *key* is not ``None``, only that item is flushed. Otherwise 482 the entire cache is flushed. 483 484 *key*, a ``(dns.name.Name, int, int)`` tuple whose values are the 485 query name, rdtype, and rdclass respectively. 486 """ 487 488 try: 489 self.lock.acquire() 490 if key is not None: 491 node = self.data.get(key) 492 if node is not None: 493 node.unlink() 494 del self.data[node.key] 495 else: 496 node = self.sentinel.next 497 while node != self.sentinel: 498 next = node.next 499 node.prev = None 500 node.next = None 501 node = next 502 self.data = {} 503 finally: 504 self.lock.release()
505 506
507 -class Resolver(object):
508 """DNS stub resolver.""" 509
510 - def __init__(self, filename='/etc/resolv.conf', configure=True):
511 """*filename*, a ``text`` or file object, specifying a file 512 in standard /etc/resolv.conf format. This parameter is meaningful 513 only when *configure* is true and the platform is POSIX. 514 515 *configure*, a ``bool``. If True (the default), the resolver 516 instance is configured in the normal fashion for the operating 517 system the resolver is running on. (I.e. by reading a 518 /etc/resolv.conf file on POSIX systems and from the registry 519 on Windows systems.) 520 """ 521 522 self.domain = None 523 self.nameservers = None 524 self.nameserver_ports = None 525 self.port = None 526 self.search = None 527 self.timeout = None 528 self.lifetime = None 529 self.keyring = None 530 self.keyname = None 531 self.keyalgorithm = None 532 self.edns = None 533 self.ednsflags = None 534 self.payload = None 535 self.cache = None 536 self.flags = None 537 self.retry_servfail = False 538 self.rotate = False 539 540 self.reset() 541 if configure: 542 if sys.platform == 'win32': 543 self.read_registry() 544 elif filename: 545 self.read_resolv_conf(filename)
546
547 - def reset(self):
548 """Reset all resolver configuration to the defaults.""" 549 550 self.domain = \ 551 dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) 552 if len(self.domain) == 0: 553 self.domain = dns.name.root 554 self.nameservers = [] 555 self.nameserver_ports = {} 556 self.port = 53 557 self.search = [] 558 self.timeout = 2.0 559 self.lifetime = 30.0 560 self.keyring = None 561 self.keyname = None 562 self.keyalgorithm = dns.tsig.default_algorithm 563 self.edns = -1 564 self.ednsflags = 0 565 self.payload = 0 566 self.cache = None 567 self.flags = None 568 self.retry_servfail = False 569 self.rotate = False
570
571 - def read_resolv_conf(self, f):
572 """Process *f* as a file in the /etc/resolv.conf format. If f is 573 a ``text``, it is used as the name of the file to open; otherwise it 574 is treated as the file itself.""" 575 576 if isinstance(f, string_types): 577 try: 578 f = open(f, 'r') 579 except IOError: 580 # /etc/resolv.conf doesn't exist, can't be read, etc. 581 # We'll just use the default resolver configuration. 582 self.nameservers = ['127.0.0.1'] 583 return 584 want_close = True 585 else: 586 want_close = False 587 try: 588 for l in f: 589 if len(l) == 0 or l[0] == '#' or l[0] == ';': 590 continue 591 tokens = l.split() 592 593 # Any line containing less than 2 tokens is malformed 594 if len(tokens) < 2: 595 continue 596 597 if tokens[0] == 'nameserver': 598 self.nameservers.append(tokens[1]) 599 elif tokens[0] == 'domain': 600 self.domain = dns.name.from_text(tokens[1]) 601 elif tokens[0] == 'search': 602 for suffix in tokens[1:]: 603 self.search.append(dns.name.from_text(suffix)) 604 elif tokens[0] == 'options': 605 if 'rotate' in tokens[1:]: 606 self.rotate = True 607 finally: 608 if want_close: 609 f.close() 610 if len(self.nameservers) == 0: 611 self.nameservers.append('127.0.0.1')
612
613 - def _determine_split_char(self, entry):
614 # 615 # The windows registry irritatingly changes the list element 616 # delimiter in between ' ' and ',' (and vice-versa) in various 617 # versions of windows. 618 # 619 if entry.find(' ') >= 0: 620 split_char = ' ' 621 elif entry.find(',') >= 0: 622 split_char = ',' 623 else: 624 # probably a singleton; treat as a space-separated list. 625 split_char = ' ' 626 return split_char
627
628 - def _config_win32_nameservers(self, nameservers):
629 # we call str() on nameservers to convert it from unicode to ascii 630 nameservers = str(nameservers) 631 split_char = self._determine_split_char(nameservers) 632 ns_list = nameservers.split(split_char) 633 for ns in ns_list: 634 if ns not in self.nameservers: 635 self.nameservers.append(ns)
636
637 - def _config_win32_domain(self, domain):
638 # we call str() on domain to convert it from unicode to ascii 639 self.domain = dns.name.from_text(str(domain))
640
641 - def _config_win32_search(self, search):
642 # we call str() on search to convert it from unicode to ascii 643 search = str(search) 644 split_char = self._determine_split_char(search) 645 search_list = search.split(split_char) 646 for s in search_list: 647 if s not in self.search: 648 self.search.append(dns.name.from_text(s))
649
650 - def _config_win32_fromkey(self, key, always_try_domain):
651 try: 652 servers, rtype = _winreg.QueryValueEx(key, 'NameServer') 653 except WindowsError: # pylint: disable=undefined-variable 654 servers = None 655 if servers: 656 self._config_win32_nameservers(servers) 657 if servers or always_try_domain: 658 try: 659 dom, rtype = _winreg.QueryValueEx(key, 'Domain') 660 if dom: 661 self._config_win32_domain(dom) 662 except WindowsError: # pylint: disable=undefined-variable 663 pass 664 else: 665 try: 666 servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') 667 except WindowsError: # pylint: disable=undefined-variable 668 servers = None 669 if servers: 670 self._config_win32_nameservers(servers) 671 try: 672 dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain') 673 if dom: 674 self._config_win32_domain(dom) 675 except WindowsError: # pylint: disable=undefined-variable 676 pass 677 try: 678 search, rtype = _winreg.QueryValueEx(key, 'SearchList') 679 except WindowsError: # pylint: disable=undefined-variable 680 search = None 681 if search: 682 self._config_win32_search(search)
683
684 - def read_registry(self):
685 """Extract resolver configuration from the Windows registry.""" 686 687 lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) 688 want_scan = False 689 try: 690 try: 691 # XP, 2000 692 tcp_params = _winreg.OpenKey(lm, 693 r'SYSTEM\CurrentControlSet' 694 r'\Services\Tcpip\Parameters') 695 want_scan = True 696 except EnvironmentError: 697 # ME 698 tcp_params = _winreg.OpenKey(lm, 699 r'SYSTEM\CurrentControlSet' 700 r'\Services\VxD\MSTCP') 701 try: 702 self._config_win32_fromkey(tcp_params, True) 703 finally: 704 tcp_params.Close() 705 if want_scan: 706 interfaces = _winreg.OpenKey(lm, 707 r'SYSTEM\CurrentControlSet' 708 r'\Services\Tcpip\Parameters' 709 r'\Interfaces') 710 try: 711 i = 0 712 while True: 713 try: 714 guid = _winreg.EnumKey(interfaces, i) 715 i += 1 716 key = _winreg.OpenKey(interfaces, guid) 717 if not self._win32_is_nic_enabled(lm, guid, key): 718 continue 719 try: 720 self._config_win32_fromkey(key, False) 721 finally: 722 key.Close() 723 except EnvironmentError: 724 break 725 finally: 726 interfaces.Close() 727 finally: 728 lm.Close()
729
730 - def _win32_is_nic_enabled(self, lm, guid, interface_key):
731 # Look in the Windows Registry to determine whether the network 732 # interface corresponding to the given guid is enabled. 733 # 734 # (Code contributed by Paul Marks, thanks!) 735 # 736 try: 737 # This hard-coded location seems to be consistent, at least 738 # from Windows 2000 through Vista. 739 connection_key = _winreg.OpenKey( 740 lm, 741 r'SYSTEM\CurrentControlSet\Control\Network' 742 r'\{4D36E972-E325-11CE-BFC1-08002BE10318}' 743 r'\%s\Connection' % guid) 744 745 try: 746 # The PnpInstanceID points to a key inside Enum 747 (pnp_id, ttype) = _winreg.QueryValueEx( 748 connection_key, 'PnpInstanceID') 749 750 if ttype != _winreg.REG_SZ: 751 raise ValueError 752 753 device_key = _winreg.OpenKey( 754 lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id) 755 756 try: 757 # Get ConfigFlags for this device 758 (flags, ttype) = _winreg.QueryValueEx( 759 device_key, 'ConfigFlags') 760 761 if ttype != _winreg.REG_DWORD: 762 raise ValueError 763 764 # Based on experimentation, bit 0x1 indicates that the 765 # device is disabled. 766 return not flags & 0x1 767 768 finally: 769 device_key.Close() 770 finally: 771 connection_key.Close() 772 except (EnvironmentError, ValueError): 773 # Pre-vista, enabled interfaces seem to have a non-empty 774 # NTEContextList; this was how dnspython detected enabled 775 # nics before the code above was contributed. We've retained 776 # the old method since we don't know if the code above works 777 # on Windows 95/98/ME. 778 try: 779 (nte, ttype) = _winreg.QueryValueEx(interface_key, 780 'NTEContextList') 781 return nte is not None 782 except WindowsError: # pylint: disable=undefined-variable 783 return False
784
785 - def _compute_timeout(self, start, lifetime=None):
786 lifetime = self.lifetime if lifetime is None else lifetime 787 now = time.time() 788 duration = now - start 789 if duration < 0: 790 if duration < -1: 791 # Time going backwards is bad. Just give up. 792 raise Timeout(timeout=duration) 793 else: 794 # Time went backwards, but only a little. This can 795 # happen, e.g. under vmware with older linux kernels. 796 # Pretend it didn't happen. 797 now = start 798 if duration >= lifetime: 799 raise Timeout(timeout=duration) 800 return min(lifetime - duration, self.timeout)
801
802 - def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, 803 tcp=False, source=None, raise_on_no_answer=True, source_port=0, 804 lifetime=None):
805 """Query nameservers to find the answer to the question. 806 807 The *qname*, *rdtype*, and *rdclass* parameters may be objects 808 of the appropriate type, or strings that can be converted into objects 809 of the appropriate type. 810 811 *qname*, a ``dns.name.Name`` or ``text``, the query name. 812 813 *rdtype*, an ``int`` or ``text``, the query type. 814 815 *rdclass*, an ``int`` or ``text``, the query class. 816 817 *tcp*, a ``bool``. If ``True``, use TCP to make the query. 818 819 *source*, a ``text`` or ``None``. If not ``None``, bind to this IP 820 address when making queries. 821 822 *raise_on_no_answer*, a ``bool``. If ``True``, raise 823 ``dns.resolver.NoAnswer`` if there's no answer to the question. 824 825 *source_port*, an ``int``, the port from which to send the message. 826 827 *lifetime*, a ``float``, how long query should run before timing out. 828 829 Raises ``dns.exception.Timeout`` if no answers could be found 830 in the specified lifetime. 831 832 Raises ``dns.resolver.NXDOMAIN`` if the query name does not exist. 833 834 Raises ``dns.resolver.YXDOMAIN`` if the query name is too long after 835 DNAME substitution. 836 837 Raises ``dns.resolver.NoAnswer`` if *raise_on_no_answer* is 838 ``True`` and the query name exists but has no RRset of the 839 desired type and class. 840 841 Raises ``dns.resolver.NoNameservers`` if no non-broken 842 nameservers are available to answer the question. 843 844 Returns a ``dns.resolver.Answer`` instance. 845 """ 846 847 if isinstance(qname, string_types): 848 qname = dns.name.from_text(qname, None) 849 if isinstance(rdtype, string_types): 850 rdtype = dns.rdatatype.from_text(rdtype) 851 if dns.rdatatype.is_metatype(rdtype): 852 raise NoMetaqueries 853 if isinstance(rdclass, string_types): 854 rdclass = dns.rdataclass.from_text(rdclass) 855 if dns.rdataclass.is_metaclass(rdclass): 856 raise NoMetaqueries 857 qnames_to_try = [] 858 if qname.is_absolute(): 859 qnames_to_try.append(qname) 860 else: 861 if len(qname) > 1: 862 qnames_to_try.append(qname.concatenate(dns.name.root)) 863 if self.search: 864 for suffix in self.search: 865 qnames_to_try.append(qname.concatenate(suffix)) 866 else: 867 qnames_to_try.append(qname.concatenate(self.domain)) 868 all_nxdomain = True 869 nxdomain_responses = {} 870 start = time.time() 871 _qname = None # make pylint happy 872 for _qname in qnames_to_try: 873 if self.cache: 874 answer = self.cache.get((_qname, rdtype, rdclass)) 875 if answer is not None: 876 if answer.rrset is None and raise_on_no_answer: 877 raise NoAnswer(response=answer.response) 878 else: 879 return answer 880 request = dns.message.make_query(_qname, rdtype, rdclass) 881 if self.keyname is not None: 882 request.use_tsig(self.keyring, self.keyname, 883 algorithm=self.keyalgorithm) 884 request.use_edns(self.edns, self.ednsflags, self.payload) 885 if self.flags is not None: 886 request.flags = self.flags 887 response = None 888 # 889 # make a copy of the servers list so we can alter it later. 890 # 891 nameservers = self.nameservers[:] 892 errors = [] 893 if self.rotate: 894 random.shuffle(nameservers) 895 backoff = 0.10 896 while response is None: 897 if len(nameservers) == 0: 898 raise NoNameservers(request=request, errors=errors) 899 for nameserver in nameservers[:]: 900 timeout = self._compute_timeout(start, lifetime) 901 port = self.nameserver_ports.get(nameserver, self.port) 902 try: 903 tcp_attempt = tcp 904 if tcp: 905 response = dns.query.tcp(request, nameserver, 906 timeout, port, 907 source=source, 908 source_port=source_port) 909 else: 910 response = dns.query.udp(request, nameserver, 911 timeout, port, 912 source=source, 913 source_port=source_port) 914 if response.flags & dns.flags.TC: 915 # Response truncated; retry with TCP. 916 tcp_attempt = True 917 timeout = self._compute_timeout(start, lifetime) 918 response = \ 919 dns.query.tcp(request, nameserver, 920 timeout, port, 921 source=source, 922 source_port=source_port) 923 except (socket.error, dns.exception.Timeout) as ex: 924 # 925 # Communication failure or timeout. Go to the 926 # next server 927 # 928 errors.append((nameserver, tcp_attempt, port, ex, 929 response)) 930 response = None 931 continue 932 except dns.query.UnexpectedSource as ex: 933 # 934 # Who knows? Keep going. 935 # 936 errors.append((nameserver, tcp_attempt, port, ex, 937 response)) 938 response = None 939 continue 940 except dns.exception.FormError as ex: 941 # 942 # We don't understand what this server is 943 # saying. Take it out of the mix and 944 # continue. 945 # 946 nameservers.remove(nameserver) 947 errors.append((nameserver, tcp_attempt, port, ex, 948 response)) 949 response = None 950 continue 951 except EOFError as ex: 952 # 953 # We're using TCP and they hung up on us. 954 # Probably they don't support TCP (though 955 # they're supposed to!). Take it out of the 956 # mix and continue. 957 # 958 nameservers.remove(nameserver) 959 errors.append((nameserver, tcp_attempt, port, ex, 960 response)) 961 response = None 962 continue 963 rcode = response.rcode() 964 if rcode == dns.rcode.YXDOMAIN: 965 ex = YXDOMAIN() 966 errors.append((nameserver, tcp_attempt, port, ex, 967 response)) 968 raise ex 969 if rcode == dns.rcode.NOERROR or \ 970 rcode == dns.rcode.NXDOMAIN: 971 break 972 # 973 # We got a response, but we're not happy with the 974 # rcode in it. Remove the server from the mix if 975 # the rcode isn't SERVFAIL. 976 # 977 if rcode != dns.rcode.SERVFAIL or not self.retry_servfail: 978 nameservers.remove(nameserver) 979 errors.append((nameserver, tcp_attempt, port, 980 dns.rcode.to_text(rcode), response)) 981 response = None 982 if response is not None: 983 break 984 # 985 # All nameservers failed! 986 # 987 if len(nameservers) > 0: 988 # 989 # But we still have servers to try. Sleep a bit 990 # so we don't pound them! 991 # 992 timeout = self._compute_timeout(start, lifetime) 993 sleep_time = min(timeout, backoff) 994 backoff *= 2 995 time.sleep(sleep_time) 996 if response.rcode() == dns.rcode.NXDOMAIN: 997 nxdomain_responses[_qname] = response 998 continue 999 all_nxdomain = False 1000 break 1001 if all_nxdomain: 1002 raise NXDOMAIN(qnames=qnames_to_try, responses=nxdomain_responses) 1003 answer = Answer(_qname, rdtype, rdclass, response, 1004 raise_on_no_answer) 1005 if self.cache: 1006 self.cache.put((_qname, rdtype, rdclass), answer) 1007 return answer
1008
1009 - def use_tsig(self, keyring, keyname=None, 1010 algorithm=dns.tsig.default_algorithm):
1011 """Add a TSIG signature to the query. 1012 1013 See the documentation of the Message class for a complete 1014 description of the keyring dictionary. 1015 1016 *keyring*, a ``dict``, the TSIG keyring to use. If a 1017 *keyring* is specified but a *keyname* is not, then the key 1018 used will be the first key in the *keyring*. Note that the 1019 order of keys in a dictionary is not defined, so applications 1020 should supply a keyname when a keyring is used, unless they 1021 know the keyring contains only one key. 1022 1023 *keyname*, a ``dns.name.Name`` or ``None``, the name of the TSIG key 1024 to use; defaults to ``None``. The key must be defined in the keyring. 1025 1026 *algorithm*, a ``dns.name.Name``, the TSIG algorithm to use. 1027 """ 1028 1029 self.keyring = keyring 1030 if keyname is None: 1031 self.keyname = list(self.keyring.keys())[0] 1032 else: 1033 self.keyname = keyname 1034 self.keyalgorithm = algorithm
1035
1036 - def use_edns(self, edns, ednsflags, payload):
1037 """Configure EDNS behavior. 1038 1039 *edns*, an ``int``, is the EDNS level to use. Specifying 1040 ``None``, ``False``, or ``-1`` means "do not use EDNS", and in this case 1041 the other parameters are ignored. Specifying ``True`` is 1042 equivalent to specifying 0, i.e. "use EDNS0". 1043 1044 *ednsflags*, an ``int``, the EDNS flag values. 1045 1046 *payload*, an ``int``, is the EDNS sender's payload field, which is the 1047 maximum size of UDP datagram the sender can handle. I.e. how big 1048 a response to this message can be. 1049 """ 1050 1051 if edns is None: 1052 edns = -1 1053 self.edns = edns 1054 self.ednsflags = ednsflags 1055 self.payload = payload
1056
1057 - def set_flags(self, flags):
1058 """Overrides the default flags with your own. 1059 1060 *flags*, an ``int``, the message flags to use. 1061 """ 1062 1063 self.flags = flags
1064 1065 1066 #: The default resolver. 1067 default_resolver = None 1068 1069
1070 -def get_default_resolver():
1071 """Get the default resolver, initializing it if necessary.""" 1072 if default_resolver is None: 1073 reset_default_resolver() 1074 return default_resolver
1075 1076
1077 -def reset_default_resolver():
1078 """Re-initialize default resolver. 1079 1080 Note that the resolver configuration (i.e. /etc/resolv.conf on UNIX 1081 systems) will be re-read immediately. 1082 """ 1083 1084 global default_resolver 1085 default_resolver = Resolver()
1086 1087
1088 -def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, 1089 tcp=False, source=None, raise_on_no_answer=True, 1090 source_port=0, lifetime=None):
1091 """Query nameservers to find the answer to the question. 1092 1093 This is a convenience function that uses the default resolver 1094 object to make the query. 1095 1096 See ``dns.resolver.Resolver.query`` for more information on the 1097 parameters. 1098 """ 1099 1100 return get_default_resolver().query(qname, rdtype, rdclass, tcp, source, 1101 raise_on_no_answer, source_port, 1102 lifetime)
1103 1104
1105 -def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None):
1106 """Find the name of the zone which contains the specified name. 1107 1108 *name*, an absolute ``dns.name.Name`` or ``text``, the query name. 1109 1110 *rdclass*, an ``int``, the query class. 1111 1112 *tcp*, a ``bool``. If ``True``, use TCP to make the query. 1113 1114 *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use. 1115 If ``None``, the default resolver is used. 1116 1117 Raises ``dns.resolver.NoRootSOA`` if there is no SOA RR at the DNS 1118 root. (This is only likely to happen if you're using non-default 1119 root servers in your network and they are misconfigured.) 1120 1121 Returns a ``dns.name.Name``. 1122 """ 1123 1124 if isinstance(name, string_types): 1125 name = dns.name.from_text(name, dns.name.root) 1126 if resolver is None: 1127 resolver = get_default_resolver() 1128 if not name.is_absolute(): 1129 raise NotAbsolute(name) 1130 while 1: 1131 try: 1132 answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) 1133 if answer.rrset.name == name: 1134 return name 1135 # otherwise we were CNAMEd or DNAMEd and need to look higher 1136 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): 1137 pass 1138 try: 1139 name = name.parent() 1140 except dns.name.NoParent: 1141 raise NoRootSOA
1142 1143 # 1144 # Support for overriding the system resolver for all python code in the 1145 # running process. 1146 # 1147 1148 _protocols_for_socktype = { 1149 socket.SOCK_DGRAM: [socket.SOL_UDP], 1150 socket.SOCK_STREAM: [socket.SOL_TCP], 1151 } 1152 1153 _resolver = None 1154 _original_getaddrinfo = socket.getaddrinfo 1155 _original_getnameinfo = socket.getnameinfo 1156 _original_getfqdn = socket.getfqdn 1157 _original_gethostbyname = socket.gethostbyname 1158 _original_gethostbyname_ex = socket.gethostbyname_ex 1159 _original_gethostbyaddr = socket.gethostbyaddr 1160 1161
1162 -def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0, 1163 proto=0, flags=0):
1164 if flags & (socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) != 0: 1165 raise NotImplementedError 1166 if host is None and service is None: 1167 raise socket.gaierror(socket.EAI_NONAME) 1168 v6addrs = [] 1169 v4addrs = [] 1170 canonical_name = None 1171 try: 1172 # Is host None or a V6 address literal? 1173 if host is None: 1174 canonical_name = 'localhost' 1175 if flags & socket.AI_PASSIVE != 0: 1176 v6addrs.append('::') 1177 v4addrs.append('0.0.0.0') 1178 else: 1179 v6addrs.append('::1') 1180 v4addrs.append('127.0.0.1') 1181 else: 1182 parts = host.split('%') 1183 if len(parts) == 2: 1184 ahost = parts[0] 1185 else: 1186 ahost = host 1187 addr = dns.ipv6.inet_aton(ahost) 1188 v6addrs.append(host) 1189 canonical_name = host 1190 except Exception: 1191 try: 1192 # Is it a V4 address literal? 1193 addr = dns.ipv4.inet_aton(host) 1194 v4addrs.append(host) 1195 canonical_name = host 1196 except Exception: 1197 if flags & socket.AI_NUMERICHOST == 0: 1198 try: 1199 if family == socket.AF_INET6 or family == socket.AF_UNSPEC: 1200 v6 = _resolver.query(host, dns.rdatatype.AAAA, 1201 raise_on_no_answer=False) 1202 # Note that setting host ensures we query the same name 1203 # for A as we did for AAAA. 1204 host = v6.qname 1205 canonical_name = v6.canonical_name.to_text(True) 1206 if v6.rrset is not None: 1207 for rdata in v6.rrset: 1208 v6addrs.append(rdata.address) 1209 if family == socket.AF_INET or family == socket.AF_UNSPEC: 1210 v4 = _resolver.query(host, dns.rdatatype.A, 1211 raise_on_no_answer=False) 1212 host = v4.qname 1213 canonical_name = v4.canonical_name.to_text(True) 1214 if v4.rrset is not None: 1215 for rdata in v4.rrset: 1216 v4addrs.append(rdata.address) 1217 except dns.resolver.NXDOMAIN: 1218 raise socket.gaierror(socket.EAI_NONAME) 1219 except Exception: 1220 raise socket.gaierror(socket.EAI_SYSTEM) 1221 port = None 1222 try: 1223 # Is it a port literal? 1224 if service is None: 1225 port = 0 1226 else: 1227 port = int(service) 1228 except Exception: 1229 if flags & socket.AI_NUMERICSERV == 0: 1230 try: 1231 port = socket.getservbyname(service) 1232 except Exception: 1233 pass 1234 if port is None: 1235 raise socket.gaierror(socket.EAI_NONAME) 1236 tuples = [] 1237 if socktype == 0: 1238 socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM] 1239 else: 1240 socktypes = [socktype] 1241 if flags & socket.AI_CANONNAME != 0: 1242 cname = canonical_name 1243 else: 1244 cname = '' 1245 if family == socket.AF_INET6 or family == socket.AF_UNSPEC: 1246 for addr in v6addrs: 1247 for socktype in socktypes: 1248 for proto in _protocols_for_socktype[socktype]: 1249 tuples.append((socket.AF_INET6, socktype, proto, 1250 cname, (addr, port, 0, 0))) 1251 if family == socket.AF_INET or family == socket.AF_UNSPEC: 1252 for addr in v4addrs: 1253 for socktype in socktypes: 1254 for proto in _protocols_for_socktype[socktype]: 1255 tuples.append((socket.AF_INET, socktype, proto, 1256 cname, (addr, port))) 1257 if len(tuples) == 0: 1258 raise socket.gaierror(socket.EAI_NONAME) 1259 return tuples
1260 1261
1262 -def _getnameinfo(sockaddr, flags=0):
1263 host = sockaddr[0] 1264 port = sockaddr[1] 1265 if len(sockaddr) == 4: 1266 scope = sockaddr[3] 1267 family = socket.AF_INET6 1268 else: 1269 scope = None 1270 family = socket.AF_INET 1271 tuples = _getaddrinfo(host, port, family, socket.SOCK_STREAM, 1272 socket.SOL_TCP, 0) 1273 if len(tuples) > 1: 1274 raise socket.error('sockaddr resolved to multiple addresses') 1275 addr = tuples[0][4][0] 1276 if flags & socket.NI_DGRAM: 1277 pname = 'udp' 1278 else: 1279 pname = 'tcp' 1280 qname = dns.reversename.from_address(addr) 1281 if flags & socket.NI_NUMERICHOST == 0: 1282 try: 1283 answer = _resolver.query(qname, 'PTR') 1284 hostname = answer.rrset[0].target.to_text(True) 1285 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): 1286 if flags & socket.NI_NAMEREQD: 1287 raise socket.gaierror(socket.EAI_NONAME) 1288 hostname = addr 1289 if scope is not None: 1290 hostname += '%' + str(scope) 1291 else: 1292 hostname = addr 1293 if scope is not None: 1294 hostname += '%' + str(scope) 1295 if flags & socket.NI_NUMERICSERV: 1296 service = str(port) 1297 else: 1298 service = socket.getservbyport(port, pname) 1299 return (hostname, service)
1300 1301
1302 -def _getfqdn(name=None):
1303 if name is None: 1304 name = socket.gethostname() 1305 try: 1306 return _getnameinfo(_getaddrinfo(name, 80)[0][4])[0] 1307 except Exception: 1308 return name
1309 1310
1311 -def _gethostbyname(name):
1312 return _gethostbyname_ex(name)[2][0]
1313 1314
1315 -def _gethostbyname_ex(name):
1316 aliases = [] 1317 addresses = [] 1318 tuples = _getaddrinfo(name, 0, socket.AF_INET, socket.SOCK_STREAM, 1319 socket.SOL_TCP, socket.AI_CANONNAME) 1320 canonical = tuples[0][3] 1321 for item in tuples: 1322 addresses.append(item[4][0]) 1323 # XXX we just ignore aliases 1324 return (canonical, aliases, addresses)
1325 1326
1327 -def _gethostbyaddr(ip):
1328 try: 1329 dns.ipv6.inet_aton(ip) 1330 sockaddr = (ip, 80, 0, 0) 1331 family = socket.AF_INET6 1332 except Exception: 1333 sockaddr = (ip, 80) 1334 family = socket.AF_INET 1335 (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD) 1336 aliases = [] 1337 addresses = [] 1338 tuples = _getaddrinfo(name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP, 1339 socket.AI_CANONNAME) 1340 canonical = tuples[0][3] 1341 for item in tuples: 1342 addresses.append(item[4][0]) 1343 # XXX we just ignore aliases 1344 return (canonical, aliases, addresses)
1345 1346
1347 -def override_system_resolver(resolver=None):
1348 """Override the system resolver routines in the socket module with 1349 versions which use dnspython's resolver. 1350 1351 This can be useful in testing situations where you want to control 1352 the resolution behavior of python code without having to change 1353 the system's resolver settings (e.g. /etc/resolv.conf). 1354 1355 The resolver to use may be specified; if it's not, the default 1356 resolver will be used. 1357 1358 resolver, a ``dns.resolver.Resolver`` or ``None``, the resolver to use. 1359 """ 1360 1361 if resolver is None: 1362 resolver = get_default_resolver() 1363 global _resolver 1364 _resolver = resolver 1365 socket.getaddrinfo = _getaddrinfo 1366 socket.getnameinfo = _getnameinfo 1367 socket.getfqdn = _getfqdn 1368 socket.gethostbyname = _gethostbyname 1369 socket.gethostbyname_ex = _gethostbyname_ex 1370 socket.gethostbyaddr = _gethostbyaddr
1371 1372
1373 -def restore_system_resolver():
1374 """Undo the effects of prior override_system_resolver().""" 1375 1376 global _resolver 1377 _resolver = None 1378 socket.getaddrinfo = _original_getaddrinfo 1379 socket.getnameinfo = _original_getnameinfo 1380 socket.getfqdn = _original_getfqdn 1381 socket.gethostbyname = _original_gethostbyname 1382 socket.gethostbyname_ex = _original_gethostbyname_ex 1383 socket.gethostbyaddr = _original_gethostbyaddr
1384