def to_address(name): """Convert a reverse map domain name into textual address form. @param name: an IPv4 or IPv6 address in reverse-map form. @type name: dns.name.Name object @rtype: str """ if name.is_subdomain(ipv4_reverse_domain): name = name.relativize(ipv4_reverse_domain) labels = list(name.labels) labels.reverse() text = '.'.join([x.decode('ascii') for x in labels]) # run through inet_aton() to check syntax and make pretty. return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) elif name.is_subdomain(ipv6_reverse_domain): name = name.relativize(ipv6_reverse_domain) labels = list(name.labels) labels.reverse() parts = [] i = 0 l = len(labels) while i < l: parts.append(''.join([x.decode('ascii') for x in labels[i:i + 4]])) i += 4 text = ':'.join(parts) # run through inet_aton() to check syntax and make pretty. return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) else: raise dns.exception.SyntaxError('unknown reverse-map address family')
def to_address(name): """Convert a reverse map domain name into textual address form. *name*, a ``dns.name.Name``, an IPv4 or IPv6 address in reverse-map name form. Raises ``dns.exception.SyntaxError`` if the name does not have a reverse-map form. Returns a ``text``. """ if name.is_subdomain(ipv4_reverse_domain): name = name.relativize(ipv4_reverse_domain) labels = list(name.labels) labels.reverse() text = b'.'.join(labels) # run through inet_aton() to check syntax and make pretty. return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) elif name.is_subdomain(ipv6_reverse_domain): name = name.relativize(ipv6_reverse_domain) labels = list(name.labels) labels.reverse() parts = [] i = 0 l = len(labels) while i < l: parts.append(b''.join(labels[i:i + 4])) i += 4 text = b':'.join(parts) # run through inet_aton() to check syntax and make pretty. return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) else: raise dns.exception.SyntaxError('unknown reverse-map address family')
def to_address(name): """Convert a reverse map domain name into textual address form. @param name: an IPv4 or IPv6 address in reverse-map form. @type name: dns.name.Name object @rtype: str """ if name.is_subdomain(ipv4_reverse_domain): name = name.relativize(ipv4_reverse_domain) labels = list(name.labels) labels.reverse() text = '.'.join(labels) # run through inet_aton() to check syntax and make pretty. return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) elif name.is_subdomain(ipv6_reverse_domain): name = name.relativize(ipv6_reverse_domain) labels = list(name.labels) labels.reverse() parts = [] i = 0 l = len(labels) while i < l: parts.append(''.join(labels[i:i+4])) i += 4 text = ':'.join(parts) # run through inet_aton() to check syntax and make pretty. return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) else: raise dns.exception.SyntaxError('unknown reverse-map address family')
def zone_for_name_effect(name): if isinstance(name, str): name = dns.name.from_text(name) zone = dns.name.from_text('zone.com') if name.is_subdomain(zone): return zone raise ValueError("Bad arguments")
def _validate_name(self, name): if name.is_absolute(): if not name.is_subdomain(self.zone.origin): raise KeyError("name is not a subdomain of the zone origin") if self.zone.relativize: name = name.relativize(self.origin) return name
def _validate_name(self, name): if name.is_absolute(): if not name.is_subdomain(self.zone.origin): raise KeyError("name is not a subdomain of the zone origin") if self.zone.relativize: # XXXRTH should it be an error if self.origin is still None? name = name.relativize(self.origin) return name
def _create_and_serve_zone(zone, mappings, port): zonefile = tempfile.NamedTemporaryFile('w', prefix='dnsviz', delete=False) atexit.register(os.remove, zonefile.name) zonefile.write('$ORIGIN %s\n@ IN SOA localhost. root.localhost. 1 1800 900 86400 600\n@ IN NS @\n@ IN A 127.0.0.1\n' % lb2s(zone.canonicalize().to_text())) for name, rdtype in mappings: if not name.is_subdomain(zone): continue zonefile.write(mappings[(name, rdtype)].to_text() + '\n') zonefile.close() _serve_zone(zone, zonefile.name, port)
def _validate_name(self, name): if isinstance(name, (str, unicode)): name = dns.name.from_text(name, None) elif not isinstance(name, dns.name.Name): raise KeyError("name parameter must be convertable to a DNS name") if name.is_absolute(): if not name.is_subdomain(self.origin): raise KeyError("name parameter must be a subdomain of the zone origin") if self.relativize: name = name.relativize(self.origin) return name
def _get_zone(name, zones): """Determine which of the zones name is in. Returns the zone name is in, or None. """ for zone in zones: if name.is_subdomain(zone): return zone return None
def is_delegated(delegated_names, name): ''' Tests a name to see if it is in a delegated zone. :param list delegated_names: List of non-apex dns.name.Names in zone with NS RRSets. :param obj name: The dns.name.Name to test. :return: True if name is delegated, False otherwise. ''' for deleg_name in delegated_names: if name.is_subdomain(deleg_name): return True return False
def to_address( name: dns.name.Name, v4_origin: dns.name.Name = ipv4_reverse_domain, v6_origin: dns.name.Name = ipv6_reverse_domain, ) -> str: """Convert a reverse map domain name into textual address form. *name*, a ``dns.name.Name``, an IPv4 or IPv6 address in reverse-map name form. *v4_origin*, a ``dns.name.Name`` representing the top-level domain for IPv4 addresses, instead of the default (in-addr.arpa.) *v6_origin*, a ``dns.name.Name`` representing the top-level domain for IPv4 addresses, instead of the default (ip6.arpa.) Raises ``dns.exception.SyntaxError`` if the name does not have a reverse-map form. Returns a ``str``. """ if name.is_subdomain(v4_origin): name = name.relativize(v4_origin) text = b".".join(reversed(name.labels)) # run through inet_ntoa() to check syntax and make pretty. return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) elif name.is_subdomain(v6_origin): name = name.relativize(v6_origin) labels = list(reversed(name.labels)) parts = [] for i in range(0, len(labels), 4): parts.append(b"".join(labels[i:i + 4])) text = b":".join(parts) # run through inet_ntoa() to check syntax and make pretty. return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) else: raise dns.exception.SyntaxError("unknown reverse-map address family")
def _analyze((cls, name, dlv_domain, try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, explicit_delegations, extra_rdtypes, explicit_only, cache, cache_level, cache_lock, th_factories)): 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, 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) return a.analyze() # re-raise a KeyboardInterrupt, as this means we've been interrupted except KeyboardInterrupt: raise # report exceptions related to network connectivity except (NetworkConnectivityException, transport.RemoteQueryTransportError), e: logger.error('Error analyzing %s: %s' % (fmt.humanize_name(name), e))
def _probe( analyst_cls: Analyst, name: str, config, rdclass, ceiling, query_class_mixin, explicit_delegations, odd_ports, cache, cache_lock, tm, resolver, ): if ceiling is not None and name.is_subdomain(ceiling): c = ceiling else: c = name try: a = analyst_cls( name, rdclass=rdclass, dlv_domain=config.dlv_domain, try_ipv4=config.try_ipv4, try_ipv6=config.try_ipv6, client_ipv4=config.client_ipv4, client_ipv6=config.client_ipv6, query_class_mixin=query_class_mixin, ceiling=c, edns_diagnostics=config.edns_diagnostics, explicit_delegations=explicit_delegations, stop_at_explicit=config.stop_at_explicit, odd_ports=odd_ports, extra_rdtypes=config.rdtypes, explicit_only=config.explicit_only, analysis_cache=cache, cache_level=config.cache_level, analysis_cache_lock=cache_lock, transport_manager=tm, th_factories=config.th_factories, resolver=resolver, ) return a.analyze() # report exceptions related to network connectivity except (NetworkConnectivityException, transport.RemoteQueryTransportError) as e: logger.error("Error analyzing %s: %s" % (humanize_name(name), e)) except: logger.exception("Error analyzing %s" % humanize_name(name)) return None
def reply_from_zone(zone, query, allnames): name = query.question[0].name rtype = query.question[0].rdtype rclass = query.question[0].rdclass if not name.is_subdomain(zone.origin): return gen_refused(query) # qname is below delegation -> referral to the delegation t = name while len(t.labels) > len(zone.origin.labels): r = zone.get_rrset(t, dns.rdatatype.NS) if r: return gen_referral(zone, query, r) t = t.parent() # find exact match to qname & qtype r = zone.get_rrset(name, rtype) if r: return gen_answer(zone, query, (r, )) # try CNAME r = zone.get_rrset(name, dns.rdatatype.CNAME) if r: return gen_answer(zone, query, (r, )) # try ANY if rtype == dns.rdatatype.ANY: r = zone.get_node(name) rrsets = [] if r: rrsets = [] for rdataset in r.rdatasets: rrsets.append( dns.rrset.from_rdata_list(name, rdataset.ttl, rdataset)) return gen_answer(zone, query, rrsets) # TODO: try DNAME, wildcard,... # NODATA # 1. rrset not found for qname # (we have A record only for qname but qtype is AAAA) # 2. empty non-terminal if name in allnames: return gen_nxdomain_nodata(zone, query, nxdomain=False) # generate NXDOMAIN return gen_nxdomain_nodata(zone, query, nxdomain=True)
def _validate_name(self, name): if isinstance(name, str): name = dns.name.from_text(name, None) elif not isinstance(name, dns.name.Name): raise KeyError("name parameter must be convertible to a DNS name") if name.is_absolute(): if not name.is_subdomain(self.origin): raise KeyError( "name parameter must be a subdomain of the zone origin") if self.relativize: name = name.relativize(self.origin) elif not self.relativize: # We have a relative name in a non-relative zone, so derelativize. if self.origin is None: raise KeyError('no zone origin is defined') name = name.derelativize(self.origin) return name
def _validate_name(self, name: dns.name.Name) -> dns.name.Name: if name.is_absolute(): if self.origin is None: # This should probably never happen as other code (e.g. # _rr_line) will notice the lack of an origin before us, but # we check just in case! raise KeyError("no zone origin is defined") if not name.is_subdomain(self.origin): raise KeyError("name is not a subdomain of the zone origin") if self.zone.relativize: name = name.relativize(self.origin) elif not self.zone.relativize: # We have a relative name in a non-relative zone, so derelativize. if self.origin is None: raise KeyError("no zone origin is defined") name = name.derelativize(self.origin) return name
def add_record(self, name, rdtype, content, rdclass="IN", ttl=None): """ Add a resource record to the zone. :param name: The record's name. :type name: string :param rdtype: The record's type, e.g. "CNAME". :type rdtype: string :param content: The record's content. :type content: string :param rdclass: The record's class. :type rdclass: string :param ttl: The record's TTL. :type ttl: ttl :return: :class:`Record <Record>` object :rtype: localzone.models.Record """ # TODO: standardize on named params? # convert string parameters to dnspython objects name = dns.name.from_text(name, self.origin) rdclass = dns.rdataclass.from_text(rdclass) rdtype = dns.rdatatype.from_text(rdtype) # TODO: won't this always be the case? if name.is_subdomain(self.origin): name = name.relativize(self.origin) if not ttl: ttl = self.ttl # create the record data rdata = dns.rdata.from_text(rdclass, rdtype, content, origin=self.origin) # get or create the node and rdataset that will conatin the record node = self.find_node(name, create=True) rdataset = self.find_rdataset(name, rdtype, create=True) # add the new rdata to the set rdataset.add(rdata, ttl) return Record(self.origin, name, node, rdataset, rdata)
def _analyze((cls, name, dlv_domain, client_ipv4, client_ipv6, ceiling, edns_diagnostics, explicit_delegations, extra_rdtypes, explicit_only, cache, cache_level, cache_lock)): if ceiling is not None and name.is_subdomain(ceiling): c = ceiling else: c = name try: a = cls(name, dlv_domain=dlv_domain, client_ipv4=client_ipv4, client_ipv6=client_ipv6, ceiling=c, edns_diagnostics=edns_diagnostics, explicit_delegations=explicit_delegations, extra_rdtypes=extra_rdtypes, explicit_only=explicit_only, analysis_cache=cache, cache_level=cache_level, analysis_cache_lock=cache_lock) return a.analyze() # re-raise a KeyboardInterrupt, as this means we've been interrupted except KeyboardInterrupt: raise # don't report EOFError, as that is what is raised if there is a # KeyboardInterrupt in ParallelAnalyst except EOFError: pass except: logger.exception('Error analyzing %s' % fmt.humanize_name(name)) return None
def _analyze(args): (cls, name, dlv_domain, try_ipv4, try_ipv6, client_ipv4, client_ipv6, query_class_mixin, ceiling, edns_diagnostics, \ 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, query_class_mixin=query_class_mixin, 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: raise # report exceptions related to network connectivity except (NetworkConnectivityException, transport.RemoteQueryTransportError) as e: logger.error('Error analyzing %s: %s' % (fmt.humanize_name(name), e)) # don't report EOFError, as that is what is raised if there is a # KeyboardInterrupt in ParallelAnalyst except EOFError: pass except: logger.exception('Error analyzing %s' % fmt.humanize_name(name)) return None
def _validate_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name: if isinstance(name, str): name = dns.name.from_text(name, None) elif not isinstance(name, dns.name.Name): raise KeyError("name parameter must be convertible to a DNS name") if name.is_absolute(): if self.origin is None: # This should probably never happen as other code (e.g. # _rr_line) will notice the lack of an origin before us, but # we check just in case! raise KeyError("no zone origin is defined") if not name.is_subdomain(self.origin): raise KeyError( "name parameter must be a subdomain of the zone origin") if self.relativize: name = name.relativize(self.origin) elif not self.relativize: # We have a relative name in a non-relative zone, so derelativize. if self.origin is None: raise KeyError("no zone origin is defined") name = name.derelativize(self.origin) return name
def inside_auto_empty_zone(name): """True if specified absolute name is a subdomain of an automatic empty zone. DNS domain is a subdomain of itself so this function returns True for zone apexes, too. >>> inside_auto_empty_zone(DNSName('in-addr.arpa.')) False >>> inside_auto_empty_zone(DNSName('10.in-addr.arpa.')) True >>> inside_auto_empty_zone(DNSName('1.10.in-addr.arpa.')) True >>> inside_auto_empty_zone(DNSName('1.10.in-addr.arpa')) Traceback (most recent call last): ... AssertionError: ... """ assert_absolute_dnsname(name) for aez in EMPTY_ZONES: if name.is_subdomain(aez): return True return False
def _analyze(args): (cls, name, dlv_domain, try_ipv4, try_ipv6, client_ipv4, client_ipv6, query_class_mixin, ceiling, edns_diagnostics, \ stop_at_explicit, extra_rdtypes, explicit_only, cache, cache_level, cache_lock) = 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, query_class_mixin=query_class_mixin, 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=resolver) return a.analyze() # re-raise a KeyboardInterrupt, as this means we've been interrupted except KeyboardInterrupt: raise # report exceptions related to network connectivity except (NetworkConnectivityException, transport.RemoteQueryTransportError) as e: logger.error('Error analyzing %s: %s' % (fmt.humanize_name(name), e)) # don't report EOFError, as that is what is raised if there is a # KeyboardInterrupt in ParallelAnalyst except EOFError: pass except: logger.exception('Error analyzing %s' % fmt.humanize_name(name)) return None
def _generate_line(self): # range lhs [ttl] [class] type rhs [ comment ] """Process one line containing the GENERATE statement from a DNS master file.""" if self.current_origin is None: raise UnknownOrigin token = self.tok.get() # Range (required) try: start, stop, step = dns.grange.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except: raise dns.exception.SyntaxError # lhs (required) try: lhs = token.value token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except: raise dns.exception.SyntaxError # TTL try: ttl = dns.ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.ttl.BadTTL: ttl = self.ttl # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError except: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = dns.rdatatype.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) # lhs (required) try: rhs = token.value except: raise dns.exception.SyntaxError lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs) rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs) for i in range(start, stop + 1, step): # +1 because bind is inclusive and python is exclusive if lsign == '+': lindex = i + int(loffset) elif lsign == '-': lindex = i - int(loffset) if rsign == '-': rindex = i - int(roffset) elif rsign == '+': rindex = i + int(roffset) lzfindex = str(lindex).zfill(int(lwidth)) rzfindex = str(rindex).zfill(int(rwidth)) name = lhs.replace('$%s' % (lmod), lzfindex) rdata = rhs.replace('$%s' % (rmod), rzfindex) self.last_name = dns.name.from_text(name, self.current_origin) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = dns.rdata.from_text(rdclass, rdtype, rdata, self.current_origin, False) except dns.exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise dns.exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def _rr_line(self): """Process one line from a DNS master file.""" # Name if self.current_origin is None: raise UnknownOrigin token = self.tok.get(want_leading = True) if not token.is_whitespace(): self.last_name = dns.name.from_text(token.value, self.current_origin) else: token = self.tok.get() if token.is_eol_or_eof(): # treat leading WS followed by EOL/EOF as if they were EOL/EOF. return self.tok.unget(token) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError # TTL try: ttl = dns.ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.ttl.BadTTL: ttl = self.ttl # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError except: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = dns.rdatatype.from_text(token.value) except: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = dns.rdata.from_text(rdclass, rdtype, self.tok, self.current_origin, False) except dns.exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise dns.exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def resolve(self, name, response): assert not name.is_absolute() or name.is_subdomain(self.origin) _logger = logging.getLogger(__name__) #_logger.debug('Enter ODUPPolicyRealm.resolve(): name: %s' % (name)) # make sure name is relative to origin if name.is_absolute(): name = name.relativize(self.origin) if self.origin == dns.name.root: origin = '' else: origin = self.origin.to_text() # check for org/bound directives in names in ancestry longest_match = None longest_match_boundary = None existing_labels = 0 for i in range(len(name) + 1): if i == 0: test_domain = dns.name.empty wildcard_name = None else: test_domain = dns.name.Name(name[-i:]) wildcard_name = dns.name.from_text('*', test_domain.parent()) test_domain_qualified = dns.name.Name(test_domain.labels + ('_odup',) + self.origin.labels) policy = None # Name exists; check for policy if test_domain in self._policies: if i > 0: existing_labels += 1 if self._policies[test_domain] is not None: _logger.debug('%s/TXT: NOERROR (local): %s' % (test_domain_qualified, self._policies[test_domain])) policy = self._policies[test_domain] response.add_query(test_domain_qualified, dns.rcode.NOERROR, policy) else: # It's effectively a NODATA response _logger.debug('%s/TXT: NODATA (local)' % (test_domain_qualified)) response.add_query(test_domain_qualified, dns.rcode.NOERROR, None) pass # Name doesn't exist; check for wildcard elif wildcard_name in self._policies and self._policies[wildcard_name] is not None: _logger.debug('%s/TXT: NOERROR (wildcard local): %s' % (test_domain_qualified, self._policies[wildcard_name])) existing_labels += 1 policy = self._policies[wildcard_name] response.add_query(test_domain_qualified, dns.rcode.NOERROR, policy) # Effective NXDOMAIN: # An NXDOMAIN result means that no further lookups are # necessary, as there is no subtree else: _logger.debug('%s/TXT: NXDOMAIN (local)' % (test_domain_qualified)) response.add_query(test_domain_qualified, dns.rcode.NXDOMAIN, None) break if policy is not None: org_match = ORG_RE.search(policy) bound_match = BOUND_RE.search(policy) # Update longestMatch by giving org and bound highest # priority and ignoring policy statements below "bound". if org_match is not None or bound_match is not None or \ (longest_match is None or BOUND_RE.search(longest_match) is None): longest_match = policy longest_match_boundary = i # If this was a organizational domain designation, # then don't go any further; the organization will # dictate policy if org_match is not None: break # If this was a boundary designation, and the answer # was synthesized from a wildcard, no further # lookups must be performed if bound_match is not None and \ bound_match.group('labels') is not None and \ int(bound_match.group('labels')) < i + 1: break # Effective NODATA response else: pass if longest_match is not None: # If a policy has been found, then look for +org or +bound # directives, which will cause org names to be returned. # A +org directive indicates that the organizational domain and # policy are (at least) one level lower than the value of # longestMatchBoundary. if ORG_RE.search(longest_match) is not None: org_domain = dns.name.Name(name[-(longest_match_boundary+1):]).derelativize(self.origin) response.set_policy(None, org_domain, None) return response # A +bound directive indicates that the organizational domain # and policy are (at least) one level lower than the value of # longestExistingBoundary. if BOUND_RE.search(longest_match) is not None and \ existing_labels + 1 <= len(name): org_domain = dns.name.Name(name[-(existing_labels+1):]).derelativize(self.origin) response.set_policy(None, org_domain, None) return response # With no +org or +bound directives present, the orgDomain and # policy remain as they were looked up, and are returned with # the policy domain policy_domain = dns.name.Name(name[-(longest_match_boundary+1):]).derelativize(self.origin) response.set_policy(policy_domain, self.origin, longest_match) return response else: # Otherwise, return the policy for the orgDomain response.set_policy(None, self.origin, None) return response
def _rr_line(self): """Process one line from a DNS master file.""" # Name if self.current_origin is None: raise UnknownOrigin token = self.tok.get(want_leading=True) if not token.is_whitespace(): self.last_name = dns.name.from_text(token.value, self.current_origin) else: token = self.tok.get() if token.is_eol_or_eof(): # treat leading WS followed by EOL/EOF as if they were EOL/EOF. return self.tok.unget(token) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError # TTL try: ttl = dns.ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.ttl.BadTTL: ttl = self.ttl # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError except: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = dns.rdatatype.from_text(token.value) except: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = dns.rdata.from_text(rdclass, rdtype, self.tok, self.current_origin, False) except dns.exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise dns.exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def _generate_line(self): # range lhs [ttl] [class] type rhs [ comment ] """Process one line containing the GENERATE statement from a DNS master file.""" if self.current_origin is None: raise UnknownOrigin token = self.tok.get() # Range (required) try: start, stop, step = dns.grange.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except: raise dns.exception.SyntaxError # lhs (required) try: lhs = token.value token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except: raise dns.exception.SyntaxError # TTL try: ttl = dns.ttl.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.ttl.BadTTL: ttl = self.ttl # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError except: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = dns.rdatatype.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) # lhs (required) try: rhs = token.value except: raise dns.exception.SyntaxError lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs) rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs) for i in range(start, stop + 1, step): # +1 because bind is inclusive and python is exclusive if lsign == u'+': lindex = i + int(loffset) elif lsign == u'-': lindex = i - int(loffset) if rsign == u'-': rindex = i - int(roffset) elif rsign == u'+': rindex = i + int(roffset) lzfindex = str(lindex).zfill(int(lwidth)) rzfindex = str(rindex).zfill(int(rwidth)) name = lhs.replace(u'$%s' % (lmod), lzfindex) rdata = rhs.replace(u'$%s' % (rmod), rzfindex) self.last_name = dns.name.from_text(name, self.current_origin) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = dns.rdata.from_text(rdclass, rdtype, rdata, self.current_origin, False) except dns.exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise dns.exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) rd.choose_relativity(self.zone.origin, self.relativize) covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def _get(self, request, name_obj, timestamp, url_subdir, date_form): options_form, values = get_dnssec_options_form_data({}) trusted_keys_explicit = values['tk'] trusted_zones = values['ta'] trusted_keys = trusted_keys_explicit + trusted_zones name_obj.retrieve_all() name_obj.populate_status(trusted_keys) zone_obj = name_obj.zone delegation_matrix = [] def stealth_cmp(x, y): return cmp((y[0], x[1], x[2]), (x[0], y[1], y[2])) all_names_list = list(zone_obj.get_ns_names()) if not all_names_list: all_names_list = list(zone_obj.get_auth_ns_ip_mapping()) all_names_list.sort() if zone_obj.parent is not None and not zone_obj.get_auth_or_designated_servers( ).difference(zone_obj.parent.get_auth_or_designated_servers()): no_non_auth_parent_msg = 'All %s servers are also authoritative for %s' % ( fmt.humanize_name( zone_obj.parent_name()), fmt.humanize_name(zone_obj.name)) else: no_non_auth_parent_msg = None #XXX need something equivalent here for lack of authoritative response for NS show_msg = False ips_from_child = zone_obj.get_servers_in_child() ips_from_parent = zone_obj.get_servers_in_parent() for name in all_names_list: if zone_obj.parent is not None: in_bailiwick = name.is_subdomain(zone_obj.parent_name()) glue_required = name.is_subdomain(zone_obj.name) else: in_bailiwick = None glue_required = None parent_status = { 'in_bailiwick': in_bailiwick, 'glue_required': glue_required } row = [] row.append(fmt.humanize_name(name)) # (t/f in parent), (glue IPs (or error, if missing)), (real IPs) if zone_obj.get_ns_names_in_parent(): glue_mapping = zone_obj.get_glue_ip_mapping() parent_status['in_parent'] = name in glue_mapping glue_ips_v4 = filter(lambda x: x.version == 4, glue_mapping.get(name, set())) glue_ips_v4.sort() glue_ips_v6 = filter(lambda x: x.version == 6, glue_mapping.get(name, set())) glue_ips_v6.sort() else: glue_ips_v4 = [] glue_ips_v6 = [] if zone_obj.delegation_status == Status.DELEGATION_STATUS_INCOMPLETE: parent_status['in_parent'] = False else: parent_status['in_parent'] = None show_msg = True row.append({ 'parent_status': parent_status, 'glue_ips_v4': glue_ips_v4, 'glue_ips_v6': glue_ips_v6 }) # (t/f in parent), (glue IPs (or error, if missing)), (real IPs) names_in_child = zone_obj.get_ns_names_in_child() if names_in_child: in_child = name in zone_obj.get_ns_names_in_child() #XXX #elif zone_obj.get_servers_authoritative_for_query(zone_obj.name, dns.rdatatype.NS): # in_child = None else: in_child = False auth_mapping = zone_obj.get_auth_ns_ip_mapping() auth_ips_v4 = filter(lambda x: x.version == 4, auth_mapping.get(name, set())) auth_ips_v4.sort() auth_ips_v6 = filter(lambda x: x.version == 6, auth_mapping.get(name, set())) auth_ips_v6.sort() row.append({ 'in_child': in_child, 'auth_ips_v4': auth_ips_v4, 'auth_ips_v6': auth_ips_v6 }) delegation_matrix.append(row) stealth_matrix = [] stealth_rows = [] for server in zone_obj.get_stealth_servers(): names, ancestor_zone = zone_obj.get_ns_name_for_ip(server) stealth_rows.append((ancestor_zone, names, server)) stealth_rows.sort(cmp=stealth_cmp) for ancestor_zone, names, server in stealth_rows: names = map(fmt.humanize_name, names) if ancestor_zone is not None: ancestor_zone = fmt.humanize_name(ancestor_zone) row = (names, ancestor_zone, server) stealth_matrix.append(row) return render_to_response('servers.html', { 'name_obj': name_obj, 'timestamp': timestamp, 'url_subdir': url_subdir, 'title': name_obj, 'date_form': date_form, 'zone_obj': zone_obj, 'delegation': delegation_matrix, 'stealth': stealth_matrix, 'no_non_auth_parent_msg': no_non_auth_parent_msg, 'show_msg': show_msg, 'ips_from_parent': ips_from_parent, 'ips_from_child': ips_from_child }, context_instance=RequestContext(request))
def _rr_line(self): """Process one line from a DNS master file.""" # Name if self.current_origin is None: raise UnknownOrigin token = self.tok.get(want_leading=True) if not token.is_whitespace(): self.last_name = self.tok.as_name(token, self.current_origin) else: token = self.tok.get() if token.is_eol_or_eof(): # treat leading WS followed by EOL/EOF as if they were EOL/EOF. return self.tok.unget(token) name = self.last_name if not name.is_subdomain(self.zone.origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone.origin) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError # TTL ttl = None try: ttl = dns.ttl.from_text(token.value) self.last_ttl = ttl self.last_ttl_known = True token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.ttl.BadTTL: if self.default_ttl_known: ttl = self.default_ttl elif self.last_ttl_known: ttl = self.last_ttl # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError except Exception: rdclass = self.zone.rdclass if rdclass != self.zone.rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = dns.rdatatype.from_text(token.value) except: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) n = self.zone.nodes.get(name) if n is None: n = self.zone.node_factory() self.zone.nodes[name] = n try: rd = dns.rdata.from_text(rdclass, rdtype, self.tok, self.current_origin, self.relativize, self.zone.origin) except dns.exception.SyntaxError: # Catch and reraise. (ty, va) = sys.exc_info()[:2] raise va except: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise dns.exception.SyntaxError("caught exception {}: {}".format( str(ty), str(va))) if not self.default_ttl_known and isinstance(rd, dns.rdtypes.ANY.SOA.SOA): # The pre-RFC2308 and pre-BIND9 behavior inherits the zone default # TTL from the SOA minttl if no $TTL statement is present before the # SOA is parsed. self.default_ttl = rd.minimum self.default_ttl_known = True # TTL check if ttl is None: if not (self.last_ttl_known or self.default_ttl_known): raise dns.exception.SyntaxError("Missing default TTL value") else: if self.default_ttl_known: ttl = self.default_ttl else: ttl = self.last_ttl covers = rd.covers() rds = n.find_rdataset(rdclass, rdtype, covers, True) rds.add(rd, ttl)
def _generate_line(self): # range lhs [ttl] [class] type rhs [ comment ] """Process one line containing the GENERATE statement from a DNS zone file.""" if self.current_origin is None: raise UnknownOrigin token = self.tok.get() # Range (required) try: start, stop, step = dns.grange.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except Exception: raise dns.exception.SyntaxError # lhs (required) try: lhs = token.value token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except Exception: raise dns.exception.SyntaxError # TTL try: ttl = dns.ttl.from_text(token.value) self.last_ttl = ttl self.last_ttl_known = True token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.ttl.BadTTL: if not (self.last_ttl_known or self.default_ttl_known): raise dns.exception.SyntaxError("Missing default TTL value") if self.default_ttl_known: ttl = self.default_ttl elif self.last_ttl_known: ttl = self.last_ttl # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise dns.exception.SyntaxError except Exception: rdclass = self.zone_rdclass if rdclass != self.zone_rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = dns.rdatatype.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except Exception: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) # rhs (required) rhs = token.value # The code currently only supports base 'd', so the last value # in the tuple _parse_modify returns is ignored lmod, lsign, loffset, lwidth, _ = self._parse_modify(lhs) rmod, rsign, roffset, rwidth, _ = self._parse_modify(rhs) for i in range(start, stop + 1, step): # +1 because bind is inclusive and python is exclusive if lsign == '+': lindex = i + int(loffset) elif lsign == '-': lindex = i - int(loffset) if rsign == '-': rindex = i - int(roffset) elif rsign == '+': rindex = i + int(roffset) lzfindex = str(lindex).zfill(int(lwidth)) rzfindex = str(rindex).zfill(int(rwidth)) name = lhs.replace('$%s' % (lmod), lzfindex) rdata = rhs.replace('$%s' % (rmod), rzfindex) self.last_name = dns.name.from_text(name, self.current_origin, self.tok.idna_codec) name = self.last_name if not name.is_subdomain(self.zone_origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone_origin) try: rd = dns.rdata.from_text(rdclass, rdtype, rdata, self.current_origin, self.relativize, self.zone_origin) except dns.exception.SyntaxError: # Catch and reraise. raise except Exception: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise dns.exception.SyntaxError("caught exception %s: %s" % (str(ty), str(va))) self.txn.add(name, ttl, rd)
def _rr_line(self): """Process one line from a DNS zone file.""" # Name if self.current_origin is None: raise UnknownOrigin token = self.tok.get(want_leading=True) if not token.is_whitespace(): self.last_name = self.tok.as_name(token, self.current_origin) else: token = self.tok.get() if token.is_eol_or_eof(): # treat leading WS followed by EOL/EOF as if they were EOL/EOF. return self.tok.unget(token) name = self.last_name if not name.is_subdomain(self.zone_origin): self._eat_line() return if self.relativize: name = name.relativize(self.zone_origin) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError # TTL ttl = None try: ttl = dns.ttl.from_text(token.value) self.last_ttl = ttl self.last_ttl_known = True token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.ttl.BadTTL: if self.default_ttl_known: ttl = self.default_ttl elif self.last_ttl_known: ttl = self.last_ttl # Class try: rdclass = dns.rdataclass.from_text(token.value) token = self.tok.get() if not token.is_identifier(): raise dns.exception.SyntaxError except dns.exception.SyntaxError: raise except Exception: rdclass = self.zone_rdclass if rdclass != self.zone_rdclass: raise dns.exception.SyntaxError("RR class is not zone's class") # Type try: rdtype = dns.rdatatype.from_text(token.value) except Exception: raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value) try: rd = dns.rdata.from_text(rdclass, rdtype, self.tok, self.current_origin, self.relativize, self.zone_origin) except dns.exception.SyntaxError: # Catch and reraise. raise except Exception: # All exceptions that occur in the processing of rdata # are treated as syntax errors. This is not strictly # correct, but it is correct almost all of the time. # We convert them to syntax errors so that we can emit # helpful filename:line info. (ty, va) = sys.exc_info()[:2] raise dns.exception.SyntaxError("caught exception {}: {}".format( str(ty), str(va))) if not self.default_ttl_known and rdtype == dns.rdatatype.SOA: # The pre-RFC2308 and pre-BIND9 behavior inherits the zone default # TTL from the SOA minttl if no $TTL statement is present before the # SOA is parsed. self.default_ttl = rd.minimum self.default_ttl_known = True if ttl is None: # if we didn't have a TTL on the SOA, set it! ttl = rd.minimum # TTL check. We had to wait until now to do this as the SOA RR's # own TTL can be inferred from its minimum. if ttl is None: raise dns.exception.SyntaxError("Missing default TTL value") self.txn.add(name, ttl, rd)
def closest_zone(self, name): """find closest enclosing zone object in Cache""" for z in reversed(sorted(self.ZoneDict.keys())): if name.is_subdomain(z): return self.get_zone(z) return None