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

Source Code for Module dns.resolver

   1  # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. 
   2  # 
   3  # Permission to use, copy, modify, and distribute this software and its 
   4  # documentation for any purpose with or without fee is hereby granted, 
   5  # provided that the above copyright notice and this permission notice 
   6  # appear in all copies. 
   7  # 
   8  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 
   9  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
  10  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 
  11  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
  12  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
  13  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 
  14  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
  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  # pylint: disable=import-error 
  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 # we have our own __str__ implementation 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
69 - def __str__(self):
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 # The definition of the Timeout exception has moved from here to the 116 # dns.exception module. We keep dns.resolver.Timeout defined for 117 # backwards compatibility. 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
129 - def _fmt_kwargs(self, **kwargs):
130 return super(NoAnswer, self)._fmt_kwargs( 131 query=kwargs['response'].question)
132 133
134 -class NoNameservers(dns.exception.DNSException):
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
148 - def _fmt_kwargs(self, **kwargs):
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
157 -class NotAbsolute(dns.exception.DNSException):
158 159 """An absolute domain name is required but a relative name was provided."""
160 161
162 -class NoRootSOA(dns.exception.DNSException):
163 164 """There is no SOA RR at the DNS root name. This should never happen!"""
165 166
167 -class NoMetaqueries(dns.exception.DNSException):
168 169 """DNS metaqueries are not allowed."""
170 171
172 -class Answer(object):
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 # Look for a SOA RR whose owner name is a superdomain 244 # of qname. 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
260 - def __getattr__(self, attr):
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
274 - def __len__(self):
275 return self.rrset and len(self.rrset) or 0
276
277 - def __iter__(self):
278 return self.rrset and iter(self.rrset) or iter(tuple())
279
280 - def __getitem__(self, i):
281 return self.rrset[i]
282
283 - def __delitem__(self, i):
284 del self.rrset[i]
285 286
287 -class Cache(object):
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
314 - def _maybe_clean(self):
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
385 -class LRUCacheNode(object):
386 387 """LRUCache node. 388 """ 389
390 - def __init__(self, key, value):
391 self.key = key 392 self.value = value 393 self.prev = self 394 self.next = self
395 401 407
411 412
413 -class LRUCache(object):
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
431 - def __init__(self, max_size=100000):
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
443 - def set_max_size(self, max_size):
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 # Unlink because we're either going to move the node to the front 462 # of the LRU list or we're going to free it. 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
524 -class Resolver(object):
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
607 - def reset(self):
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
630 - def read_resolv_conf(self, f):
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 # /etc/resolv.conf doesn't exist, can't be read, etc. 639 # We'll just use the default resolver configuration. 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 # Any line containing less than 2 tokens is malformed 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
671 - def _determine_split_char(self, entry):
672 # 673 # The windows registry irritatingly changes the list element 674 # delimiter in between ' ' and ',' (and vice-versa) in various 675 # versions of windows. 676 # 677 if entry.find(' ') >= 0: 678 split_char = ' ' 679 elif entry.find(',') >= 0: 680 split_char = ',' 681 else: 682 # probably a singleton; treat as a space-separated list. 683 split_char = ' ' 684 return split_char
685
686 - def _config_win32_nameservers(self, nameservers):
687 """Configure a NameServer registry entry.""" 688 # we call str() on nameservers to convert it from unicode to ascii 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 # we call str() on domain to convert it from unicode to ascii 699 self.domain = dns.name.from_text(str(domain))
700
701 - def _config_win32_search(self, search):
702 """Configure a Search registry entry.""" 703 # we call str() on search to convert it from unicode to ascii 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
711 - def _config_win32_fromkey(self, key):
712 """Extract DNS info from a registry key.""" 713 try: 714 servers, rtype = _winreg.QueryValueEx(key, 'NameServer') 715 except WindowsError: # pylint: disable=undefined-variable 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: # pylint: disable=undefined-variable 724 pass 725 else: 726 try: 727 servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') 728 except WindowsError: # pylint: disable=undefined-variable 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: # pylint: disable=undefined-variable 737 pass 738 try: 739 search, rtype = _winreg.QueryValueEx(key, 'SearchList') 740 except WindowsError: # pylint: disable=undefined-variable 741 search = None 742 if search: 743 self._config_win32_search(search)
744
745 - def read_registry(self):
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 # XP, 2000 752 tcp_params = _winreg.OpenKey(lm, 753 r'SYSTEM\CurrentControlSet' 754 r'\Services\Tcpip\Parameters') 755 want_scan = True 756 except EnvironmentError: 757 # ME 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
790 - def _win32_is_nic_enabled(self, lm, guid, interface_key):
791 # Look in the Windows Registry to determine whether the network 792 # interface corresponding to the given guid is enabled. 793 # 794 # (Code contributed by Paul Marks, thanks!) 795 # 796 try: 797 # This hard-coded location seems to be consistent, at least 798 # from Windows 2000 through Vista. 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 # The PnpInstanceID points to a key inside Enum 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 # Get ConfigFlags for this device 818 (flags, ttype) = _winreg.QueryValueEx( 819 device_key, 'ConfigFlags') 820 821 if ttype != _winreg.REG_DWORD: 822 raise ValueError 823 824 # Based on experimentation, bit 0x1 indicates that the 825 # device is disabled. 826 return not flags & 0x1 827 828 finally: 829 device_key.Close() 830 finally: 831 connection_key.Close() 832 except (EnvironmentError, ValueError): 833 # Pre-vista, enabled interfaces seem to have a non-empty 834 # NTEContextList; this was how dnspython detected enabled 835 # nics before the code above was contributed. We've retained 836 # the old method since we don't know if the code above works 837 # on Windows 95/98/ME. 838 try: 839 (nte, ttype) = _winreg.QueryValueEx(interface_key, 840 'NTEContextList') 841 return nte is not None 842 except WindowsError: # pylint: disable=undefined-variable 843 return False
844
845 - def _compute_timeout(self, start):
846 now = time.time() 847 duration = now - start 848 if duration < 0: 849 if duration < -1: 850 # Time going backwards is bad. Just give up. 851 raise Timeout(timeout=duration) 852 else: 853 # Time went backwards, but only a little. This can 854 # happen, e.g. under vmware with older linux kernels. 855 # Pretend it didn't happen. 856 now = start 857 if duration >= self.lifetime: 858 raise Timeout(timeout=duration) 859 return min(self.lifetime - duration, self.timeout)
860
861 - def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, 862 tcp=False, source=None, raise_on_no_answer=True, source_port=0):
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 # make pylint happy 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 # make a copy of the servers list so we can alter it later. 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 # Response truncated; retry with TCP. 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 # Communication failure or timeout. Go to the 975 # next server 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 # Who knows? Keep going. 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 # We don't understand what this server is 992 # saying. Take it out of the mix and 993 # continue. 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 # We're using TCP and they hung up on us. 1003 # Probably they don't support TCP (though 1004 # they're supposed to!). Take it out of the 1005 # mix and continue. 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 # We got a response, but we're not happy with the 1023 # rcode in it. Remove the server from the mix if 1024 # the rcode isn't SERVFAIL. 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 # All nameservers failed! 1035 # 1036 if len(nameservers) > 0: 1037 # 1038 # But we still have servers to try. Sleep a bit 1039 # so we don't pound them! 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
1058 - def use_tsig(self, keyring, keyname=None, 1059 algorithm=dns.tsig.default_algorithm):
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
1096 - def set_flags(self, flags):
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
1106 -def get_default_resolver():
1107 """Get the default resolver, initializing it if necessary.""" 1108 if default_resolver is None: 1109 reset_default_resolver() 1110 return default_resolver
1111 1112
1113 -def reset_default_resolver():
1114 """Re-initialize default resolver. 1115 1116 resolv.conf will be re-read immediatelly. 1117 """ 1118 global default_resolver 1119 default_resolver = Resolver()
1120 1121
1122 -def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, 1123 tcp=False, source=None, raise_on_no_answer=True, 1124 source_port=0):
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
1135 -def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None):
1136 """Find the name of the zone which contains the specified name. 1137 1138 @param name: the query name 1139 @type name: absolute dns.name.Name object or string 1140 @param rdclass: The query class 1141 @type rdclass: int 1142 @param tcp: use TCP to make the query (default is False). 1143 @type tcp: bool 1144 @param resolver: the resolver to use 1145 @type resolver: dns.resolver.Resolver object or None 1146 @rtype: dns.name.Name""" 1147 1148 if isinstance(name, string_types): 1149 name = dns.name.from_text(name, dns.name.root) 1150 if resolver is None: 1151 resolver = get_default_resolver() 1152 if not name.is_absolute(): 1153 raise NotAbsolute(name) 1154 while 1: 1155 try: 1156 answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) 1157 if answer.rrset.name == name: 1158 return name 1159 # otherwise we were CNAMEd or DNAMEd and need to look higher 1160 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): 1161 pass 1162 try: 1163 name = name.parent() 1164 except dns.name.NoParent: 1165 raise NoRootSOA
1166 1167 # 1168 # Support for overriding the system resolver for all python code in the 1169 # running process. 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 # Is host None or a V6 address literal? 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 # Is it a V4 address literal? 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 # Note that setting host ensures we query the same name 1227 # for A as we did for AAAA. 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 # Is it a port literal? 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
1286 -def _getnameinfo(sockaddr, flags=0):
1287 host = sockaddr[0] 1288 port = sockaddr[1] 1289 if len(sockaddr) == 4: 1290 scope = sockaddr[3] 1291 family = socket.AF_INET6 1292 else: 1293 scope = None 1294 family = socket.AF_INET 1295 tuples = _getaddrinfo(host, port, family, socket.SOCK_STREAM, 1296 socket.SOL_TCP, 0) 1297 if len(tuples) > 1: 1298 raise socket.error('sockaddr resolved to multiple addresses') 1299 addr = tuples[0][4][0] 1300 if flags & socket.NI_DGRAM: 1301 pname = 'udp' 1302 else: 1303 pname = 'tcp' 1304 qname = dns.reversename.from_address(addr) 1305 if flags & socket.NI_NUMERICHOST == 0: 1306 try: 1307 answer = _resolver.query(qname, 'PTR') 1308 hostname = answer.rrset[0].target.to_text(True) 1309 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): 1310 if flags & socket.NI_NAMEREQD: 1311 raise socket.gaierror(socket.EAI_NONAME) 1312 hostname = addr 1313 if scope is not None: 1314 hostname += '%' + str(scope) 1315 else: 1316 hostname = addr 1317 if scope is not None: 1318 hostname += '%' + str(scope) 1319 if flags & socket.NI_NUMERICSERV: 1320 service = str(port) 1321 else: 1322 service = socket.getservbyport(port, pname) 1323 return (hostname, service)
1324 1325
1326 -def _getfqdn(name=None):
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
1335 -def _gethostbyname(name):
1336 return _gethostbyname_ex(name)[2][0]
1337 1338
1339 -def _gethostbyname_ex(name):
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 # XXX we just ignore aliases 1348 return (canonical, aliases, addresses)
1349 1350
1351 -def _gethostbyaddr(ip):
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 # XXX we just ignore aliases 1368 return (canonical, aliases, addresses)
1369 1370
1371 -def override_system_resolver(resolver=None):
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
1397 -def restore_system_resolver():
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