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