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

Source Code for Module dns.resolver

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