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