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   
  25  import dns.exception 
  26  import dns.flags 
  27  import dns.ipv4 
  28  import dns.ipv6 
  29  import dns.message 
  30  import dns.name 
  31  import dns.query 
  32  import dns.rcode 
  33  import dns.rdataclass 
  34  import dns.rdatatype 
  35  import dns.reversename 
  36   
  37  if sys.platform == 'win32': 
  38      import _winreg 
  39   
40 -class NXDOMAIN(dns.exception.DNSException):
41 """The query name does not exist.""" 42 pass
43 44 # The definition of the Timeout exception has moved from here to the 45 # dns.exception module. We keep dns.resolver.Timeout defined for 46 # backwards compatibility. 47 48 Timeout = dns.exception.Timeout 49
50 -class NoAnswer(dns.exception.DNSException):
51 """The response did not contain an answer to the question.""" 52 pass
53
54 -class NoNameservers(dns.exception.DNSException):
55 """No non-broken nameservers are available to answer the query.""" 56 pass
57
58 -class NotAbsolute(dns.exception.DNSException):
59 """Raised if an absolute domain name is required but a relative name 60 was provided.""" 61 pass
62
63 -class NoRootSOA(dns.exception.DNSException):
64 """Raised if for some reason there is no SOA at the root name. 65 This should never happen!""" 66 pass
67
68 -class NoMetaqueries(dns.exception.DNSException):
69 """Metaqueries are not allowed.""" 70 pass
71
72 -class Answer(object):
73 """DNS stub resolver answer 74 75 Instances of this class bundle up the result of a successful DNS 76 resolution. 77 78 For convenience, the answer object implements much of the sequence 79 protocol, forwarding to its rrset. E.g. "for a in answer" is 80 equivalent to "for a in answer.rrset", "answer[i]" is equivalent 81 to "answer.rrset[i]", and "answer[i:j]" is equivalent to 82 "answer.rrset[i:j]". 83 84 Note that CNAMEs or DNAMEs in the response may mean that answer 85 node's name might not be the query name. 86 87 @ivar qname: The query name 88 @type qname: dns.name.Name object 89 @ivar rdtype: The query type 90 @type rdtype: int 91 @ivar rdclass: The query class 92 @type rdclass: int 93 @ivar response: The response message 94 @type response: dns.message.Message object 95 @ivar rrset: The answer 96 @type rrset: dns.rrset.RRset object 97 @ivar expiration: The time when the answer expires 98 @type expiration: float (seconds since the epoch) 99 @ivar canonical_name: The canonical name of the query name 100 @type canonical_name: dns.name.Name object 101 """
102 - def __init__(self, qname, rdtype, rdclass, response, 103 raise_on_no_answer=True):
104 self.qname = qname 105 self.rdtype = rdtype 106 self.rdclass = rdclass 107 self.response = response 108 min_ttl = -1 109 rrset = None 110 for count in range(0, 15): 111 try: 112 rrset = response.find_rrset(response.answer, qname, 113 rdclass, rdtype) 114 if min_ttl == -1 or rrset.ttl < min_ttl: 115 min_ttl = rrset.ttl 116 break 117 except KeyError: 118 if rdtype != dns.rdatatype.CNAME: 119 try: 120 crrset = response.find_rrset(response.answer, 121 qname, 122 rdclass, 123 dns.rdatatype.CNAME) 124 if min_ttl == -1 or crrset.ttl < min_ttl: 125 min_ttl = crrset.ttl 126 for rd in crrset: 127 qname = rd.target 128 break 129 continue 130 except KeyError: 131 if raise_on_no_answer: 132 raise NoAnswer 133 if raise_on_no_answer: 134 raise NoAnswer 135 if rrset is None and raise_on_no_answer: 136 raise NoAnswer 137 self.canonical_name = qname 138 self.rrset = rrset 139 if rrset is None: 140 while 1: 141 # Look for a SOA RR whose owner name is a superdomain 142 # of qname. 143 try: 144 srrset = response.find_rrset(response.authority, qname, 145 rdclass, dns.rdatatype.SOA) 146 if min_ttl == -1 or srrset.ttl < min_ttl: 147 min_ttl = srrset.ttl 148 if srrset[0].minimum < min_ttl: 149 min_ttl = srrset[0].minimum 150 break 151 except KeyError: 152 try: 153 qname = qname.parent() 154 except dns.name.NoParent: 155 break 156 self.expiration = time.time() + min_ttl
157
158 - def __getattr__(self, attr):
159 if attr == 'name': 160 return self.rrset.name 161 elif attr == 'ttl': 162 return self.rrset.ttl 163 elif attr == 'covers': 164 return self.rrset.covers 165 elif attr == 'rdclass': 166 return self.rrset.rdclass 167 elif attr == 'rdtype': 168 return self.rrset.rdtype 169 else: 170 raise AttributeError(attr)
171
172 - def __len__(self):
173 return len(self.rrset)
174
175 - def __iter__(self):
176 return iter(self.rrset)
177
178 - def __getitem__(self, i):
179 return self.rrset[i]
180
181 - def __delitem__(self, i):
182 del self.rrset[i]
183
184 - def __getslice__(self, i, j):
185 return self.rrset[i:j]
186
187 - def __delslice__(self, i, j):
188 del self.rrset[i:j]
189
190 -class Cache(object):
191 """Simple DNS answer cache. 192 193 @ivar data: A dictionary of cached data 194 @type data: dict 195 @ivar cleaning_interval: The number of seconds between cleanings. The 196 default is 300 (5 minutes). 197 @type cleaning_interval: float 198 @ivar next_cleaning: The time the cache should next be cleaned (in seconds 199 since the epoch.) 200 @type next_cleaning: float 201 """ 202
203 - def __init__(self, cleaning_interval=300.0):
204 """Initialize a DNS cache. 205 206 @param cleaning_interval: the number of seconds between periodic 207 cleanings. The default is 300.0 208 @type cleaning_interval: float. 209 """ 210 211 self.data = {} 212 self.cleaning_interval = cleaning_interval 213 self.next_cleaning = time.time() + self.cleaning_interval
214
215 - def maybe_clean(self):
216 """Clean the cache if it's time to do so.""" 217 218 now = time.time() 219 if self.next_cleaning <= now: 220 keys_to_delete = [] 221 for (k, v) in self.data.items(): 222 if v.expiration <= now: 223 keys_to_delete.append(k) 224 for k in keys_to_delete: 225 del self.data[k] 226 now = time.time() 227 self.next_cleaning = now + self.cleaning_interval
228
229 - def get(self, key):
230 """Get the answer associated with I{key}. Returns None if 231 no answer is cached for the key. 232 @param key: the key 233 @type key: (dns.name.Name, int, int) tuple whose values are the 234 query name, rdtype, and rdclass. 235 @rtype: dns.resolver.Answer object or None 236 """ 237 238 self.maybe_clean() 239 v = self.data.get(key) 240 if v is None or v.expiration <= time.time(): 241 return None 242 return v
243
244 - def put(self, key, value):
245 """Associate key and value in the cache. 246 @param key: the key 247 @type key: (dns.name.Name, int, int) tuple whose values are the 248 query name, rdtype, and rdclass. 249 @param value: The answer being cached 250 @type value: dns.resolver.Answer object 251 """ 252 253 self.maybe_clean() 254 self.data[key] = value
255
256 - def flush(self, key=None):
257 """Flush the cache. 258 259 If I{key} is specified, only that item is flushed. Otherwise 260 the entire cache is flushed. 261 262 @param key: the key to flush 263 @type key: (dns.name.Name, int, int) tuple or None 264 """ 265 266 if not key is None: 267 if key in self.data: 268 del self.data[key] 269 else: 270 self.data = {} 271 self.next_cleaning = time.time() + self.cleaning_interval
272
273 -class LRUCacheNode(object):
274 """LRUCache node. 275 """
276 - def __init__(self, key, value):
277 self.key = key 278 self.value = value 279 self.prev = self 280 self.next = self
281 287 293
297
298 -class LRUCache(object):
299 """Bounded least-recently-used DNS answer cache. 300 301 This cache is better than the simple cache (above) if you're 302 running a web crawler or other process that does a lot of 303 resolutions. The LRUCache has a maximum number of nodes, and when 304 it is full, the least-recently used node is removed to make space 305 for a new one. 306 307 @ivar data: A dictionary of cached data 308 @type data: dict 309 @ivar sentinel: sentinel node for circular doubly linked list of nodes 310 @type sentinel: LRUCacheNode object 311 @ivar max_size: The maximum number of nodes 312 @type max_size: int 313 """ 314
315 - def __init__(self, max_size=100000):
316 """Initialize a DNS cache. 317 318 @param max_size: The maximum number of nodes to cache; the default is 100000. Must be > 1. 319 @type max_size: int 320 """ 321 self.data = {} 322 self.set_max_size(max_size) 323 self.sentinel = LRUCacheNode(None, None)
324
325 - def set_max_size(self, max_size):
326 if max_size < 1: 327 max_size = 1 328 self.max_size = max_size
329
330 - def get(self, key):
331 """Get the answer associated with I{key}. Returns None if 332 no answer is cached for the key. 333 @param key: the key 334 @type key: (dns.name.Name, int, int) tuple whose values are the 335 query name, rdtype, and rdclass. 336 @rtype: dns.resolver.Answer object or None 337 """ 338 node = self.data.get(key) 339 if node is None: 340 return None 341 # Unlink because we're either going to move the node to the front 342 # of the LRU list or we're going to free it. 343 node.unlink() 344 if node.value.expiration <= time.time(): 345 del self.data[node.key] 346 return None 347 node.link_after(self.sentinel) 348 return node.value
349
350 - def put(self, key, value):
351 """Associate key and value in the cache. 352 @param key: the key 353 @type key: (dns.name.Name, int, int) tuple whose values are the 354 query name, rdtype, and rdclass. 355 @param value: The answer being cached 356 @type value: dns.resolver.Answer object 357 """ 358 node = self.data.get(key) 359 if not node is None: 360 node.unlink() 361 del self.data[node.key] 362 while len(self.data) >= self.max_size: 363 node = self.sentinel.prev 364 node.unlink() 365 del self.data[node.key] 366 node = LRUCacheNode(key, value) 367 node.link_after(self.sentinel) 368 self.data[key] = node
369
370 - def flush(self, key=None):
371 """Flush the cache. 372 373 If I{key} is specified, only that item is flushed. Otherwise 374 the entire cache is flushed. 375 376 @param key: the key to flush 377 @type key: (dns.name.Name, int, int) tuple or None 378 """ 379 if not key is None: 380 node = self.data.get(key) 381 if not node is None: 382 node.unlink() 383 del self.data[node.key] 384 else: 385 node = self.sentinel.next 386 while node != self.sentinel: 387 next = node.next 388 node.prev = None 389 node.next = None 390 node = next 391 self.data = {}
392
393 -class Resolver(object):
394 """DNS stub resolver 395 396 @ivar domain: The domain of this host 397 @type domain: dns.name.Name object 398 @ivar nameservers: A list of nameservers to query. Each nameserver is 399 a string which contains the IP address of a nameserver. 400 @type nameservers: list of strings 401 @ivar search: The search list. If the query name is a relative name, 402 the resolver will construct an absolute query name by appending the search 403 names one by one to the query name. 404 @type search: list of dns.name.Name objects 405 @ivar port: The port to which to send queries. The default is 53. 406 @type port: int 407 @ivar timeout: The number of seconds to wait for a response from a 408 server, before timing out. 409 @type timeout: float 410 @ivar lifetime: The total number of seconds to spend trying to get an 411 answer to the question. If the lifetime expires, a Timeout exception 412 will occur. 413 @type lifetime: float 414 @ivar keyring: The TSIG keyring to use. The default is None. 415 @type keyring: dict 416 @ivar keyname: The TSIG keyname to use. The default is None. 417 @type keyname: dns.name.Name object 418 @ivar keyalgorithm: The TSIG key algorithm to use. The default is 419 dns.tsig.default_algorithm. 420 @type keyalgorithm: string 421 @ivar edns: The EDNS level to use. The default is -1, no Edns. 422 @type edns: int 423 @ivar ednsflags: The EDNS flags 424 @type ednsflags: int 425 @ivar payload: The EDNS payload size. The default is 0. 426 @type payload: int 427 @ivar cache: The cache to use. The default is None. 428 @type cache: dns.resolver.Cache object 429 """
430 - def __init__(self, filename='/etc/resolv.conf', configure=True):
431 """Initialize a resolver instance. 432 433 @param filename: The filename of a configuration file in 434 standard /etc/resolv.conf format. This parameter is meaningful 435 only when I{configure} is true and the platform is POSIX. 436 @type filename: string or file object 437 @param configure: If True (the default), the resolver instance 438 is configured in the normal fashion for the operating system 439 the resolver is running on. (I.e. a /etc/resolv.conf file on 440 POSIX systems and from the registry on Windows systems.) 441 @type configure: bool""" 442 443 self.reset() 444 if configure: 445 if sys.platform == 'win32': 446 self.read_registry() 447 elif filename: 448 self.read_resolv_conf(filename)
449
450 - def reset(self):
451 """Reset all resolver configuration to the defaults.""" 452 self.domain = \ 453 dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) 454 if len(self.domain) == 0: 455 self.domain = dns.name.root 456 self.nameservers = [] 457 self.search = [] 458 self.port = 53 459 self.timeout = 2.0 460 self.lifetime = 30.0 461 self.keyring = None 462 self.keyname = None 463 self.keyalgorithm = dns.tsig.default_algorithm 464 self.edns = -1 465 self.ednsflags = 0 466 self.payload = 0 467 self.cache = None
468
469 - def read_resolv_conf(self, f):
470 """Process f as a file in the /etc/resolv.conf format. If f is 471 a string, it is used as the name of the file to open; otherwise it 472 is treated as the file itself.""" 473 if isinstance(f, str): 474 try: 475 f = open(f, 'r') 476 except IOError: 477 # /etc/resolv.conf doesn't exist, can't be read, etc. 478 # We'll just use the default resolver configuration. 479 self.nameservers = ['127.0.0.1'] 480 return 481 want_close = True 482 else: 483 want_close = False 484 try: 485 for l in f: 486 if len(l) == 0 or l[0] == '#' or l[0] == ';': 487 continue 488 tokens = l.split() 489 if len(tokens) == 0: 490 continue 491 if tokens[0] == 'nameserver': 492 self.nameservers.append(tokens[1]) 493 elif tokens[0] == 'domain': 494 self.domain = dns.name.from_text(tokens[1]) 495 elif tokens[0] == 'search': 496 for suffix in tokens[1:]: 497 self.search.append(dns.name.from_text(suffix)) 498 finally: 499 if want_close: 500 f.close() 501 if len(self.nameservers) == 0: 502 self.nameservers.append('127.0.0.1')
503
504 - def _determine_split_char(self, entry):
505 # 506 # The windows registry irritatingly changes the list element 507 # delimiter in between ' ' and ',' (and vice-versa) in various 508 # versions of windows. 509 # 510 if entry.find(' ') >= 0: 511 split_char = ' ' 512 elif entry.find(',') >= 0: 513 split_char = ',' 514 else: 515 # probably a singleton; treat as a space-separated list. 516 split_char = ' ' 517 return split_char
518
519 - def _config_win32_nameservers(self, nameservers):
520 """Configure a NameServer registry entry.""" 521 split_char = self._determine_split_char(nameservers) 522 ns_list = nameservers.split(split_char) 523 for ns in ns_list: 524 if not ns in self.nameservers: 525 self.nameservers.append(ns)
526
527 - def _config_win32_domain(self, domain):
528 """Configure a Domain registry entry.""" 529 self.domain = dns.name.from_text(domain)
530
531 - def _config_win32_search(self, search):
532 """Configure a Search registry entry.""" 533 split_char = self._determine_split_char(search) 534 search_list = search.split(split_char) 535 for s in search_list: 536 if not s in self.search: 537 self.search.append(dns.name.from_text(s))
538
539 - def _config_win32_fromkey(self, key):
540 """Extract DNS info from a registry key.""" 541 try: 542 servers, rtype = _winreg.QueryValueEx(key, 'NameServer') 543 except WindowsError: 544 servers = None 545 if servers: 546 self._config_win32_nameservers(servers) 547 try: 548 dom, rtype = _winreg.QueryValueEx(key, 'Domain') 549 if dom: 550 self._config_win32_domain(dom) 551 except WindowsError: 552 pass 553 else: 554 try: 555 servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') 556 except WindowsError: 557 servers = None 558 if servers: 559 self._config_win32_nameservers(servers) 560 try: 561 dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain') 562 if dom: 563 self._config_win32_domain(dom) 564 except WindowsError: 565 pass 566 try: 567 search, rtype = _winreg.QueryValueEx(key, 'SearchList') 568 except WindowsError: 569 search = None 570 if search: 571 self._config_win32_search(search)
572
573 - def read_registry(self):
574 """Extract resolver configuration from the Windows registry.""" 575 lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) 576 want_scan = False 577 try: 578 try: 579 # XP, 2000 580 tcp_params = _winreg.OpenKey(lm, 581 r'SYSTEM\CurrentControlSet' 582 r'\Services\Tcpip\Parameters') 583 want_scan = True 584 except EnvironmentError: 585 # ME 586 tcp_params = _winreg.OpenKey(lm, 587 r'SYSTEM\CurrentControlSet' 588 r'\Services\VxD\MSTCP') 589 try: 590 self._config_win32_fromkey(tcp_params) 591 finally: 592 tcp_params.Close() 593 if want_scan: 594 interfaces = _winreg.OpenKey(lm, 595 r'SYSTEM\CurrentControlSet' 596 r'\Services\Tcpip\Parameters' 597 r'\Interfaces') 598 try: 599 i = 0 600 while True: 601 try: 602 guid = _winreg.EnumKey(interfaces, i) 603 i += 1 604 key = _winreg.OpenKey(interfaces, guid) 605 if not self._win32_is_nic_enabled(lm, guid, key): 606 continue 607 try: 608 self._config_win32_fromkey(key) 609 finally: 610 key.Close() 611 except EnvironmentError: 612 break 613 finally: 614 interfaces.Close() 615 finally: 616 lm.Close()
617
618 - def _win32_is_nic_enabled(self, lm, guid, interface_key):
619 # Look in the Windows Registry to determine whether the network 620 # interface corresponding to the given guid is enabled. 621 # 622 # (Code contributed by Paul Marks, thanks!) 623 # 624 try: 625 # This hard-coded location seems to be consistent, at least 626 # from Windows 2000 through Vista. 627 connection_key = _winreg.OpenKey( 628 lm, 629 r'SYSTEM\CurrentControlSet\Control\Network' 630 r'\{4D36E972-E325-11CE-BFC1-08002BE10318}' 631 r'\%s\Connection' % guid) 632 633 try: 634 # The PnpInstanceID points to a key inside Enum 635 (pnp_id, ttype) = _winreg.QueryValueEx( 636 connection_key, 'PnpInstanceID') 637 638 if ttype != _winreg.REG_SZ: 639 raise ValueError 640 641 device_key = _winreg.OpenKey( 642 lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id) 643 644 try: 645 # Get ConfigFlags for this device 646 (flags, ttype) = _winreg.QueryValueEx( 647 device_key, 'ConfigFlags') 648 649 if ttype != _winreg.REG_DWORD: 650 raise ValueError 651 652 # Based on experimentation, bit 0x1 indicates that the 653 # device is disabled. 654 return not (flags & 0x1) 655 656 finally: 657 device_key.Close() 658 finally: 659 connection_key.Close() 660 except (EnvironmentError, ValueError): 661 # Pre-vista, enabled interfaces seem to have a non-empty 662 # NTEContextList; this was how dnspython detected enabled 663 # nics before the code above was contributed. We've retained 664 # the old method since we don't know if the code above works 665 # on Windows 95/98/ME. 666 try: 667 (nte, ttype) = _winreg.QueryValueEx(interface_key, 668 'NTEContextList') 669 return nte is not None 670 except WindowsError: 671 return False
672
673 - def _compute_timeout(self, start):
674 now = time.time() 675 if now < start: 676 if start - now > 1: 677 # Time going backwards is bad. Just give up. 678 raise Timeout 679 else: 680 # Time went backwards, but only a little. This can 681 # happen, e.g. under vmware with older linux kernels. 682 # Pretend it didn't happen. 683 now = start 684 duration = now - start 685 if duration >= self.lifetime: 686 raise Timeout 687 return min(self.lifetime - duration, self.timeout)
688
689 - def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, 690 tcp=False, source=None, raise_on_no_answer=True, source_port=0):
691 """Query nameservers to find the answer to the question. 692 693 The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects 694 of the appropriate type, or strings that can be converted into objects 695 of the appropriate type. E.g. For I{rdtype} the integer 2 and the 696 the string 'NS' both mean to query for records with DNS rdata type NS. 697 698 @param qname: the query name 699 @type qname: dns.name.Name object or string 700 @param rdtype: the query type 701 @type rdtype: int or string 702 @param rdclass: the query class 703 @type rdclass: int or string 704 @param tcp: use TCP to make the query (default is False). 705 @type tcp: bool 706 @param source: bind to this IP address (defaults to machine default IP). 707 @type source: IP address in dotted quad notation 708 @param raise_on_no_answer: raise NoAnswer if there's no answer 709 (defaults is True). 710 @type raise_on_no_answer: bool 711 @param source_port: The port from which to send the message. 712 The default is 0. 713 @type source_port: int 714 @rtype: dns.resolver.Answer instance 715 @raises Timeout: no answers could be found in the specified lifetime 716 @raises NXDOMAIN: the query name does not exist 717 @raises NoAnswer: the response did not contain an answer and 718 raise_on_no_answer is True. 719 @raises NoNameservers: no non-broken nameservers are available to 720 answer the question.""" 721 722 if isinstance(qname, str): 723 qname = dns.name.from_text(qname, None) 724 if isinstance(rdtype, str): 725 rdtype = dns.rdatatype.from_text(rdtype) 726 if dns.rdatatype.is_metatype(rdtype): 727 raise NoMetaqueries 728 if isinstance(rdclass, str): 729 rdclass = dns.rdataclass.from_text(rdclass) 730 if dns.rdataclass.is_metaclass(rdclass): 731 raise NoMetaqueries 732 qnames_to_try = [] 733 if qname.is_absolute(): 734 qnames_to_try.append(qname) 735 else: 736 if len(qname) > 1: 737 qnames_to_try.append(qname.concatenate(dns.name.root)) 738 if self.search: 739 for suffix in self.search: 740 qnames_to_try.append(qname.concatenate(suffix)) 741 else: 742 qnames_to_try.append(qname.concatenate(self.domain)) 743 all_nxdomain = True 744 start = time.time() 745 for qname in qnames_to_try: 746 if self.cache: 747 answer = self.cache.get((qname, rdtype, rdclass)) 748 if not answer is None: 749 if answer.rrset is None and raise_on_no_answer: 750 raise NoAnswer 751 else: 752 return answer 753 request = dns.message.make_query(qname, rdtype, rdclass) 754 if not self.keyname is None: 755 request.use_tsig(self.keyring, self.keyname, 756 algorithm=self.keyalgorithm) 757 request.use_edns(self.edns, self.ednsflags, self.payload) 758 response = None 759 # 760 # make a copy of the servers list so we can alter it later. 761 # 762 nameservers = self.nameservers[:] 763 backoff = 0.10 764 while response is None: 765 if len(nameservers) == 0: 766 raise NoNameservers 767 for nameserver in nameservers[:]: 768 timeout = self._compute_timeout(start) 769 try: 770 if tcp: 771 response = dns.query.tcp(request, nameserver, 772 timeout, self.port, 773 source=source, 774 source_port=source_port) 775 else: 776 response = dns.query.udp(request, nameserver, 777 timeout, self.port, 778 source=source, 779 source_port=source_port) 780 if response.flags & dns.flags.TC: 781 # Response truncated; retry with TCP. 782 timeout = self._compute_timeout(start) 783 response = dns.query.tcp(request, nameserver, 784 timeout, self.port, 785 source=source, 786 source_port=source_port) 787 788 except (socket.error, dns.exception.Timeout): 789 # 790 # Communication failure or timeout. Go to the 791 # next server 792 # 793 response = None 794 continue 795 except dns.query.UnexpectedSource: 796 # 797 # Who knows? Keep going. 798 # 799 response = None 800 continue 801 except dns.exception.FormError: 802 # 803 # We don't understand what this server is 804 # saying. Take it out of the mix and 805 # continue. 806 # 807 nameservers.remove(nameserver) 808 response = None 809 continue 810 except EOFError: 811 # 812 # We're using TCP and they hung up on us. 813 # Probably they don't support TCP (though 814 # they're supposed to!). Take it out of the 815 # mix and continue. 816 # 817 nameservers.remove(nameserver) 818 response = None 819 continue 820 rcode = response.rcode() 821 if rcode == dns.rcode.NOERROR or \ 822 rcode == dns.rcode.NXDOMAIN: 823 break 824 # 825 # We got a response, but we're not happy with the 826 # rcode in it. Remove the server from the mix if 827 # the rcode isn't SERVFAIL. 828 # 829 if rcode != dns.rcode.SERVFAIL: 830 nameservers.remove(nameserver) 831 response = None 832 if not response is None: 833 break 834 # 835 # All nameservers failed! 836 # 837 if len(nameservers) > 0: 838 # 839 # But we still have servers to try. Sleep a bit 840 # so we don't pound them! 841 # 842 timeout = self._compute_timeout(start) 843 sleep_time = min(timeout, backoff) 844 backoff *= 2 845 time.sleep(sleep_time) 846 if response.rcode() == dns.rcode.NXDOMAIN: 847 continue 848 all_nxdomain = False 849 break 850 if all_nxdomain: 851 raise NXDOMAIN 852 answer = Answer(qname, rdtype, rdclass, response, 853 raise_on_no_answer) 854 if self.cache: 855 self.cache.put((qname, rdtype, rdclass), answer) 856 return answer
857
858 - def use_tsig(self, keyring, keyname=None, 859 algorithm=dns.tsig.default_algorithm):
860 """Add a TSIG signature to the query. 861 862 @param keyring: The TSIG keyring to use; defaults to None. 863 @type keyring: dict 864 @param keyname: The name of the TSIG key to use; defaults to None. 865 The key must be defined in the keyring. If a keyring is specified 866 but a keyname is not, then the key used will be the first key in the 867 keyring. Note that the order of keys in a dictionary is not defined, 868 so applications should supply a keyname when a keyring is used, unless 869 they know the keyring contains only one key. 870 @param algorithm: The TSIG key algorithm to use. The default 871 is dns.tsig.default_algorithm. 872 @type algorithm: string""" 873 self.keyring = keyring 874 if keyname is None: 875 self.keyname = next(iter(self.keyring.keys())) 876 else: 877 self.keyname = keyname 878 self.keyalgorithm = algorithm
879
880 - def use_edns(self, edns, ednsflags, payload):
881 """Configure Edns. 882 883 @param edns: The EDNS level to use. The default is -1, no Edns. 884 @type edns: int 885 @param ednsflags: The EDNS flags 886 @type ednsflags: int 887 @param payload: The EDNS payload size. The default is 0. 888 @type payload: int""" 889 890 if edns is None: 891 edns = -1 892 self.edns = edns 893 self.ednsflags = ednsflags 894 self.payload = payload
895 896 default_resolver = None 897
898 -def get_default_resolver():
899 """Get the default resolver, initializing it if necessary.""" 900 global default_resolver 901 if default_resolver is None: 902 default_resolver = Resolver() 903 return default_resolver
904
905 -def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, 906 tcp=False, source=None, raise_on_no_answer=True, 907 source_port=0):
908 """Query nameservers to find the answer to the question. 909 910 This is a convenience function that uses the default resolver 911 object to make the query. 912 @see: L{dns.resolver.Resolver.query} for more information on the 913 parameters.""" 914 return get_default_resolver().query(qname, rdtype, rdclass, tcp, source, 915 raise_on_no_answer, source_port)
916
917 -def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None):
918 """Find the name of the zone which contains the specified name. 919 920 @param name: the query name 921 @type name: absolute dns.name.Name object or string 922 @param rdclass: The query class 923 @type rdclass: int 924 @param tcp: use TCP to make the query (default is False). 925 @type tcp: bool 926 @param resolver: the resolver to use 927 @type resolver: dns.resolver.Resolver object or None 928 @rtype: dns.name.Name""" 929 930 if isinstance(name, str): 931 name = dns.name.from_text(name, dns.name.root) 932 if resolver is None: 933 resolver = get_default_resolver() 934 if not name.is_absolute(): 935 raise NotAbsolute(name) 936 while 1: 937 try: 938 answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) 939 if answer.rrset.name == name: 940 return name 941 # otherwise we were CNAMEd or DNAMEd and need to look higher 942 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): 943 pass 944 try: 945 name = name.parent() 946 except dns.name.NoParent: 947 raise NoRootSOA
948 949 # 950 # Support for overriding the system resolver for all python code in the 951 # running process. 952 # 953 954 _protocols_for_socktype = { 955 socket.SOCK_DGRAM : [socket.SOL_UDP], 956 socket.SOCK_STREAM : [socket.SOL_TCP], 957 } 958 959 _resolver = None 960 _original_getaddrinfo = socket.getaddrinfo 961 _original_getnameinfo = socket.getnameinfo 962 _original_getfqdn = socket.getfqdn 963 _original_gethostbyname = socket.gethostbyname 964 _original_gethostbyname_ex = socket.gethostbyname_ex 965 _original_gethostbyaddr = socket.gethostbyaddr 966
967 -def _getaddrinfo(host=None, service=None, family=socket.AF_UNSPEC, socktype=0, 968 proto=0, flags=0):
969 if flags & (socket.AI_ADDRCONFIG|socket.AI_V4MAPPED) != 0: 970 raise NotImplementedError 971 if host is None and service is None: 972 raise socket.gaierror(socket.EAI_NONAME) 973 v6addrs = [] 974 v4addrs = [] 975 canonical_name = None 976 try: 977 # Is host None or a V6 address literal? 978 if host is None: 979 canonical_name = 'localhost' 980 if flags & socket.AI_PASSIVE != 0: 981 v6addrs.append('::') 982 v4addrs.append('0.0.0.0') 983 else: 984 v6addrs.append('::1') 985 v4addrs.append('127.0.0.1') 986 else: 987 parts = host.split('%') 988 if len(parts) == 2: 989 ahost = parts[0] 990 else: 991 ahost = host 992 addr = dns.ipv6.inet_aton(ahost) 993 v6addrs.append(host) 994 canonical_name = host 995 except: 996 try: 997 # Is it a V4 address literal? 998 addr = dns.ipv4.inet_aton(host) 999 v4addrs.append(host) 1000 canonical_name = host 1001 except: 1002 if flags & socket.AI_NUMERICHOST == 0: 1003 try: 1004 qname = None 1005 if family == socket.AF_INET6 or family == socket.AF_UNSPEC: 1006 v6 = _resolver.query(host, dns.rdatatype.AAAA, 1007 raise_on_no_answer=False) 1008 # Note that setting host ensures we query the same name 1009 # for A as we did for AAAA. 1010 host = v6.qname 1011 canonical_name = v6.canonical_name.to_text(True) 1012 if v6.rrset is not None: 1013 for rdata in v6.rrset: 1014 v6addrs.append(rdata.address) 1015 if family == socket.AF_INET or family == socket.AF_UNSPEC: 1016 v4 = _resolver.query(host, dns.rdatatype.A, 1017 raise_on_no_answer=False) 1018 host = v4.qname 1019 canonical_name = v4.canonical_name.to_text(True) 1020 if v4.rrset is not None: 1021 for rdata in v4.rrset: 1022 v4addrs.append(rdata.address) 1023 except dns.resolver.NXDOMAIN: 1024 raise socket.gaierror(socket.EAI_NONAME) 1025 except: 1026 raise socket.gaierror(socket.EAI_SYSTEM) 1027 port = None 1028 try: 1029 # Is it a port literal? 1030 if service is None: 1031 port = 0 1032 else: 1033 port = int(service) 1034 except: 1035 if flags & socket.AI_NUMERICSERV == 0: 1036 try: 1037 port = socket.getservbyname(service) 1038 except: 1039 pass 1040 if port is None: 1041 raise socket.gaierror(socket.EAI_NONAME) 1042 tuples = [] 1043 if socktype == 0: 1044 socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM] 1045 else: 1046 socktypes = [socktype] 1047 if flags & socket.AI_CANONNAME != 0: 1048 cname = canonical_name 1049 else: 1050 cname = '' 1051 if family == socket.AF_INET6 or family == socket.AF_UNSPEC: 1052 for addr in v6addrs: 1053 for socktype in socktypes: 1054 for proto in _protocols_for_socktype[socktype]: 1055 tuples.append((socket.AF_INET6, socktype, proto, 1056 cname, (addr, port, 0, 0))) 1057 if family == socket.AF_INET or family == socket.AF_UNSPEC: 1058 for addr in v4addrs: 1059 for socktype in socktypes: 1060 for proto in _protocols_for_socktype[socktype]: 1061 tuples.append((socket.AF_INET, socktype, proto, 1062 cname, (addr, port))) 1063 if len(tuples) == 0: 1064 raise socket.gaierror(socket.EAI_NONAME) 1065 return tuples
1066
1067 -def _getnameinfo(sockaddr, flags=0):
1068 host = sockaddr[0] 1069 port = sockaddr[1] 1070 if len(sockaddr) == 4: 1071 scope = sockaddr[3] 1072 family = socket.AF_INET6 1073 else: 1074 scope = None 1075 family = socket.AF_INET 1076 tuples = _getaddrinfo(host, port, family, socket.SOCK_STREAM, 1077 socket.SOL_TCP, 0) 1078 if len(tuples) > 1: 1079 raise socket.error('sockaddr resolved to multiple addresses') 1080 addr = tuples[0][4][0] 1081 if flags & socket.NI_DGRAM: 1082 pname = 'udp' 1083 else: 1084 pname = 'tcp' 1085 qname = dns.reversename.from_address(addr) 1086 if flags & socket.NI_NUMERICHOST == 0: 1087 try: 1088 answer = _resolver.query(qname, 'PTR') 1089 hostname = answer.rrset[0].target.to_text(True) 1090 except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): 1091 if flags & socket.NI_NAMEREQD: 1092 raise socket.gaierror(socket.EAI_NONAME) 1093 hostname = addr 1094 if scope is not None: 1095 hostname += '%' + str(scope) 1096 else: 1097 hostname = addr 1098 if scope is not None: 1099 hostname += '%' + str(scope) 1100 if flags & socket.NI_NUMERICSERV: 1101 service = str(port) 1102 else: 1103 service = socket.getservbyport(port, pname) 1104 return (hostname, service)
1105
1106 -def _getfqdn(name=None):
1107 if name is None: 1108 name = socket.gethostname() 1109 return _getnameinfo(_getaddrinfo(name, 80)[0][4])[0]
1110
1111 -def _gethostbyname(name):
1112 return _gethostbyname_ex(name)[2][0]
1113
1114 -def _gethostbyname_ex(name):
1115 aliases = [] 1116 addresses = [] 1117 tuples = _getaddrinfo(name, 0, socket.AF_INET, socket.SOCK_STREAM, 1118 socket.SOL_TCP, socket.AI_CANONNAME) 1119 canonical = tuples[0][3] 1120 for item in tuples: 1121 addresses.append(item[4][0]) 1122 # XXX we just ignore aliases 1123 return (canonical, aliases, addresses)
1124
1125 -def _gethostbyaddr(ip):
1126 try: 1127 addr = dns.ipv6.inet_aton(ip) 1128 sockaddr = (ip, 80, 0, 0) 1129 family = socket.AF_INET6 1130 except: 1131 sockaddr = (ip, 80) 1132 family = socket.AF_INET 1133 (name, port) = _getnameinfo(sockaddr, socket.NI_NAMEREQD) 1134 aliases = [] 1135 addresses = [] 1136 tuples = _getaddrinfo(name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP, 1137 socket.AI_CANONNAME) 1138 canonical = tuples[0][3] 1139 for item in tuples: 1140 addresses.append(item[4][0]) 1141 # XXX we just ignore aliases 1142 return (canonical, aliases, addresses)
1143
1144 -def override_system_resolver(resolver=None):
1145 """Override the system resolver routines in the socket module with 1146 versions which use dnspython's resolver. 1147 1148 This can be useful in testing situations where you want to control 1149 the resolution behavior of python code without having to change 1150 the system's resolver settings (e.g. /etc/resolv.conf). 1151 1152 The resolver to use may be specified; if it's not, the default 1153 resolver will be used. 1154 1155 @param resolver: the resolver to use 1156 @type resolver: dns.resolver.Resolver object or None 1157 """ 1158 if resolver is None: 1159 resolver = get_default_resolver() 1160 global _resolver 1161 _resolver = resolver 1162 socket.getaddrinfo = _getaddrinfo 1163 socket.getnameinfo = _getnameinfo 1164 socket.getfqdn = _getfqdn 1165 socket.gethostbyname = _gethostbyname 1166 socket.gethostbyname_ex = _gethostbyname_ex 1167 socket.gethostbyaddr = _gethostbyaddr
1168
1169 -def restore_system_resolver():
1170 """Undo the effects of override_system_resolver(). 1171 """ 1172 global _resolver 1173 _resolver = None 1174 socket.getaddrinfo = _original_getaddrinfo 1175 socket.getnameinfo = _original_getnameinfo 1176 socket.getfqdn = _original_getfqdn 1177 socket.gethostbyname = _original_gethostbyname 1178 socket.gethostbyname_ex = _original_gethostbyname_ex 1179 socket.gethostbyaddr = _original_gethostbyaddr
1180