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