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