Index: tools/telemetry/third_party/webpagereplay/third_party/dns/resolver.py |
diff --git a/tools/telemetry/third_party/webpagereplay/third_party/dns/resolver.py b/tools/telemetry/third_party/webpagereplay/third_party/dns/resolver.py |
deleted file mode 100644 |
index 372d7d83615b9474e0a1e4594e6eae375d99d4f6..0000000000000000000000000000000000000000 |
--- a/tools/telemetry/third_party/webpagereplay/third_party/dns/resolver.py |
+++ /dev/null |
@@ -1,761 +0,0 @@ |
-# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. |
-# |
-# Permission to use, copy, modify, and distribute this software and its |
-# documentation for any purpose with or without fee is hereby granted, |
-# provided that the above copyright notice and this permission notice |
-# appear in all copies. |
-# |
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES |
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR |
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
- |
-"""DNS stub resolver. |
- |
-@var default_resolver: The default resolver object |
-@type default_resolver: dns.resolver.Resolver object""" |
- |
-import socket |
-import sys |
-import time |
- |
-import dns.exception |
-import dns.message |
-import dns.name |
-import dns.query |
-import dns.rcode |
-import dns.rdataclass |
-import dns.rdatatype |
- |
-if sys.platform == 'win32': |
- import _winreg |
- |
-class NXDOMAIN(dns.exception.DNSException): |
- """The query name does not exist.""" |
- pass |
- |
-# The definition of the Timeout exception has moved from here to the |
-# dns.exception module. We keep dns.resolver.Timeout defined for |
-# backwards compatibility. |
- |
-Timeout = dns.exception.Timeout |
- |
-class NoAnswer(dns.exception.DNSException): |
- """The response did not contain an answer to the question.""" |
- pass |
- |
-class NoNameservers(dns.exception.DNSException): |
- """No non-broken nameservers are available to answer the query.""" |
- pass |
- |
-class NotAbsolute(dns.exception.DNSException): |
- """Raised if an absolute domain name is required but a relative name |
- was provided.""" |
- pass |
- |
-class NoRootSOA(dns.exception.DNSException): |
- """Raised if for some reason there is no SOA at the root name. |
- This should never happen!""" |
- pass |
- |
- |
-class Answer(object): |
- """DNS stub resolver answer |
- |
- Instances of this class bundle up the result of a successful DNS |
- resolution. |
- |
- For convenience, the answer object implements much of the sequence |
- protocol, forwarding to its rrset. E.g. "for a in answer" is |
- equivalent to "for a in answer.rrset", "answer[i]" is equivalent |
- to "answer.rrset[i]", and "answer[i:j]" is equivalent to |
- "answer.rrset[i:j]". |
- |
- Note that CNAMEs or DNAMEs in the response may mean that answer |
- node's name might not be the query name. |
- |
- @ivar qname: The query name |
- @type qname: dns.name.Name object |
- @ivar rdtype: The query type |
- @type rdtype: int |
- @ivar rdclass: The query class |
- @type rdclass: int |
- @ivar response: The response message |
- @type response: dns.message.Message object |
- @ivar rrset: The answer |
- @type rrset: dns.rrset.RRset object |
- @ivar expiration: The time when the answer expires |
- @type expiration: float (seconds since the epoch) |
- """ |
- def __init__(self, qname, rdtype, rdclass, response): |
- self.qname = qname |
- self.rdtype = rdtype |
- self.rdclass = rdclass |
- self.response = response |
- min_ttl = -1 |
- rrset = None |
- for count in xrange(0, 15): |
- try: |
- rrset = response.find_rrset(response.answer, qname, |
- rdclass, rdtype) |
- if min_ttl == -1 or rrset.ttl < min_ttl: |
- min_ttl = rrset.ttl |
- break |
- except KeyError: |
- if rdtype != dns.rdatatype.CNAME: |
- try: |
- crrset = response.find_rrset(response.answer, |
- qname, |
- rdclass, |
- dns.rdatatype.CNAME) |
- if min_ttl == -1 or crrset.ttl < min_ttl: |
- min_ttl = crrset.ttl |
- for rd in crrset: |
- qname = rd.target |
- break |
- continue |
- except KeyError: |
- raise NoAnswer |
- raise NoAnswer |
- if rrset is None: |
- raise NoAnswer |
- self.rrset = rrset |
- self.expiration = time.time() + min_ttl |
- |
- def __getattr__(self, attr): |
- if attr == 'name': |
- return self.rrset.name |
- elif attr == 'ttl': |
- return self.rrset.ttl |
- elif attr == 'covers': |
- return self.rrset.covers |
- elif attr == 'rdclass': |
- return self.rrset.rdclass |
- elif attr == 'rdtype': |
- return self.rrset.rdtype |
- else: |
- raise AttributeError(attr) |
- |
- def __len__(self): |
- return len(self.rrset) |
- |
- def __iter__(self): |
- return iter(self.rrset) |
- |
- def __getitem__(self, i): |
- return self.rrset[i] |
- |
- def __delitem__(self, i): |
- del self.rrset[i] |
- |
- def __getslice__(self, i, j): |
- return self.rrset[i:j] |
- |
- def __delslice__(self, i, j): |
- del self.rrset[i:j] |
- |
-class Cache(object): |
- """Simple DNS answer cache. |
- |
- @ivar data: A dictionary of cached data |
- @type data: dict |
- @ivar cleaning_interval: The number of seconds between cleanings. The |
- default is 300 (5 minutes). |
- @type cleaning_interval: float |
- @ivar next_cleaning: The time the cache should next be cleaned (in seconds |
- since the epoch.) |
- @type next_cleaning: float |
- """ |
- |
- def __init__(self, cleaning_interval=300.0): |
- """Initialize a DNS cache. |
- |
- @param cleaning_interval: the number of seconds between periodic |
- cleanings. The default is 300.0 |
- @type cleaning_interval: float. |
- """ |
- |
- self.data = {} |
- self.cleaning_interval = cleaning_interval |
- self.next_cleaning = time.time() + self.cleaning_interval |
- |
- def maybe_clean(self): |
- """Clean the cache if it's time to do so.""" |
- |
- now = time.time() |
- if self.next_cleaning <= now: |
- keys_to_delete = [] |
- for (k, v) in self.data.iteritems(): |
- if v.expiration <= now: |
- keys_to_delete.append(k) |
- for k in keys_to_delete: |
- del self.data[k] |
- now = time.time() |
- self.next_cleaning = now + self.cleaning_interval |
- |
- def get(self, key): |
- """Get the answer associated with I{key}. Returns None if |
- no answer is cached for the key. |
- @param key: the key |
- @type key: (dns.name.Name, int, int) tuple whose values are the |
- query name, rdtype, and rdclass. |
- @rtype: dns.resolver.Answer object or None |
- """ |
- |
- self.maybe_clean() |
- v = self.data.get(key) |
- if v is None or v.expiration <= time.time(): |
- return None |
- return v |
- |
- def put(self, key, value): |
- """Associate key and value in the cache. |
- @param key: the key |
- @type key: (dns.name.Name, int, int) tuple whose values are the |
- query name, rdtype, and rdclass. |
- @param value: The answer being cached |
- @type value: dns.resolver.Answer object |
- """ |
- |
- self.maybe_clean() |
- self.data[key] = value |
- |
- def flush(self, key=None): |
- """Flush the cache. |
- |
- If I{key} is specified, only that item is flushed. Otherwise |
- the entire cache is flushed. |
- |
- @param key: the key to flush |
- @type key: (dns.name.Name, int, int) tuple or None |
- """ |
- |
- if not key is None: |
- if self.data.has_key(key): |
- del self.data[key] |
- else: |
- self.data = {} |
- self.next_cleaning = time.time() + self.cleaning_interval |
- |
-class Resolver(object): |
- """DNS stub resolver |
- |
- @ivar domain: The domain of this host |
- @type domain: dns.name.Name object |
- @ivar nameservers: A list of nameservers to query. Each nameserver is |
- a string which contains the IP address of a nameserver. |
- @type nameservers: list of strings |
- @ivar search: The search list. If the query name is a relative name, |
- the resolver will construct an absolute query name by appending the search |
- names one by one to the query name. |
- @type search: list of dns.name.Name objects |
- @ivar port: The port to which to send queries. The default is 53. |
- @type port: int |
- @ivar timeout: The number of seconds to wait for a response from a |
- server, before timing out. |
- @type timeout: float |
- @ivar lifetime: The total number of seconds to spend trying to get an |
- answer to the question. If the lifetime expires, a Timeout exception |
- will occur. |
- @type lifetime: float |
- @ivar keyring: The TSIG keyring to use. The default is None. |
- @type keyring: dict |
- @ivar keyname: The TSIG keyname to use. The default is None. |
- @type keyname: dns.name.Name object |
- @ivar keyalgorithm: The TSIG key algorithm to use. The default is |
- dns.tsig.default_algorithm. |
- @type keyalgorithm: string |
- @ivar edns: The EDNS level to use. The default is -1, no Edns. |
- @type edns: int |
- @ivar ednsflags: The EDNS flags |
- @type ednsflags: int |
- @ivar payload: The EDNS payload size. The default is 0. |
- @type payload: int |
- @ivar cache: The cache to use. The default is None. |
- @type cache: dns.resolver.Cache object |
- """ |
- def __init__(self, filename='/etc/resolv.conf', configure=True): |
- """Initialize a resolver instance. |
- |
- @param filename: The filename of a configuration file in |
- standard /etc/resolv.conf format. This parameter is meaningful |
- only when I{configure} is true and the platform is POSIX. |
- @type filename: string or file object |
- @param configure: If True (the default), the resolver instance |
- is configured in the normal fashion for the operating system |
- the resolver is running on. (I.e. a /etc/resolv.conf file on |
- POSIX systems and from the registry on Windows systems.) |
- @type configure: bool""" |
- |
- self.reset() |
- if configure: |
- if sys.platform == 'win32': |
- self.read_registry() |
- elif filename: |
- self.read_resolv_conf(filename) |
- |
- def reset(self): |
- """Reset all resolver configuration to the defaults.""" |
- self.domain = \ |
- dns.name.Name(dns.name.from_text(socket.gethostname())[1:]) |
- if len(self.domain) == 0: |
- self.domain = dns.name.root |
- self.nameservers = [] |
- self.search = [] |
- self.port = 53 |
- self.timeout = 2.0 |
- self.lifetime = 30.0 |
- self.keyring = None |
- self.keyname = None |
- self.keyalgorithm = dns.tsig.default_algorithm |
- self.edns = -1 |
- self.ednsflags = 0 |
- self.payload = 0 |
- self.cache = None |
- |
- def read_resolv_conf(self, f): |
- """Process f as a file in the /etc/resolv.conf format. If f is |
- a string, it is used as the name of the file to open; otherwise it |
- is treated as the file itself.""" |
- if isinstance(f, str) or isinstance(f, unicode): |
- try: |
- f = open(f, 'r') |
- except IOError: |
- # /etc/resolv.conf doesn't exist, can't be read, etc. |
- # We'll just use the default resolver configuration. |
- self.nameservers = ['127.0.0.1'] |
- return |
- want_close = True |
- else: |
- want_close = False |
- try: |
- for l in f: |
- if len(l) == 0 or l[0] == '#' or l[0] == ';': |
- continue |
- tokens = l.split() |
- if len(tokens) == 0: |
- continue |
- if tokens[0] == 'nameserver': |
- self.nameservers.append(tokens[1]) |
- elif tokens[0] == 'domain': |
- self.domain = dns.name.from_text(tokens[1]) |
- elif tokens[0] == 'search': |
- for suffix in tokens[1:]: |
- self.search.append(dns.name.from_text(suffix)) |
- finally: |
- if want_close: |
- f.close() |
- if len(self.nameservers) == 0: |
- self.nameservers.append('127.0.0.1') |
- |
- def _determine_split_char(self, entry): |
- # |
- # The windows registry irritatingly changes the list element |
- # delimiter in between ' ' and ',' (and vice-versa) in various |
- # versions of windows. |
- # |
- if entry.find(' ') >= 0: |
- split_char = ' ' |
- elif entry.find(',') >= 0: |
- split_char = ',' |
- else: |
- # probably a singleton; treat as a space-separated list. |
- split_char = ' ' |
- return split_char |
- |
- def _config_win32_nameservers(self, nameservers): |
- """Configure a NameServer registry entry.""" |
- # we call str() on nameservers to convert it from unicode to ascii |
- nameservers = str(nameservers) |
- split_char = self._determine_split_char(nameservers) |
- ns_list = nameservers.split(split_char) |
- for ns in ns_list: |
- if not ns in self.nameservers: |
- self.nameservers.append(ns) |
- |
- def _config_win32_domain(self, domain): |
- """Configure a Domain registry entry.""" |
- # we call str() on domain to convert it from unicode to ascii |
- self.domain = dns.name.from_text(str(domain)) |
- |
- def _config_win32_search(self, search): |
- """Configure a Search registry entry.""" |
- # we call str() on search to convert it from unicode to ascii |
- search = str(search) |
- split_char = self._determine_split_char(search) |
- search_list = search.split(split_char) |
- for s in search_list: |
- if not s in self.search: |
- self.search.append(dns.name.from_text(s)) |
- |
- def _config_win32_fromkey(self, key): |
- """Extract DNS info from a registry key.""" |
- try: |
- servers, rtype = _winreg.QueryValueEx(key, 'NameServer') |
- except WindowsError: |
- servers = None |
- if servers: |
- self._config_win32_nameservers(servers) |
- try: |
- dom, rtype = _winreg.QueryValueEx(key, 'Domain') |
- if dom: |
- self._config_win32_domain(dom) |
- except WindowsError: |
- pass |
- else: |
- try: |
- servers, rtype = _winreg.QueryValueEx(key, 'DhcpNameServer') |
- except WindowsError: |
- servers = None |
- if servers: |
- self._config_win32_nameservers(servers) |
- try: |
- dom, rtype = _winreg.QueryValueEx(key, 'DhcpDomain') |
- if dom: |
- self._config_win32_domain(dom) |
- except WindowsError: |
- pass |
- try: |
- search, rtype = _winreg.QueryValueEx(key, 'SearchList') |
- except WindowsError: |
- search = None |
- if search: |
- self._config_win32_search(search) |
- |
- def read_registry(self): |
- """Extract resolver configuration from the Windows registry.""" |
- lm = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) |
- want_scan = False |
- try: |
- try: |
- # XP, 2000 |
- tcp_params = _winreg.OpenKey(lm, |
- r'SYSTEM\CurrentControlSet' |
- r'\Services\Tcpip\Parameters') |
- want_scan = True |
- except EnvironmentError: |
- # ME |
- tcp_params = _winreg.OpenKey(lm, |
- r'SYSTEM\CurrentControlSet' |
- r'\Services\VxD\MSTCP') |
- try: |
- self._config_win32_fromkey(tcp_params) |
- finally: |
- tcp_params.Close() |
- if want_scan: |
- interfaces = _winreg.OpenKey(lm, |
- r'SYSTEM\CurrentControlSet' |
- r'\Services\Tcpip\Parameters' |
- r'\Interfaces') |
- try: |
- i = 0 |
- while True: |
- try: |
- guid = _winreg.EnumKey(interfaces, i) |
- i += 1 |
- key = _winreg.OpenKey(interfaces, guid) |
- if not self._win32_is_nic_enabled(lm, guid, key): |
- continue |
- try: |
- self._config_win32_fromkey(key) |
- finally: |
- key.Close() |
- except EnvironmentError: |
- break |
- finally: |
- interfaces.Close() |
- finally: |
- lm.Close() |
- |
- def _win32_is_nic_enabled(self, lm, guid, interface_key): |
- # Look in the Windows Registry to determine whether the network |
- # interface corresponding to the given guid is enabled. |
- # |
- # (Code contributed by Paul Marks, thanks!) |
- # |
- try: |
- # This hard-coded location seems to be consistent, at least |
- # from Windows 2000 through Vista. |
- connection_key = _winreg.OpenKey( |
- lm, |
- r'SYSTEM\CurrentControlSet\Control\Network' |
- r'\{4D36E972-E325-11CE-BFC1-08002BE10318}' |
- r'\%s\Connection' % guid) |
- |
- try: |
- # The PnpInstanceID points to a key inside Enum |
- (pnp_id, ttype) = _winreg.QueryValueEx( |
- connection_key, 'PnpInstanceID') |
- |
- if ttype != _winreg.REG_SZ: |
- raise ValueError |
- |
- device_key = _winreg.OpenKey( |
- lm, r'SYSTEM\CurrentControlSet\Enum\%s' % pnp_id) |
- |
- try: |
- # Get ConfigFlags for this device |
- (flags, ttype) = _winreg.QueryValueEx( |
- device_key, 'ConfigFlags') |
- |
- if ttype != _winreg.REG_DWORD: |
- raise ValueError |
- |
- # Based on experimentation, bit 0x1 indicates that the |
- # device is disabled. |
- return not (flags & 0x1) |
- |
- finally: |
- device_key.Close() |
- finally: |
- connection_key.Close() |
- except (EnvironmentError, ValueError): |
- # Pre-vista, enabled interfaces seem to have a non-empty |
- # NTEContextList; this was how dnspython detected enabled |
- # nics before the code above was contributed. We've retained |
- # the old method since we don't know if the code above works |
- # on Windows 95/98/ME. |
- try: |
- (nte, ttype) = _winreg.QueryValueEx(interface_key, |
- 'NTEContextList') |
- return nte is not None |
- except WindowsError: |
- return False |
- |
- def _compute_timeout(self, start): |
- now = time.time() |
- if now < start: |
- if start - now > 1: |
- # Time going backwards is bad. Just give up. |
- raise Timeout |
- else: |
- # Time went backwards, but only a little. This can |
- # happen, e.g. under vmware with older linux kernels. |
- # Pretend it didn't happen. |
- now = start |
- duration = now - start |
- if duration >= self.lifetime: |
- raise Timeout |
- return min(self.lifetime - duration, self.timeout) |
- |
- def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, |
- tcp=False, source=None): |
- """Query nameservers to find the answer to the question. |
- |
- The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects |
- of the appropriate type, or strings that can be converted into objects |
- of the appropriate type. E.g. For I{rdtype} the integer 2 and the |
- the string 'NS' both mean to query for records with DNS rdata type NS. |
- |
- @param qname: the query name |
- @type qname: dns.name.Name object or string |
- @param rdtype: the query type |
- @type rdtype: int or string |
- @param rdclass: the query class |
- @type rdclass: int or string |
- @param tcp: use TCP to make the query (default is False). |
- @type tcp: bool |
- @param source: bind to this IP address (defaults to machine default IP). |
- @type source: IP address in dotted quad notation |
- @rtype: dns.resolver.Answer instance |
- @raises Timeout: no answers could be found in the specified lifetime |
- @raises NXDOMAIN: the query name does not exist |
- @raises NoAnswer: the response did not contain an answer |
- @raises NoNameservers: no non-broken nameservers are available to |
- answer the question.""" |
- |
- if isinstance(qname, (str, unicode)): |
- qname = dns.name.from_text(qname, None) |
- if isinstance(rdtype, str): |
- rdtype = dns.rdatatype.from_text(rdtype) |
- if isinstance(rdclass, str): |
- rdclass = dns.rdataclass.from_text(rdclass) |
- qnames_to_try = [] |
- if qname.is_absolute(): |
- qnames_to_try.append(qname) |
- else: |
- if len(qname) > 1: |
- qnames_to_try.append(qname.concatenate(dns.name.root)) |
- if self.search: |
- for suffix in self.search: |
- qnames_to_try.append(qname.concatenate(suffix)) |
- else: |
- qnames_to_try.append(qname.concatenate(self.domain)) |
- all_nxdomain = True |
- start = time.time() |
- for qname in qnames_to_try: |
- if self.cache: |
- answer = self.cache.get((qname, rdtype, rdclass)) |
- if answer: |
- return answer |
- request = dns.message.make_query(qname, rdtype, rdclass) |
- if not self.keyname is None: |
- request.use_tsig(self.keyring, self.keyname, self.keyalgorithm) |
- request.use_edns(self.edns, self.ednsflags, self.payload) |
- response = None |
- # |
- # make a copy of the servers list so we can alter it later. |
- # |
- nameservers = self.nameservers[:] |
- backoff = 0.10 |
- while response is None: |
- if len(nameservers) == 0: |
- raise NoNameservers |
- for nameserver in nameservers[:]: |
- timeout = self._compute_timeout(start) |
- try: |
- if tcp: |
- response = dns.query.tcp(request, nameserver, |
- timeout, self.port, |
- source=source) |
- else: |
- response = dns.query.udp(request, nameserver, |
- timeout, self.port, |
- source=source) |
- except (socket.error, dns.exception.Timeout): |
- # |
- # Communication failure or timeout. Go to the |
- # next server |
- # |
- response = None |
- continue |
- except dns.query.UnexpectedSource: |
- # |
- # Who knows? Keep going. |
- # |
- response = None |
- continue |
- except dns.exception.FormError: |
- # |
- # We don't understand what this server is |
- # saying. Take it out of the mix and |
- # continue. |
- # |
- nameservers.remove(nameserver) |
- response = None |
- continue |
- rcode = response.rcode() |
- if rcode == dns.rcode.NOERROR or \ |
- rcode == dns.rcode.NXDOMAIN: |
- break |
- # |
- # We got a response, but we're not happy with the |
- # rcode in it. Remove the server from the mix if |
- # the rcode isn't SERVFAIL. |
- # |
- if rcode != dns.rcode.SERVFAIL: |
- nameservers.remove(nameserver) |
- response = None |
- if not response is None: |
- break |
- # |
- # All nameservers failed! |
- # |
- if len(nameservers) > 0: |
- # |
- # But we still have servers to try. Sleep a bit |
- # so we don't pound them! |
- # |
- timeout = self._compute_timeout(start) |
- sleep_time = min(timeout, backoff) |
- backoff *= 2 |
- time.sleep(sleep_time) |
- if response.rcode() == dns.rcode.NXDOMAIN: |
- continue |
- all_nxdomain = False |
- break |
- if all_nxdomain: |
- raise NXDOMAIN |
- answer = Answer(qname, rdtype, rdclass, response) |
- if self.cache: |
- self.cache.put((qname, rdtype, rdclass), answer) |
- return answer |
- |
- def use_tsig(self, keyring, keyname=None, |
- algorithm=dns.tsig.default_algorithm): |
- """Add a TSIG signature to the query. |
- |
- @param keyring: The TSIG keyring to use; defaults to None. |
- @type keyring: dict |
- @param keyname: The name of the TSIG key to use; defaults to None. |
- The key must be defined in the keyring. If a keyring is specified |
- but a keyname is not, then the key used will be the first key in the |
- keyring. Note that the order of keys in a dictionary is not defined, |
- so applications should supply a keyname when a keyring is used, unless |
- they know the keyring contains only one key. |
- @param algorithm: The TSIG key algorithm to use. The default |
- is dns.tsig.default_algorithm. |
- @type algorithm: string""" |
- self.keyring = keyring |
- if keyname is None: |
- self.keyname = self.keyring.keys()[0] |
- else: |
- self.keyname = keyname |
- self.keyalgorithm = algorithm |
- |
- def use_edns(self, edns, ednsflags, payload): |
- """Configure Edns. |
- |
- @param edns: The EDNS level to use. The default is -1, no Edns. |
- @type edns: int |
- @param ednsflags: The EDNS flags |
- @type ednsflags: int |
- @param payload: The EDNS payload size. The default is 0. |
- @type payload: int""" |
- |
- if edns is None: |
- edns = -1 |
- self.edns = edns |
- self.ednsflags = ednsflags |
- self.payload = payload |
- |
-default_resolver = None |
- |
-def get_default_resolver(): |
- """Get the default resolver, initializing it if necessary.""" |
- global default_resolver |
- if default_resolver is None: |
- default_resolver = Resolver() |
- return default_resolver |
- |
-def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN, |
- tcp=False, source=None): |
- """Query nameservers to find the answer to the question. |
- |
- This is a convenience function that uses the default resolver |
- object to make the query. |
- @see: L{dns.resolver.Resolver.query} for more information on the |
- parameters.""" |
- return get_default_resolver().query(qname, rdtype, rdclass, tcp, source) |
- |
-def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None): |
- """Find the name of the zone which contains the specified name. |
- |
- @param name: the query name |
- @type name: absolute dns.name.Name object or string |
- @param rdclass: The query class |
- @type rdclass: int |
- @param tcp: use TCP to make the query (default is False). |
- @type tcp: bool |
- @param resolver: the resolver to use |
- @type resolver: dns.resolver.Resolver object or None |
- @rtype: dns.name.Name""" |
- |
- if isinstance(name, (str, unicode)): |
- name = dns.name.from_text(name, dns.name.root) |
- if resolver is None: |
- resolver = get_default_resolver() |
- if not name.is_absolute(): |
- raise NotAbsolute(name) |
- while 1: |
- try: |
- answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp) |
- return name |
- except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): |
- try: |
- name = name.parent() |
- except dns.name.NoParent: |
- raise NoRootSOA |