diff options
author | Casey Deccio <casey@deccio.net> | 2016-08-02 20:01:27 +0300 |
---|---|---|
committer | Casey Deccio <casey@deccio.net> | 2016-08-02 20:01:27 +0300 |
commit | cebbb54a6bc00ffe83b32af4cd285fc205e76706 (patch) | |
tree | 61040f1aa611f8166e0057ad35fb30373008174a | |
parent | 18e8294ecafb1943fca908da4aeb112f1bef37f8 (diff) |
Allow analysis of domain beyond explicit delegation
Allow analysis of domain beyond explicit delegation, if specified on
command line.
-rw-r--r-- | dnsviz/analysis/online.py | 35 | ||||
-rw-r--r-- | dnsviz/commands/probe.py | 30 |
2 files changed, 33 insertions, 32 deletions
diff --git a/dnsviz/analysis/online.py b/dnsviz/analysis/online.py index 4926535..272842e 100644 --- a/dnsviz/analysis/online.py +++ b/dnsviz/analysis/online.py @@ -963,10 +963,11 @@ class Analyst(object): qname_only = True analysis_type = ANALYSIS_TYPE_AUTHORITATIVE - clone_attrnames = ['dlv_domain', 'try_ipv4', 'try_ipv6', 'client_ipv4', 'client_ipv6', 'logger', 'ceiling', 'edns_diagnostics', 'follow_ns', 'explicit_delegations', 'odd_ports', 'explicit_only', 'analysis_cache', 'cache_level', 'analysis_cache_lock', 'transport_manager', 'th_factories', 'resolver'] + clone_attrnames = ['dlv_domain', 'try_ipv4', 'try_ipv6', 'client_ipv4', 'client_ipv6', 'logger', 'ceiling', 'edns_diagnostics', 'follow_ns', 'explicit_delegations', 'stop_at_explicit', 'odd_ports', 'explicit_only', 'analysis_cache', 'cache_level', 'analysis_cache_lock', 'transport_manager', 'th_factories', 'resolver'] def __init__(self, name, dlv_domain=None, try_ipv4=True, try_ipv6=True, client_ipv4=None, client_ipv6=None, logger=_logger, ceiling=None, edns_diagnostics=False, - follow_ns=False, follow_mx=False, trace=None, explicit_delegations=None, odd_ports=None, extra_rdtypes=None, explicit_only=False, analysis_cache=None, cache_level=None, analysis_cache_lock=None, th_factories=None, transport_manager=None, resolver=None): + follow_ns=False, follow_mx=False, trace=None, explicit_delegations=None, stop_at_explicit=None, odd_ports=None, extra_rdtypes=None, explicit_only=False, + analysis_cache=None, cache_level=None, analysis_cache_lock=None, th_factories=None, transport_manager=None, resolver=None): if transport_manager is None: self.transport_manager = transport.DNSQueryTransportManager() @@ -988,6 +989,11 @@ class Analyst(object): else: self.explicit_delegations = explicit_delegations + if stop_at_explicit is None: + self.stop_at_explicit = {} + else: + self.stop_at_explicit = stop_at_explicit + if odd_ports is None: self.odd_ports = {} else: @@ -1008,7 +1014,7 @@ class Analyst(object): c = self.name try: while True: - if (c, dns.rdatatype.NS) in self.explicit_delegations: + if (c, dns.rdatatype.NS) in self.explicit_delegations and self.stop_at_explicit[c]: break c = c.parent() except dns.name.NoParent: @@ -1025,7 +1031,6 @@ class Analyst(object): ceiling = c self.local_ceiling = self._detect_ceiling(ceiling)[0] - self._fix_explicit_delegation() self.try_ipv4 = try_ipv4 self.try_ipv6 = try_ipv6 @@ -1119,24 +1124,6 @@ class Analyst(object): return ceiling, True return self._detect_ceiling(ceiling.parent()) - def _fix_explicit_delegation(self): - if self.local_ceiling is None: - return - - # at this point, if self.name or any ancestor below self.local_ceiling has an - # explicit delegation, then it is obsolete and needs to be applied to - # self.local_ceiling instead. - n = self.name - explicit_delegation = None - while n != self.local_ceiling: - if (n, dns.rdatatype.NS) in self.explicit_delegations: - if explicit_delegation is None: - explicit_delegation = self.explicit_delegations[(n, dns.rdatatype.NS)] - del self.explicit_delegations[(n, dns.rdatatype.NS)] - n = n.parent() - if explicit_delegation is not None: - self.explicit_delegations[(self.local_ceiling, dns.rdatatype.NS)] = explicit_delegation - def _get_servers_from_hints(self, name, hints): servers = set() for rdata in hints[(name, dns.rdatatype.NS)]: @@ -1484,10 +1471,10 @@ class Analyst(object): # ceiling or the name is a subdomain of the ceiling if name == dns.name.root: parent_obj = None + elif (name, dns.rdatatype.NS) in self.explicit_delegations and self.stop_at_explicit[name]: + parent_obj = None elif self.local_ceiling is not None and self.local_ceiling.is_subdomain(name): parent_obj = self._analyze_stub(name.parent()) - elif (name, dns.rdatatype.NS) in self.explicit_delegations: - parent_obj = None else: parent_obj = self._analyze(name.parent()) diff --git a/dnsviz/commands/probe.py b/dnsviz/commands/probe.py index e27916a..ccbedda 100644 --- a/dnsviz/commands/probe.py +++ b/dnsviz/commands/probe.py @@ -78,6 +78,7 @@ A_ROOT_IPV6 = IPAddr('2001:503:ba3e::2:30') BRACKETS_RE = re.compile(r'^\[(.*)\]$') PORT_RE = re.compile(r'^(.*):(\d+)$') +STOP_RE = re.compile(r'^(.*)\+$') NAME_VAL_DELIM_RE = re.compile(r'\s*=\s*') #XXX this is a hack required for inter-process sharing of dns.name.Name @@ -115,13 +116,13 @@ def _init_subprocess(): def _analyze(args): (cls, name, dlv_domain, try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, \ - extra_rdtypes, explicit_only, cache, cache_level, cache_lock, th_factories) = args + stop_at_explicit, extra_rdtypes, explicit_only, cache, cache_level, cache_lock, th_factories) = args if ceiling is not None and name.is_subdomain(ceiling): c = ceiling else: c = name try: - a = cls(name, dlv_domain=dlv_domain, try_ipv4=try_ipv4, try_ipv6=try_ipv6, client_ipv4=client_ipv4, client_ipv6=client_ipv6, ceiling=c, edns_diagnostics=edns_diagnostics, explicit_delegations=explicit_delegations, odd_ports=odd_ports, extra_rdtypes=extra_rdtypes, explicit_only=explicit_only, analysis_cache=cache, cache_level=cache_level, analysis_cache_lock=cache_lock, transport_manager=tm, th_factories=th_factories, resolver=full_resolver) + a = cls(name, dlv_domain=dlv_domain, try_ipv4=try_ipv4, try_ipv6=try_ipv6, client_ipv4=client_ipv4, client_ipv6=client_ipv6, ceiling=c, edns_diagnostics=edns_diagnostics, explicit_delegations=explicit_delegations, stop_at_explicit=stop_at_explicit, odd_ports=odd_ports, extra_rdtypes=extra_rdtypes, explicit_only=explicit_only, analysis_cache=cache, cache_level=cache_level, analysis_cache_lock=cache_lock, transport_manager=tm, th_factories=th_factories, resolver=full_resolver) return a.analyze() # re-raise a KeyboardInterrupt, as this means we've been interrupted except KeyboardInterrupt: @@ -140,13 +141,14 @@ def _analyze(args): class BulkAnalyst(object): analyst_cls = PrivateAnalyst - def __init__(self, try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, extra_rdtypes, explicit_only, dlv_domain, th_factories): + def __init__(self, try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, stop_at_explicit, cache_level, extra_rdtypes, explicit_only, dlv_domain, th_factories): self.try_ipv4 = try_ipv4 self.try_ipv6 = try_ipv6 self.client_ipv4 = client_ipv4 self.client_ipv6 = client_ipv6 self.ceiling = ceiling self.edns_diagnostics = edns_diagnostics + self.stop_at_explicit = stop_at_explicit self.cache_level = cache_level self.extra_rdtypes = extra_rdtypes self.explicit_only = explicit_only @@ -158,7 +160,7 @@ class BulkAnalyst(object): def _name_to_args_iter(self, names): for name in names: - yield (self.analyst_cls, name, self.dlv_domain, self.try_ipv4, self.try_ipv6, self.client_ipv4, self.client_ipv6, self.ceiling, self.edns_diagnostics, self.extra_rdtypes, self.explicit_only, self.cache, self.cache_level, self.cache_lock, self.th_factories) + yield (self.analyst_cls, name, self.dlv_domain, self.try_ipv4, self.try_ipv6, self.client_ipv4, self.client_ipv6, self.ceiling, self.edns_diagnostics, self.stop_at_explicit, self.extra_rdtypes, self.explicit_only, self.cache, self.cache_level, self.cache_lock, self.th_factories) def analyze(self, names, flush_func=None): name_objs = [] @@ -236,8 +238,8 @@ class RecursiveMultiProcessAnalyst(MultiProcessAnalystMixin, PrivateRecursiveAna class ParallelAnalystMixin(object): analyst_cls = MultiProcessAnalyst - def __init__(self, try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, extra_rdtypes, explicit_only, dlv_domain, th_factories, processes): - super(ParallelAnalystMixin, self).__init__(try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, extra_rdtypes, explicit_only, dlv_domain, th_factories) + def __init__(self, try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, stop_at_explicit, cache_level, extra_rdtypes, explicit_only, dlv_domain, th_factories, processes): + super(ParallelAnalystMixin, self).__init__(try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, stop_at_explicit, cache_level, extra_rdtypes, explicit_only, dlv_domain, th_factories) self.manager = multiprocessing.managers.SyncManager() self.manager.start() @@ -507,6 +509,7 @@ def main(argv): # get all the -x options explicit_delegations = {} odd_ports = {} + stop_at_explicit = {} client_ipv4 = None client_ipv6 = None for opt, arg in opts: @@ -518,11 +521,22 @@ def main(argv): sys.exit(1) domain = domain.strip() mappings = mappings.strip() + + match = STOP_RE.search(domain) + if match is not None: + domain = match.group(1) + try: domain = dns.name.from_text(domain) except dns.exception.DNSException: usage('The domain name was invalid: "%s"' % domain) sys.exit(1) + + if match is not None: + stop_at_explicit[domain] = True + else: + stop_at_explicit[domain] = False + if not mappings: usage('Incorrect usage of -x option: "%s"' % arg) sys.exit(1) @@ -826,9 +840,9 @@ def main(argv): name_objs.append(OnlineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) else: if '-t' in opts: - a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, rdtypes, explicit_only, dlv_domain, th_factories, processes) + a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, stop_at_explicit, cache_level, rdtypes, explicit_only, dlv_domain, th_factories, processes) else: - a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, rdtypes, explicit_only, dlv_domain, th_factories) + a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, stop_at_explicit, cache_level, rdtypes, explicit_only, dlv_domain, th_factories) if flush: fh.write('{') a.analyze(names, _flush) |