def humanize_name(name, idn=False): if idn: try: name = name.canonicalize().to_unicode() except UnicodeError: name = name.canonicalize().to_text() else: name = name.canonicalize().to_text() if name == '.': return name return name.rstrip('.')
def humanize_name(name, idn=False): if idn: try: name = name.canonicalize().to_unicode() except UnicodeError: name = lb2s(name.canonicalize().to_text()) else: name = lb2s(name.canonicalize().to_text()) if name == '.': return name return name.rstrip('.')
def make_ds(name, key, algorithm, origin=None): """Create a DS record for a DNSSEC key. *name* is the owner name of the DS record. *key* is a ``dns.rdtypes.ANY.DNSKEY``. *algorithm* is a string describing which hash algorithm to use. The currently supported hashes are "SHA1" and "SHA256". Case does not matter for these strings. *origin* is a ``dns.name.Name`` and will be used as the origin if *key* is a relative name. Returns a ``dns.rdtypes.ANY.DS``. """ if algorithm.upper() == 'SHA1': dsalg = 1 hash = dns.hash.hashes['SHA1']() elif algorithm.upper() == 'SHA256': dsalg = 2 hash = dns.hash.hashes['SHA256']() else: raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) if isinstance(name, string_types): name = dns.name.from_text(name, origin) hash.update(name.canonicalize().to_wire()) hash.update(_to_rdata(key, origin)) digest = hash.digest() dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata))
def make_ds(name, key, algorithm, origin=None): """Create a DS record for a DNSSEC key. :param name: Owner name of the DS record :type name: string :param key: a DNSKEY :type key: :py:data:`dns.rdtypes.ANY.DNSKEY` :param algorithm: a string describing which hash algorithm to use.The currently supported hashes are "SHA1" and "SHA256". Case does not matter for these strings. :type algorithm: string :param origin: Will be used as origin if `key` is a relative name, defaults to None :type origin: :py:data:`dns.name.Name`, optional :raises UnsupportedAlgorithm: If the algorithm is not either "SHA1" or "SHA256" exception will be thrown :return: a DS record :rtype: :py:data:`dns.rdtypes.ANY.DS` """ if algorithm.upper() == 'SHA1': dsalg = 1 dshash = hashlib.sha1() elif algorithm.upper() == 'SHA256': dsalg = 2 dshash = hashlib.sha256() else: raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) if isinstance(name, str): name = dns.name.from_text(name, origin) dshash.update(name.canonicalize().to_wire()) dshash.update(_to_rdata(key, origin)) digest = dshash.digest() dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata))
def make_ds(name, key, algorithm, origin=None): """Create a DS record for a DNSSEC key. *name* is the owner name of the DS record. *key* is a ``dns.rdtypes.ANY.DNSKEY``. *algorithm* is a string describing which hash algorithm to use. The currently supported hashes are "SHA1" and "SHA256". Case does not matter for these strings. *origin* is a ``dns.name.Name`` and will be used as the origin if *key* is a relative name. Returns a ``dns.rdtypes.ANY.DS``. """ if algorithm.upper() == 'SHA1': dsalg = 1 hash = SHA1.new() elif algorithm.upper() == 'SHA256': dsalg = 2 hash = SHA256.new() else: raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) if isinstance(name, str): name = dns.name.from_text(name, origin) hash.update(name.canonicalize().to_wire()) hash.update(_to_rdata(key, origin)) digest = hash.digest() dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata))
def get_prep_value(self, value): if value is None: return None if isinstance(value, dns.name.Name): name = value else: name = dns.name.from_text(value) if self.canonicalize: name = name.canonicalize() return name.to_text()
def make_ds( name: Union[dns.name.Name, str], key: dns.rdata.Rdata, algorithm: Union[DSDigest, str], origin: Optional[dns.name.Name] = None, ) -> DS: """Create a DS record for a DNSSEC key. *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record. *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY``, the key the DS is about. *algorithm*, a ``str`` or ``int`` specifying the hash algorithm. The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case does not matter for these strings. *origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name, then it will be made absolute using the specified origin. Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. Returns a ``dns.rdtypes.ANY.DS.DS`` """ try: if isinstance(algorithm, str): algorithm = DSDigest[algorithm.upper()] except Exception: raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) if not isinstance(key, DNSKEY): raise ValueError("key is not a DNSKEY") if algorithm == DSDigest.SHA1: dshash = hashlib.sha1() elif algorithm == DSDigest.SHA256: dshash = hashlib.sha256() elif algorithm == DSDigest.SHA384: dshash = hashlib.sha384() else: raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) if isinstance(name, str): name = dns.name.from_text(name, origin) wire = name.canonicalize().to_wire() assert wire is not None dshash.update(wire) dshash.update(key.to_wire(origin=origin)) digest = dshash.digest() dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, algorithm) + digest ds = dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata)) return cast(DS, ds)
def nsec3_covers_name(nsec_rrset, name, zonename): """ Does NSEC3 RR cover the given name? """ name = name.canonicalize() n1 = nsec_rrset.name.canonicalize() n2_hash = base64.b32encode(nsec_rrset[0].next) n2_hash = n2_hash.translate(b32_to_ext_hex).decode() n2 = dns.name.Name((n2_hash, ) + zonename.labels) n2 = n2.canonicalize() if (name.fullcompare(n1)[1] > 0) and (name.fullcompare(n2)[1] < 0): return True return False
def make_ds(name, key, algorithm, origin=None): if algorithm.upper() == 'SHA1': dsalg = 1 hash = dns.hash.get('SHA1')() elif algorithm.upper() == 'SHA256': dsalg = 2 hash = dns.hash.get('SHA256')() else: raise UnsupportedAlgorithm, 'unsupported algorithm "%s"' % algorithm if isinstance(name, (str, unicode)): name = dns.name.from_text(name, origin) hash.update(name.canonicalize().to_wire()) hash.update(_to_rdata(key, origin)) digest = hash.digest() dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata))
def make_ds(name, key, algorithm, origin=None): """Create a DS record for a DNSSEC key. *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record. *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY``, the key the DS is about. *algorithm*, a ``str`` specifying the hash algorithm. The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case does not matter for these strings. *origin*, a ``dns.name.Name`` or ``None``, if `key` is a relative name, then it will be made absolute using the specified origin. Raises ``UnsupportedAlgorithm`` if the algorithm is unknown. Returns a ``dns.rdtypes.ANY.DS.DS`` """ if algorithm.upper() == "SHA1": dsalg = 1 dshash = hashlib.sha1() elif algorithm.upper() == "SHA256": dsalg = 2 dshash = hashlib.sha256() elif algorithm.upper() == "SHA384": dsalg = 4 dshash = hashlib.sha384() else: raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm) if isinstance(name, str): name = dns.name.from_text(name, origin) dshash.update(name.canonicalize().to_wire()) dshash.update(_to_rdata(key, origin)) digest = dshash.digest() dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, dsalg) + digest return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata))
class DomainNameField(models.CharField): description = _("Domain name (with maximum length of %(max_length)s characters)") def __init__(self, *args, **kwargs): self.canonicalize = kwargs.pop('canonicalize', True) super(DomainNameField, self).__init__(*args, **kwargs) def from_db_value(self, value, expression, connection, context): return self.to_python(value) def to_python(self, value): if value is None: return None if isinstance(value, dns.name.Name): name = value else: try: name = dns.name.from_text(value) except Exception, e: raise ValidationError('%s: %s is of type %s' % (e, value, type(value))) if self.canonicalize: name = name.canonicalize() return name
def main(argv): try: arghelper = GrokArgHelper(logger) arghelper.build_parser('%s %s' % (sys.argv[0], argv[0]), argv[1:]) logger.setLevel(logging.WARNING) try: arghelper.check_args() arghelper.set_kwargs() arghelper.set_buffers() arghelper.aggregate_trusted_key_info() arghelper.ingest_input() arghelper.ingest_names() except argparse.ArgumentTypeError as e: arghelper.parser.error(str(e)) except AnalysisInputError as e: s = str(e) if s: logger.error(s) sys.exit(3) if arghelper.args.minimize_output: kwargs = {} else: kwargs = {'indent': 4, 'separators': (',', ': ')} # if trusted keys were supplied, check that pygraphviz is installed if arghelper.trusted_keys: test_pygraphviz() name_objs = [] cache = {} for name in arghelper.names: name_str = lb2s(name.canonicalize().to_text()) if name_str not in arghelper.analysis_structured or arghelper.analysis_structured[ name_str].get('stub', True): logger.error( 'The analysis of "%s" was not found in the input.' % lb2s(name.to_text())) continue name_obj = OfflineDomainNameAnalysis.deserialize( name, arghelper.analysis_structured, cache, strict_cookies=arghelper.args.enforce_cookies, allow_private=arghelper.args.allow_private) name_objs.append(name_obj) if not name_objs: sys.exit(4) arghelper.update_trusted_key_info() d = OrderedDict() for name_obj in name_objs: name_obj.populate_status( arghelper.trusted_keys, supported_algs=arghelper.args.algorithms, supported_digest_algs=arghelper.args.digest_algorithms) if arghelper.trusted_keys: G = DNSAuthGraph() for qname, rdtype in name_obj.queries: if name_obj.is_zone() and rdtype in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV): continue G.graph_rrset_auth(name_obj, qname, rdtype) for target, mx_obj in name_obj.mx_targets.items(): if mx_obj is not None: G.graph_rrset_auth(mx_obj, target, dns.rdatatype.A) G.graph_rrset_auth(mx_obj, target, dns.rdatatype.AAAA) for target, ns_obj in name_obj.ns_dependencies.items(): if ns_obj is not None: G.graph_rrset_auth(ns_obj, target, dns.rdatatype.A) G.graph_rrset_auth(ns_obj, target, dns.rdatatype.AAAA) G.add_trust(arghelper.trusted_keys, supported_algs=arghelper.args.algorithms) name_obj.populate_response_component_status(G) name_obj.serialize_status(d, loglevel=arghelper.log_level) if d: s = json.dumps(d, ensure_ascii=False, **kwargs) if not arghelper.args.minimize_output and arghelper.args.output_file.isatty( ) and os.environ.get('TERM', 'dumb') != 'dumb': s = color_json(s) arghelper.args.output_file.write(s.encode('utf-8')) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4)
def main(argv): try: test_m2crypto() #TODO remove -p option (it is now the default, and -c is used to change it) try: opts, args = getopt.getopt(argv[1:], 'f:r:t:o:cpl:h') except getopt.GetoptError as e: usage(str(e)) sys.exit(1) # collect trusted keys trusted_keys = [] for opt, arg in opts: if opt == '-t': try: tk_str = io.open(arg, 'r', encoding='utf-8').read() except IOError as e: sys.stderr.write('%s: "%s"\n' % (e.strerror, arg)) sys.exit(3) try: trusted_keys.extend(get_trusted_keys(tk_str)) except dns.exception.DNSException: sys.stderr.write('There was an error parsing the trusted keys file: "%s"\n' % arg) sys.exit(3) opts = dict(opts) if '-h' in opts: usage() sys.exit(0) if '-f' in opts and args: usage('If -f is used, then domain names may not supplied as command line arguments.') sys.exit(1) if '-l' in opts: if opts['-l'] == 'error': loglevel = logging.ERROR elif opts['-l'] == 'warning': loglevel = logging.WARNING elif opts['-l'] == 'info': loglevel = logging.INFO elif opts['-l'] == 'debug': loglevel = logging.DEBUG else: usage('Invalid log level: "%s"' % opts['-l']) sys.exit(1) else: loglevel = logging.DEBUG handler = logging.StreamHandler() handler.setLevel(logging.WARNING) logger.addHandler(handler) logger.setLevel(logging.WARNING) if '-r' not in opts or opts['-r'] == '-': opt_r = sys.stdin.fileno() else: opt_r = opts['-r'] try: analysis_str = io.open(opt_r, 'r', encoding='utf-8').read() except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts.get('-r', '-'))) sys.exit(3) try: analysis_structured = json.loads(analysis_str) except ValueError: logger.error('There was an error parsing the json input: "%s"' % opts.get('-r', '-')) sys.exit(3) # check version if '_meta._dnsviz.' not in analysis_structured or 'version' not in analysis_structured['_meta._dnsviz.']: logger.error('No version information in JSON input.') sys.exit(3) try: major_vers, minor_vers = [int(x) for x in str(analysis_structured['_meta._dnsviz.']['version']).split('.', 1)] except ValueError: logger.error('Version of JSON input is invalid: %s' % analysis_structured['_meta._dnsviz.']['version']) sys.exit(3) # ensure major version is a match and minor version is no greater # than the current minor version curr_major_vers, curr_minor_vers = [int(x) for x in str(DNS_RAW_VERSION).split('.', 1)] if major_vers != curr_major_vers or minor_vers > curr_minor_vers: logger.error('Version %d.%d of JSON input is incompatible with this software.' % (major_vers, minor_vers)) sys.exit(3) names = [] if '-f' in opts: if opts['-f'] == '-': opts['-f'] = sys.stdin.fileno() try: f = io.open(opts['-f'], 'r', encoding='utf-8') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-f'])) sys.exit(3) for line in f: name = line.strip() try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) f.close() else: if args: # python3/python2 dual compatibility if isinstance(args[0], bytes): args = [codecs.decode(x, sys.getfilesystemencoding()) for x in args] else: try: args = analysis_structured['_meta._dnsviz.']['names'] except KeyError: logger.error('No names found in json input!') sys.exit(3) for name in args: try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) if '-o' not in opts or opts['-o'] == '-': opts['-o'] = sys.stdout.fileno() try: fh = io.open(opts['-o'], 'wb') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-o'])) sys.exit(3) if '-c' not in opts: kwargs = { 'indent': 4, 'separators': (',', ': ') } else: kwargs = {} # if trusted keys were supplied, check that pygraphviz is installed if trusted_keys: test_pygraphviz() name_objs = [] cache = {} for name in names: name_str = lb2s(name.canonicalize().to_text()) if name_str not in analysis_structured or analysis_structured[name_str].get('stub', True): logger.error('The analysis of "%s" was not found in the input.' % lb2s(name.to_text())) continue name_objs.append(OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) if not name_objs: sys.exit(4) d = OrderedDict() for name_obj in name_objs: name_obj.populate_status(trusted_keys) if trusted_keys: G = DNSAuthGraph() for qname, rdtype in name_obj.queries: if name_obj.is_zone() and rdtype in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV): continue G.graph_rrset_auth(name_obj, qname, rdtype) for target, mx_obj in name_obj.mx_targets.items(): if mx_obj is not None: G.graph_rrset_auth(mx_obj, target, dns.rdatatype.A) G.graph_rrset_auth(mx_obj, target, dns.rdatatype.AAAA) for target, ns_obj in name_obj.ns_dependencies.items(): if ns_obj is not None: G.graph_rrset_auth(ns_obj, target, dns.rdatatype.A) G.graph_rrset_auth(ns_obj, target, dns.rdatatype.AAAA) G.add_trust(trusted_keys) name_obj.populate_response_component_status(G) name_obj.serialize_status(d, loglevel=loglevel) if d: s = json.dumps(d, ensure_ascii=False, **kwargs) if '-c' not in opts and fh.isatty() and os.environ.get('TERM', 'dumb') != 'dumb': s = color_json(s) fh.write(s.encode('utf-8')) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4)
def main(argv): try: test_m2crypto() test_pygraphviz() try: opts, args = getopt.getopt(argv[1:], 'f:r:R:t:Oo:h') except getopt.GetoptError as e: usage(str(e)) sys.exit(1) # collect trusted keys trusted_keys = [] for opt, arg in opts: if opt == '-t': try: tk_str = io.open(arg, 'r', encoding='utf-8').read() except IOError as e: sys.stderr.write('%s: "%s"\n' % (e.strerror, arg)) sys.exit(3) try: trusted_keys.extend(get_trusted_keys(tk_str)) except dns.exception.DNSException: sys.stderr.write( 'There was an error parsing the trusted keys file: "%s"\n' % arg) sys.exit(3) opts = dict(opts) if '-h' in opts: usage() sys.exit(0) if '-f' in opts and args: usage( 'If -f is used, then domain names may not supplied as command line arguments.' ) sys.exit(1) if '-R' in opts: try: rdtypes = opts['-R'].split(',') except ValueError: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) try: rdtypes = [dns.rdatatype.from_text(x) for x in rdtypes] except dns.rdatatype.UnknownRdatatype: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) else: rdtypes = None if '-o' in opts and '-O' in opts: usage('The -o and -O options may not be used together.') sys.exit(1) handler = logging.StreamHandler() handler.setLevel(logging.WARNING) logger.addHandler(handler) logger.setLevel(logging.WARNING) if '-r' not in opts or opts['-r'] == '-': opt_r = sys.stdin.fileno() else: opt_r = opts['-r'] try: analysis_str = io.open(opt_r, 'r', encoding='utf-8').read() except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts.get('-r', '-'))) sys.exit(3) try: analysis_structured = json.loads(analysis_str) except ValueError: logger.error('There was an error parsing the json input: "%s"' % opts.get('-r', '-')) sys.exit(3) # check version if '_meta._dnsviz.' not in analysis_structured or 'version' not in analysis_structured[ '_meta._dnsviz.']: logger.error('No version information in JSON input.') sys.exit(3) try: major_vers, minor_vers = [ int(x) for x in str(analysis_structured['_meta._dnsviz.'] ['version']).split('.', 1) ] except ValueError: logger.error('Version of JSON input is invalid: %s' % analysis_structured['_meta._dnsviz.']['version']) sys.exit(3) # ensure major version is a match and minor version is no greater # than the current minor version curr_major_vers, curr_minor_vers = [ int(x) for x in str(DNS_RAW_VERSION).split('.', 1) ] if major_vers != curr_major_vers or minor_vers > curr_minor_vers: logger.error( 'Version %d.%d of JSON input is incompatible with this software.' % (major_vers, minor_vers)) sys.exit(3) names = [] if '-f' in opts: if opts['-f'] == '-': opts['-f'] = sys.stdin.fileno() try: f = io.open(opts['-f'], 'r', encoding='utf-8') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-f'])) sys.exit(3) for line in f: name = line.strip() try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) f.close() else: if args: # python3/python2 dual compatibility if isinstance(args[0], bytes): args = [ codecs.decode(x, sys.getfilesystemencoding()) for x in args ] else: try: args = analysis_structured['_meta._dnsviz.']['names'] except KeyError: logger.error('No names found in json input!') sys.exit(3) for name in args: try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) if '-t' not in opts: try: tk_str = io.open(TRUSTED_KEYS_ROOT, 'r', encoding='utf-8').read() except IOError as e: logger.error('Error reading trusted keys file "%s": %s' % (TRUSTED_KEYS_ROOT, e.strerror)) sys.exit(3) try: trusted_keys.extend(get_trusted_keys(tk_str)) except dns.exception.DNSException: logger.error( 'There was an error parsing the trusted keys file: "%s"' % arg) sys.exit(3) name_objs = [] cache = {} for name in names: name_str = lb2s(name.canonicalize().to_text()) if name_str not in analysis_structured or analysis_structured[ name_str].get('stub', True): logger.error( 'The analysis of "%s" was not found in the input.' % lb2s(name.to_text())) continue name_objs.append( TTLAgnosticOfflineDomainNameAnalysis.deserialize( name, analysis_structured, cache)) if not name_objs: sys.exit(4) G = DNSAuthGraph() for name_obj in name_objs: name_obj.populate_status(trusted_keys) for qname, rdtype in name_obj.queries: if rdtypes is None: # if rdtypes was not specified, then graph all, with some # exceptions if name_obj.is_zone() and rdtype in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV): continue else: # if rdtypes was specified, then only graph rdtypes that # were specified if qname != name_obj.name or rdtype not in rdtypes: continue G.graph_rrset_auth(name_obj, qname, rdtype) if rdtypes is not None: for rdtype in rdtypes: if (name_obj.name, rdtype) not in name_obj.queries: logger.error( 'No query for "%s/%s" was included in the analysis.' % (lb2s(name_obj.name.to_text()), dns.rdatatype.to_text(rdtype))) if '-O' in opts: if name_obj.name == dns.name.root: name = 'root' else: name = lb2s( name_obj.name.canonicalize().to_text()).rstrip('.') finish_graph(G, [name_obj], rdtypes, trusted_keys, '%s.txt' % name) G = DNSAuthGraph() if '-O' not in opts: if '-o' not in opts or opts['-o'] == '-': finish_graph(G, name_objs, rdtypes, trusted_keys, None) else: finish_graph(G, name_objs, rdtypes, trusted_keys, opts['-o']) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4)
tk_str = open(opts['-t']).read() except IOError, e: logger.error('%s: "%s"' % (e.strerror, opts['-t'])) sys.exit(3) try: trusted_keys = get_trusted_keys(tk_str) except dns.exception.DNSException: logger.error('There was an error parsing the trusted keys file: "%s"' % opts['-t']) sys.exit(3) else: trusted_keys = () name_objs = [] cache = {} for name in names: name_str = name.canonicalize().to_text() if name_str not in analysis_structured or analysis_structured[name_str].get('stub', True): logger.error('The analysis of "%s" was not found in the input.' % name.to_text()) continue name_objs.append(OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) if not name_objs: sys.exit(4) G = DNSAuthGraph() for name_obj in name_objs: name_obj.populate_status(trusted_keys) for qname, rdtype in name_obj.queries: if rdtypes is None: # if rdtypes was not specified, then graph all, with some # exceptions
def print_result(analysis_structured): latest_analysis_date = None name_objs = [] cache = {} names = OrderedDict() strict_cookies = False allow_private = False supported_digest_algs = None supported_algs = None rdtypes = None args = analysis_structured['_meta._dnsviz.']['names'] for name in args: try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: if name not in names: names[name] = None for name in names: name_str = lb2s(name.canonicalize().to_text()) print('* %s' % name_str) if name_str not in analysis_structured or analysis_structured[name_str].get('stub', True): logger.error('The analysis of "%s" was not found in the input.' % lb2s(name.to_text())) continue name_obj = TTLAgnosticOfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache, strict_cookies=strict_cookies, allow_private=allow_private) name_objs.append(name_obj) if latest_analysis_date is None or latest_analysis_date > name_obj.analysis_end: latest_analysis_date = name_obj.analysis_end if latest_analysis_date is None: logger.error('The analysis of "%s" doesn\'t include at least one analysis.' % lb2s(name.to_text())) print(names) return trusted_keys = get_default_trusted_keys(latest_analysis_date) G = DNSAuthGraph() for name_obj in name_objs: name_obj.populate_status(trusted_keys, supported_algs=supported_algs, supported_digest_algs=supported_digest_algs) for qname, rdtype in name_obj.queries: if rdtypes is None: # if rdtypes was not specified, then graph all, with some # exceptions if name_obj.is_zone() and rdtype in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV): continue else: # if rdtypes was specified, then only graph rdtypes that # were specified if qname != name_obj.name or rdtype not in rdtypes: continue G.graph_rrset_auth(name_obj, qname, rdtype) if rdtypes is not None: for rdtype in rdtypes: if (name_obj.name, rdtype) not in name_obj.queries: logger.error('No query for "%s/%s" was included in the analysis.' % (lb2s(name_obj.name.to_text()), dns.rdatatype.to_text(rdtype))) finish_graph(G, name_objs, rdtypes, trusted_keys, supported_algs, None)
except IOError, e: logger.error('Error reading trusted keys file "%s": %s' % (TRUSTED_KEYS_ROOT, e.strerror)) sys.exit(3) try: trusted_keys.extend(get_trusted_keys(tk_str)) except dns.exception.DNSException: logger.error( 'There was an error parsing the trusted keys file: "%s"' % arg) sys.exit(3) name_objs = [] cache = {} for name in names: name_str = name.canonicalize().to_text() if name_str not in analysis_structured or analysis_structured[ name_str].get('stub', True): logger.error( 'The analysis of "%s" was not found in the input.' % name.to_text()) continue name_objs.append( OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) if not name_objs: sys.exit(4) G = DNSAuthGraph()
def uuid_for_name(name): return uuid.uuid5(uuid.NAMESPACE_DNS, name.canonicalize().to_text())
def main(argv): try: test_m2crypto() test_pygraphviz() try: opts, args = getopt.getopt(argv[1:], 'f:r:R:t:Oo:T:h') except getopt.GetoptError as e: usage(str(e)) sys.exit(1) # collect trusted keys trusted_keys = [] for opt, arg in opts: if opt == '-t': try: tk_str = io.open(arg, 'r', encoding='utf-8').read() except IOError as e: sys.stderr.write('%s: "%s"\n' % (e.strerror, arg)) sys.exit(3) try: trusted_keys.extend(get_trusted_keys(tk_str)) except dns.exception.DNSException: sys.stderr.write('There was an error parsing the trusted keys file: "%s"\n' % arg) sys.exit(3) opts = dict(opts) if '-h' in opts: usage() sys.exit(0) if '-f' in opts and args: usage('If -f is used, then domain names may not supplied as command line arguments.') sys.exit(1) if '-R' in opts: try: rdtypes = opts['-R'].split(',') except ValueError: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) try: rdtypes = [dns.rdatatype.from_text(x) for x in rdtypes] except dns.rdatatype.UnknownRdatatype: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) else: rdtypes = None if '-T' in opts: fmt = opts['-T'] elif '-o' in opts: fmt = opts['-o'].split('.')[-1] else: fmt = 'dot' if fmt not in ('dot','png','jpg','svg','html'): usage('Image format unrecognized: "%s"' % fmt) sys.exit(1) if '-o' in opts and '-O' in opts: usage('The -o and -O options may not be used together.') sys.exit(1) handler = logging.StreamHandler() handler.setLevel(logging.WARNING) logger.addHandler(handler) logger.setLevel(logging.WARNING) if '-r' not in opts or opts['-r'] == '-': opt_r = sys.stdin.fileno() else: opt_r = opts['-r'] try: analysis_str = io.open(opt_r, 'r', encoding='utf-8').read() except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts.get('-r', '-'))) sys.exit(3) try: analysis_structured = json.loads(analysis_str) except ValueError: logger.error('There was an error parsing the json input: "%s"' % opts.get('-r', '-')) sys.exit(3) # check version if '_meta._dnsviz.' not in analysis_structured or 'version' not in analysis_structured['_meta._dnsviz.']: logger.error('No version information in JSON input.') sys.exit(3) try: major_vers, minor_vers = [int(x) for x in str(analysis_structured['_meta._dnsviz.']['version']).split('.', 1)] except ValueError: logger.error('Version of JSON input is invalid: %s' % analysis_structured['_meta._dnsviz.']['version']) sys.exit(3) # ensure major version is a match and minor version is no greater # than the current minor version curr_major_vers, curr_minor_vers = [int(x) for x in str(DNS_RAW_VERSION).split('.', 1)] if major_vers != curr_major_vers or minor_vers > curr_minor_vers: logger.error('Version %d.%d of JSON input is incompatible with this software.' % (major_vers, minor_vers)) sys.exit(3) names = [] if '-f' in opts: if opts['-f'] == '-': opts['-f'] = sys.stdin.fileno() try: f = io.open(opts['-f'], 'r', encoding='utf-8') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-f'])) sys.exit(3) for line in f: name = line.strip() try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) f.close() else: if args: # python3/python2 dual compatibility if isinstance(args[0], bytes): args = [codecs.decode(x, sys.getfilesystemencoding()) for x in args] else: try: args = analysis_structured['_meta._dnsviz.']['names'] except KeyError: logger.error('No names found in json input!') sys.exit(3) for name in args: try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) if '-t' not in opts: try: tk_str = io.open(TRUSTED_KEYS_ROOT, 'r', encoding='utf-8').read() except IOError as e: logger.error('Error reading trusted keys file "%s": %s' % (TRUSTED_KEYS_ROOT, e.strerror)) sys.exit(3) try: trusted_keys.extend(get_trusted_keys(tk_str)) except dns.exception.DNSException: logger.error('There was an error parsing the trusted keys file: "%s"' % arg) sys.exit(3) name_objs = [] cache = {} for name in names: name_str = lb2s(name.canonicalize().to_text()) if name_str not in analysis_structured or analysis_structured[name_str].get('stub', True): logger.error('The analysis of "%s" was not found in the input.' % lb2s(name.to_text())) continue name_objs.append(OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) if not name_objs: sys.exit(4) G = DNSAuthGraph() for name_obj in name_objs: name_obj.populate_status(trusted_keys) for qname, rdtype in name_obj.queries: if rdtypes is None: # if rdtypes was not specified, then graph all, with some # exceptions if name_obj.is_zone() and rdtype in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV): continue else: # if rdtypes was specified, then only graph rdtypes that # were specified if qname != name_obj.name or rdtype not in rdtypes: continue G.graph_rrset_auth(name_obj, qname, rdtype) if rdtypes is not None: for rdtype in rdtypes: if (name_obj.name, rdtype) not in name_obj.queries: logger.error('No query for "%s/%s" was included in the analysis.' % (lb2s(name_obj.name.to_text()), dns.rdatatype.to_text(rdtype))) if '-O' in opts: if name_obj.name == dns.name.root: name = 'root' else: name = lb2s(name_obj.name.canonicalize().to_text()).rstrip('.') finish_graph(G, [name_obj], rdtypes, trusted_keys, fmt, '%s.%s' % (name, fmt)) G = DNSAuthGraph() if '-O' not in opts: if '-o' not in opts or opts['-o'] == '-': finish_graph(G, name_objs, rdtypes, trusted_keys, fmt, None) else: finish_graph(G, name_objs, rdtypes, trusted_keys, fmt, opts['-o']) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4)
def name_url_encode(name): if name == dns.name.root: return 'root' return urllib.quote(name.canonicalize().to_text().rstrip('.').replace('/', 'S'), safe='')
d = collections.OrderedDict() name_obj.serialize(d) s = json.dumps(d, **kwargs) lindex = s.index('{') rindex = s.rindex('}') fh.write(s[lindex+1:rindex]+',') dnsviz_meta = { 'version': DNS_RAW_VERSION, 'names': [n.to_text() for n in names] } flush = '-F' in opts name_objs = [] if '-r' in opts: cache = {} for name in names: if name.canonicalize().to_text() not in analysis_structured: logger.error('The domain name was not found in the analysis input: "%s"' % name.to_text()) continue name_objs.append(OnlineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) else: if '-t' in opts: a = cls(client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, explicit_delegations, rdtypes, explicit_only, dlv_domain, processes) else: a = cls(client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, explicit_delegations, rdtypes, explicit_only, dlv_domain) if flush: fh.write('{') a.analyze(names, _flush) fh.write('"_meta._dnsviz.":%s}' % json.dumps(dnsviz_meta, **kwargs)) sys.exit(0) name_objs = a.analyze(names)
def main(argv): try: test_pygraphviz() try: opts, args = getopt.getopt(argv[1:], 'f:r:R:et:a:d:CPOo:T:h') except getopt.GetoptError as e: sys.stderr.write('%s\n' % str(e)) sys.exit(1) # collect trusted keys trusted_keys = [] for opt, arg in opts: if opt == '-t': try: with io.open(arg, 'r', encoding='utf-8') as fh: tk_str = fh.read() except IOError as e: logger.error('%s: "%s"' % (e.strerror, arg)) sys.exit(3) try: trusted_keys.extend(get_trusted_keys(tk_str)) except dns.exception.DNSException: logger.error( 'There was an error parsing the trusted keys file: "%s"' % arg) sys.exit(3) opts = dict(opts) if '-h' in opts: usage() sys.exit(0) if '-f' in opts and args: sys.stderr.write( 'If -f is used, then domain names may not supplied as command line arguments.\n' ) sys.exit(1) if '-R' in opts: try: rdtypes = opts['-R'].split(',') except ValueError: sys.stderr.write('The list of types was invalid: "%s"\n' % opts['-R']) sys.exit(1) try: rdtypes = [dns.rdatatype.from_text(x) for x in rdtypes] except dns.rdatatype.UnknownRdatatype: sys.stderr.write('The list of types was invalid: "%s"\n' % opts['-R']) sys.exit(1) else: rdtypes = None if '-a' in opts: try: supported_algs = opts['-a'].split(',') except ValueError: sys.stderr.write('The list of algorithms was invalid: "%s"\n' % opts['-a']) sys.exit(1) try: supported_algs = set([int(x) for x in supported_algs]) except ValueError: sys.stderr.write('The list of algorithms was invalid: "%s"\n' % opts['-a']) sys.exit(1) else: supported_algs = None if '-d' in opts: try: supported_digest_algs = opts['-d'].split(',') except ValueError: sys.stderr.write( 'The list of digest algorithms was invalid: "%s"\n' % opts['-d']) sys.exit(1) try: supported_digest_algs = set( [int(x) for x in supported_digest_algs]) except ValueError: sys.stderr.write( 'The list of digest algorithms was invalid: "%s"\n' % opts['-d']) sys.exit(1) else: supported_digest_algs = None strict_cookies = '-C' in opts allow_private = '-P' in opts remove_edges = '-e' not in opts if '-T' in opts: fmt = opts['-T'] elif '-o' in opts: fmt = opts['-o'].split('.')[-1] else: fmt = 'dot' if fmt not in ('dot', 'png', 'jpg', 'svg', 'html'): sys.stderr.write('Image format unrecognized: "%s"\n' % fmt) sys.exit(1) if '-o' in opts and '-O' in opts: sys.stderr.write( 'The -o and -O options may not be used together.\n') sys.exit(1) if '-r' not in opts or opts['-r'] == '-': opt_r = sys.stdin.fileno() else: opt_r = opts['-r'] try: with io.open(opt_r, 'r', encoding='utf-8') as fh: analysis_str = fh.read() except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts.get('-r', '-'))) sys.exit(3) if not analysis_str: if opt_r != sys.stdin.fileno(): logger.error('No input.') sys.exit(3) try: analysis_structured = json.loads(analysis_str) except ValueError: logger.error('There was an error parsing the JSON input: "%s"' % opts.get('-r', '-')) sys.exit(3) # check version if '_meta._dnsviz.' not in analysis_structured or 'version' not in analysis_structured[ '_meta._dnsviz.']: logger.error('No version information in JSON input.') sys.exit(3) try: major_vers, minor_vers = [ int(x) for x in str(analysis_structured['_meta._dnsviz.'] ['version']).split('.', 1) ] except ValueError: logger.error('Version of JSON input is invalid: %s' % analysis_structured['_meta._dnsviz.']['version']) sys.exit(3) # ensure major version is a match and minor version is no greater # than the current minor version curr_major_vers, curr_minor_vers = [ int(x) for x in str(DNS_RAW_VERSION).split('.', 1) ] if major_vers != curr_major_vers or minor_vers > curr_minor_vers: logger.error( 'Version %d.%d of JSON input is incompatible with this software.' % (major_vers, minor_vers)) sys.exit(3) names = OrderedDict() if '-f' in opts: if opts['-f'] == '-': opts['-f'] = sys.stdin.fileno() try: f = io.open(opts['-f'], 'r', encoding='utf-8') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-f'])) sys.exit(3) for line in f: name = line.strip() try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: if name not in names: names[name] = None f.close() else: if args: # python3/python2 dual compatibility if isinstance(args[0], bytes): args = [ codecs.decode(x, sys.getfilesystemencoding()) for x in args ] else: try: args = analysis_structured['_meta._dnsviz.']['names'] except KeyError: logger.error('No names found in JSON input!') sys.exit(3) for name in args: try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: if name not in names: names[name] = None latest_analysis_date = None name_objs = [] cache = {} for name in names: name_str = lb2s(name.canonicalize().to_text()) if name_str not in analysis_structured or analysis_structured[ name_str].get('stub', True): logger.error( 'The analysis of "%s" was not found in the input.' % lb2s(name.to_text())) continue name_obj = OfflineDomainNameAnalysis.deserialize( name, analysis_structured, cache, strict_cookies=strict_cookies, allow_private=allow_private) name_objs.append(name_obj) if latest_analysis_date is None or latest_analysis_date > name_obj.analysis_end: latest_analysis_date = name_obj.analysis_end if not name_objs: sys.exit(4) if '-t' not in opts: trusted_keys = get_default_trusted_keys(latest_analysis_date) G = DNSAuthGraph() for name_obj in name_objs: name_obj.populate_status( trusted_keys, supported_algs=supported_algs, supported_digest_algs=supported_digest_algs) for qname, rdtype in name_obj.queries: if rdtypes is None: # if rdtypes was not specified, then graph all, with some # exceptions if name_obj.is_zone() and rdtype in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV): continue else: # if rdtypes was specified, then only graph rdtypes that # were specified if qname != name_obj.name or rdtype not in rdtypes: continue G.graph_rrset_auth(name_obj, qname, rdtype) if rdtypes is not None: for rdtype in rdtypes: if (name_obj.name, rdtype) not in name_obj.queries: logger.error( 'No query for "%s/%s" was included in the analysis.' % (lb2s(name_obj.name.to_text()), dns.rdatatype.to_text(rdtype))) if '-O' in opts: if name_obj.name == dns.name.root: name = 'root' else: name = lb2s( name_obj.name.canonicalize().to_text()).rstrip('.') finish_graph(G, [name_obj], rdtypes, trusted_keys, supported_algs, fmt, '%s.%s' % (name, fmt), remove_edges) G = DNSAuthGraph() if '-O' not in opts: if '-o' not in opts or opts['-o'] == '-': finish_graph(G, name_objs, rdtypes, trusted_keys, supported_algs, fmt, None, remove_edges) else: finish_graph(G, name_objs, rdtypes, trusted_keys, supported_algs, fmt, opts['-o'], remove_edges) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4)
def main(argv): global tm global full_resolver global stub_resolver global explicit_delegations global odd_ports global next_port try: try: opts, args = getopt.getopt( argv[1:], 'f:d:l:c:r:t:64b:u:kmpo:a:R:x:N:D:e:EAs:Fh') except getopt.GetoptError as e: usage(str(e)) sys.exit(1) _init_tm() stub_resolver = Resolver.from_file('/etc/resolv.conf', StandardRecursiveQueryCD, transport_manager=tm) # get all the options for which there might be multiple values explicit_delegations = {} odd_ports = {} stop_at_explicit = {} client_ipv4 = None client_ipv6 = None delegation_info = {} for opt, arg in opts: if opt in ('-x', '-N'): try: domain, mappings = arg.split(':', 1) except ValueError: usage('Incorrect usage of %s option: "%s"' % (opt, arg)) sys.exit(1) domain = domain.strip() mappings = mappings.strip() match = STOP_RE.search(domain) if match is not None: if opt == '-N': usage('Incorrect usage of %s option: "%s"' % (opt, arg)) sys.exit(1) 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 opt == '-N' and domain == dns.name.root: usage('The root zone cannot be used with option -N.') sys.exit(1) if match is not None: stop_at_explicit[domain] = True else: stop_at_explicit[domain] = False if opt == '-N': if domain == dns.name.root: usage('The root zone cannot be used with option -N.') sys.exit(1) parent = domain.parent() if parent not in delegation_info: delegation_info[parent] = {} delegation_mapping = delegation_info[parent] else: delegation_mapping = explicit_delegations if not mappings: usage('Incorrect usage of %s option: "%s"' % (arg, opt)) sys.exit(1) if (domain, dns.rdatatype.NS) not in delegation_mapping: delegation_mapping[(domain, dns.rdatatype.NS)] = dns.rrset.RRset( domain, dns.rdataclass.IN, dns.rdatatype.NS) name_addr_mappings_from_string(domain, mappings, delegation_mapping, opt == '-N') elif opt == '-D': try: domain, ds_str = arg.split(':', 1) except ValueError: usage('Incorrect usage of %s option: "%s"' % (opt, arg)) sys.exit(1) domain = domain.strip() ds_str = ds_str.strip() try: domain = dns.name.from_text(domain) except dns.exception.DNSException: usage('The domain name was invalid: "%s"' % domain) sys.exit(1) parent = domain.parent() if parent not in delegation_info: delegation_info[parent] = {} delegation_mapping = delegation_info[parent] if not ds_str: usage('Incorrect usage of %s option: "%s"' % (arg, opt)) sys.exit(1) if (domain, dns.rdatatype.DS) not in delegation_mapping: delegation_mapping[(domain, dns.rdatatype.DS)] = dns.rrset.RRset( domain, dns.rdataclass.IN, dns.rdatatype.DS) ds_from_string(domain, ds_str.strip(), delegation_mapping) elif opt == '-b': try: addr = IPAddr(arg) except ValueError: usage('The IP address was invalid: "%s"' % arg) sys.exit(1) if addr.version == 4: client_ipv4 = addr fam = socket.AF_INET else: client_ipv6 = addr fam = socket.AF_INET6 try: s = socket.socket(fam) s.bind((addr, 0)) del s except socket.error as e: if e.errno == errno.EADDRNOTAVAIL: usage('Cannot bind to specified IP address: "%s"' % addr) sys.exit(1) opts = dict(opts) if '-h' in opts: usage() sys.exit(0) if not ('-f' in opts or args) and '-r' not in opts: usage( 'When -r is not used, either -f must be used or domain names must be supplied as command line arguments.' ) sys.exit(1) if '-f' in opts and args: usage( 'If -f is used, then domain names may not supplied as command line arguments.' ) sys.exit(1) if '-A' in opts and '-s' in opts: usage('If -A is used, then -s cannot be used.') sys.exit(1) if '-x' in opts and '-A' not in opts: usage('-x may only be used in conjunction with -A.') sys.exit(1) if '-N' in opts and '-A' not in opts: usage('-N may only be used in conjunction with -A.') sys.exit(1) if '-D' in opts and '-N' not in opts: #TODO retrieve NS/A/AAAA if -D is specified but -N is not usage('-D may only be used in conjunction with -N.') sys.exit(1) if '-4' in opts and '-6' in opts: usage('-4 and -6 may not be used together.') sys.exit(1) if '-a' in opts: try: ceiling = dns.name.from_text(opts['-a']) except dns.exception.DNSException: usage('The domain name was invalid: "%s"' % opts['-a']) sys.exit(1) elif '-A' in opts: ceiling = None else: ceiling = dns.name.root if '-R' in opts: explicit_only = True try: rdtypes = opts['-R'].split(',') except ValueError: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) try: rdtypes = [dns.rdatatype.from_text(x) for x in rdtypes] except dns.rdatatype.UnknownRdatatype: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) else: rdtypes = None explicit_only = False # if neither is specified, then they're both tried if '-4' not in opts and '-6' not in opts: try_ipv4 = True try_ipv6 = True # if one or the other is specified, then only the one specified is # tried else: if '-4' in opts: try_ipv4 = True try_ipv6 = False else: # -6 in opts try_ipv4 = False try_ipv6 = True for domain in delegation_info: if (domain, dns.rdatatype.NS) in explicit_delegations: usage( 'Cannot use "%s" with -x if its child is specified with -N' % lb2s(domain.canonicalize().to_text())) sys.exit(1) port = next_port next_port += 1 _create_and_serve_zone(domain, delegation_info[domain], port) localhost = dns.name.from_text('localhost') loopback = IPAddr('127.0.0.1') explicit_delegations[(domain, dns.rdatatype.NS)] = dns.rrset.RRset( domain, dns.rdataclass.IN, dns.rdatatype.NS) explicit_delegations[(domain, dns.rdatatype.NS)].add( dns.rdtypes.ANY.NS.NS(dns.rdataclass.IN, dns.rdatatype.NS, localhost)) explicit_delegations[(localhost, dns.rdatatype.A)] = dns.rrset.RRset( localhost, dns.rdataclass.IN, dns.rdatatype.A) explicit_delegations[(localhost, dns.rdatatype.A)].add( dns.rdtypes.IN.A.A(dns.rdataclass.IN, dns.rdatatype.A, loopback)) odd_ports[(domain, loopback)] = port stop_at_explicit[domain] = True if '-A' not in opts: if '-t' in opts: cls = RecursiveParallelAnalyst else: cls = RecursiveBulkAnalyst explicit_delegations[(WILDCARD_EXPLICIT_DELEGATION, dns.rdatatype.NS)] = dns.rrset.RRset( WILDCARD_EXPLICIT_DELEGATION, dns.rdataclass.IN, dns.rdatatype.NS) if '-s' in opts: name_addr_mappings_from_string(WILDCARD_EXPLICIT_DELEGATION, opts['-s'], explicit_delegations, False) else: for i, server in enumerate(stub_resolver._servers): if IPAddr(server).version == 6: rdtype = dns.rdatatype.AAAA else: rdtype = dns.rdatatype.A name = dns.name.from_text('ns%d' % i) explicit_delegations[(WILDCARD_EXPLICIT_DELEGATION, dns.rdatatype.NS)].add( dns.rdtypes.ANY.NS.NS( dns.rdataclass.IN, dns.rdatatype.NS, name)) if (name, rdtype) not in explicit_delegations: explicit_delegations[(name, rdtype)] = dns.rrset.RRset( name, dns.rdataclass.IN, rdtype) explicit_delegations[(name, rdtype)].add( dns.rdata.from_text(dns.rdataclass.IN, rdtype, server)) else: if '-t' in opts: cls = ParallelAnalyst else: cls = BulkAnalyst edns_diagnostics = '-E' in opts if '-u' in opts: # check that version is >= 2.7.9 if HTTPS is requested if opts['-u'].startswith('https'): vers0, vers1, vers2 = sys.version_info[:3] if (2, 7, 9) > (vers0, vers1, vers2): sys.stderr.write( 'python version >= 2.7.9 is required to use a DNS looking glass with HTTPS.\n' ) sys.exit(1) url = urlparse.urlparse(opts['-u']) if url.scheme in ('http', 'https'): th_factories = (transport.DNSQueryTransportHandlerHTTPFactory( opts['-u'], insecure='-k' in opts), ) elif url.scheme == 'ws': if url.hostname is not None: usage( 'WebSocket URL must designate a local UNIX domain socket.' ) sys.exit(1) th_factories = ( transport.DNSQueryTransportHandlerWebSocketFactory( url.path), ) else: usage('Unsupported URL scheme: "%s"' % opts['-u']) sys.exit(1) else: th_factories = None if '-l' in opts: try: dlv_domain = dns.name.from_text(opts['-l']) except dns.exception.DNSException: usage('The domain name was invalid: "%s"' % opts['-l']) sys.exit(1) else: dlv_domain = None # the following option is not documented in usage, as it doesn't # apply to most users try: cache_level = int(opts['-c']) except (KeyError, ValueError): cache_level = None try: processes = int(opts.get('-t', 1)) except ValueError: usage('The number of threads used must be greater than 0.') sys.exit(1) if processes < 1: usage('The number of threads used must be greater than 0.') sys.exit(1) try: val = int(opts.get('-d', 2)) except ValueError: usage('The debug value must be an integer between 0 and 3.') sys.exit(1) if val < 0 or val > 3: usage('The debug value must be an integer between 0 and 3.') sys.exit(1) if val > 2: debug_level = logging.DEBUG elif val > 1: debug_level = logging.INFO elif val > 0: debug_level = logging.WARNING else: debug_level = logging.ERROR handler = logging.StreamHandler() handler.setLevel(debug_level) logger.addHandler(handler) logger.setLevel(debug_level) if '-A' in opts: if try_ipv4 and get_client_address(A_ROOT_IPV4) is None: logger.warning('No global IPv4 connectivity detected') if try_ipv6 and get_client_address(A_ROOT_IPV6) is None: logger.warning('No global IPv6 connectivity detected') if '-r' in opts: if opts['-r'] == '-': opt_r = sys.stdin.fileno() else: opt_r = opts['-r'] try: analysis_str = io.open(opt_r, 'r', encoding='utf-8').read() except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts.get('-r', '-'))) sys.exit(3) try: analysis_structured = json.loads(analysis_str) except ValueError: logger.error( 'There was an error parsing the json input: "%s"' % opts['-r']) sys.exit(3) # check version if '_meta._dnsviz.' not in analysis_structured or 'version' not in analysis_structured[ '_meta._dnsviz.']: logger.error('No version information in JSON input.') sys.exit(3) try: major_vers, minor_vers = [ int(x) for x in str(analysis_structured['_meta._dnsviz.'] ['version']).split('.', 1) ] except ValueError: logger.error('Version of JSON input is invalid: %s' % analysis_structured['_meta._dnsviz.']['version']) sys.exit(3) # ensure major version is a match and minor version is no greater # than the current minor version curr_major_vers, curr_minor_vers = [ int(x) for x in str(DNS_RAW_VERSION).split('.', 1) ] if major_vers != curr_major_vers or minor_vers > curr_minor_vers: logger.error( 'Version %d.%d of JSON input is incompatible with this software.' % (major_vers, minor_vers)) sys.exit(3) names = [] if '-f' in opts: if opts['-f'] == '-': opts['-f'] = sys.stdin.fileno() try: f = io.open(opts['-f'], 'r', encoding='utf-8') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-f'])) sys.exit(3) for line in f: name = line.strip() try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) f.close() else: if args: # python3/python2 dual compatibility if isinstance(args[0], bytes): args = [ codecs.decode(x, sys.getfilesystemencoding()) for x in args ] else: try: args = analysis_structured['_meta._dnsviz.']['names'] except KeyError: logger.error('No names found in json input!') sys.exit(3) for name in args: try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) if '-p' in opts: kwargs = {'indent': 4, 'separators': (',', ': ')} else: kwargs = {} meta_only = '-m' in opts if '-o' not in opts or opts['-o'] == '-': opts['-o'] = sys.stdout.fileno() try: fh = io.open(opts['-o'], 'wb') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-o'])) sys.exit(3) def _flush(name_obj): d = collections.OrderedDict() name_obj.serialize(d) s = json.dumps(d, **kwargs) lindex = s.index('{') rindex = s.rindex('}') fh.write(s[lindex + 1:rindex] + ',') dnsviz_meta = { 'version': DNS_RAW_VERSION, 'names': [lb2s(n.to_text()) for n in names] } flush = '-F' in opts if '-e' in opts: CustomQueryMixin.edns_options = [_get_ecs_option(opts['-e'])] query_class_mixin = CustomQueryMixin else: query_class_mixin = None name_objs = [] if '-r' in opts: cache = {} for name in names: if name.canonicalize().to_text() not in analysis_structured: logger.error( 'The domain name was not found in the analysis input: "%s"' % name.to_text()) continue name_objs.append( OnlineDomainNameAnalysis.deserialize( name, analysis_structured, cache)) else: if '-t' in opts: a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, query_class_mixin, ceiling, edns_diagnostics, stop_at_explicit, cache_level, rdtypes, explicit_only, dlv_domain, th_factories, processes) else: _init_resolver() a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, query_class_mixin, ceiling, edns_diagnostics, stop_at_explicit, cache_level, rdtypes, explicit_only, dlv_domain, th_factories) if flush: fh.write('{') a.analyze(names, _flush) fh.write('"_meta._dnsviz.":%s}' % json.dumps(dnsviz_meta, **kwargs)) sys.exit(0) name_objs = a.analyze(names) name_objs = [x for x in name_objs if x is not None] if not name_objs: sys.exit(4) d = collections.OrderedDict() for name_obj in name_objs: name_obj.serialize(d, meta_only) d['_meta._dnsviz.'] = dnsviz_meta try: fh.write( json.dumps(d, ensure_ascii=False, **kwargs).encode('utf-8')) except IOError as e: logger.error('Error writing analysis: %s' % e) sys.exit(3) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4) # tm is global (because of possible multiprocessing), so we need to # explicitly close it here finally: if tm is not None: tm.close()
def main(argv): global tm global th_factories global resolver global bootstrap_resolver global explicit_delegations global odd_ports global next_port try: try: opts, args = getopt.getopt(argv[1:], 'f:d:l:c:r:t:64b:u:kmpo:a:R:x:N:D:ne:EAs:Fh') except getopt.GetoptError as e: usage(str(e)) sys.exit(1) _init_tm() bootstrap_resolver = Resolver.from_file('/etc/resolv.conf', StandardRecursiveQueryCD, transport_manager=tm) # get all the options for which there might be multiple values explicit_delegations = {} odd_ports = {} stop_at_explicit = {} client_ipv4 = None client_ipv6 = None delegation_info = {} for opt, arg in opts: if opt in ('-x', '-N'): try: domain, mappings = arg.split(':', 1) except ValueError: usage('Incorrect usage of %s option: "%s"' % (opt, arg)) sys.exit(1) domain = domain.strip() mappings = mappings.strip() match = STOP_RE.search(domain) if match is not None: if opt == '-N': usage('Incorrect usage of %s option: "%s"' % (opt, arg)) sys.exit(1) 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 opt == '-N' and domain == dns.name.root: usage('The root zone cannot be used with option -N.') sys.exit(1) if match is not None: stop_at_explicit[domain] = True else: stop_at_explicit[domain] = False if opt == '-N': if domain == dns.name.root: usage('The root zone cannot be used with option -N.') sys.exit(1) parent = domain.parent() if parent not in delegation_info: delegation_info[parent] = {} delegation_mapping = delegation_info[parent] else: delegation_mapping = explicit_delegations if not mappings: usage('Incorrect usage of %s option: "%s"' % (arg, opt)) sys.exit(1) if (domain, dns.rdatatype.NS) not in delegation_mapping: delegation_mapping[(domain, dns.rdatatype.NS)] = dns.rrset.RRset(domain, dns.rdataclass.IN, dns.rdatatype.NS) name_addr_mappings_from_string(domain, mappings, delegation_mapping, opt == '-N') elif opt == '-D': try: domain, ds_str = arg.split(':', 1) except ValueError: usage('Incorrect usage of %s option: "%s"' % (opt, arg)) sys.exit(1) domain = domain.strip() ds_str = ds_str.strip() try: domain = dns.name.from_text(domain) except dns.exception.DNSException: usage('The domain name was invalid: "%s"' % domain) sys.exit(1) parent = domain.parent() if parent not in delegation_info: delegation_info[parent] = {} delegation_mapping = delegation_info[parent] if not ds_str: usage('Incorrect usage of %s option: "%s"' % (arg, opt)) sys.exit(1) if (domain, dns.rdatatype.DS) not in delegation_mapping: delegation_mapping[(domain, dns.rdatatype.DS)] = dns.rrset.RRset(domain, dns.rdataclass.IN, dns.rdatatype.DS) ds_from_string(domain, ds_str.strip(), delegation_mapping) elif opt == '-b': try: addr = IPAddr(arg) except ValueError: usage('The IP address was invalid: "%s"' % arg) sys.exit(1) if addr.version == 4: client_ipv4 = addr fam = socket.AF_INET else: client_ipv6 = addr fam = socket.AF_INET6 try: s = socket.socket(fam) s.bind((addr, 0)) del s except socket.error as e: if e.errno == errno.EADDRNOTAVAIL: usage('Cannot bind to specified IP address: "%s"' % addr) sys.exit(1) opts = dict(opts) if '-h' in opts: usage() sys.exit(0) if not ('-f' in opts or args) and '-r' not in opts: usage('When -r is not used, either -f must be used or domain names must be supplied as command line arguments.') sys.exit(1) if '-f' in opts and args: usage('If -f is used, then domain names may not supplied as command line arguments.') sys.exit(1) if '-A' in opts and '-s' in opts: usage('If -A is used, then -s cannot be used.') sys.exit(1) if '-x' in opts and '-A' not in opts: usage('-x may only be used in conjunction with -A.') sys.exit(1) if '-N' in opts and '-A' not in opts: usage('-N may only be used in conjunction with -A.') sys.exit(1) if '-D' in opts and '-N' not in opts: #TODO retrieve NS/A/AAAA if -D is specified but -N is not usage('-D may only be used in conjunction with -N.') sys.exit(1) if '-4' in opts and '-6' in opts: usage('-4 and -6 may not be used together.') sys.exit(1) if '-a' in opts: try: ceiling = dns.name.from_text(opts['-a']) except dns.exception.DNSException: usage('The domain name was invalid: "%s"' % opts['-a']) sys.exit(1) elif '-A' in opts: ceiling = None else: ceiling = dns.name.root if '-R' in opts: explicit_only = True try: rdtypes = opts['-R'].split(',') except ValueError: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) try: rdtypes = [dns.rdatatype.from_text(x) for x in rdtypes] except dns.rdatatype.UnknownRdatatype: usage('The list of types was invalid: "%s"' % opts['-R']) sys.exit(1) else: rdtypes = None explicit_only = False # if neither is specified, then they're both tried if '-4' not in opts and '-6' not in opts: try_ipv4 = True try_ipv6 = True # if one or the other is specified, then only the one specified is # tried else: if '-4' in opts: try_ipv4 = True try_ipv6 = False else: # -6 in opts try_ipv4 = False try_ipv6 = True for domain in delegation_info: if (domain, dns.rdatatype.NS) in explicit_delegations: usage('Cannot use "%s" with -x if its child is specified with -N' % lb2s(domain.canonicalize().to_text())) sys.exit(1) port = next_port next_port += 1 _create_and_serve_zone(domain, delegation_info[domain], port) localhost = dns.name.from_text('localhost') loopback = IPAddr('127.0.0.1') explicit_delegations[(domain, dns.rdatatype.NS)] = dns.rrset.RRset(domain, dns.rdataclass.IN, dns.rdatatype.NS) explicit_delegations[(domain, dns.rdatatype.NS)].add(dns.rdtypes.ANY.NS.NS(dns.rdataclass.IN, dns.rdatatype.NS, localhost)) explicit_delegations[(localhost, dns.rdatatype.A)] = dns.rrset.RRset(localhost, dns.rdataclass.IN, dns.rdatatype.A) explicit_delegations[(localhost, dns.rdatatype.A)].add(dns.rdtypes.IN.A.A(dns.rdataclass.IN, dns.rdatatype.A, loopback)) odd_ports[(domain, loopback)] = port stop_at_explicit[domain] = True if '-A' not in opts: if '-t' in opts: cls = RecursiveParallelAnalyst else: cls = RecursiveBulkAnalyst explicit_delegations[(WILDCARD_EXPLICIT_DELEGATION, dns.rdatatype.NS)] = dns.rrset.RRset(WILDCARD_EXPLICIT_DELEGATION, dns.rdataclass.IN, dns.rdatatype.NS) if '-s' in opts: name_addr_mappings_from_string(WILDCARD_EXPLICIT_DELEGATION, opts['-s'], explicit_delegations, False) else: for i, server in enumerate(bootstrap_resolver._servers): if IPAddr(server).version == 6: rdtype = dns.rdatatype.AAAA else: rdtype = dns.rdatatype.A name = dns.name.from_text('ns%d' % i) explicit_delegations[(WILDCARD_EXPLICIT_DELEGATION, dns.rdatatype.NS)].add(dns.rdtypes.ANY.NS.NS(dns.rdataclass.IN, dns.rdatatype.NS, name)) if (name, rdtype) not in explicit_delegations: explicit_delegations[(name, rdtype)] = dns.rrset.RRset(name, dns.rdataclass.IN, rdtype) explicit_delegations[(name, rdtype)].add(dns.rdata.from_text(dns.rdataclass.IN, rdtype, server)) else: if '-t' in opts: cls = ParallelAnalyst else: cls = BulkAnalyst edns_diagnostics = '-E' in opts if '-u' in opts: # check that version is >= 2.7.9 if HTTPS is requested if opts['-u'].startswith('https'): vers0, vers1, vers2 = sys.version_info[:3] if (2, 7, 9) > (vers0, vers1, vers2): sys.stderr.write('python version >= 2.7.9 is required to use a DNS looking glass with HTTPS.\n') sys.exit(1) url = urlparse.urlparse(opts['-u']) if url.scheme in ('http', 'https'): th_factories = (transport.DNSQueryTransportHandlerHTTPFactory(opts['-u'], insecure='-k' in opts),) elif url.scheme == 'ws': if url.hostname is not None: usage('WebSocket URL must designate a local UNIX domain socket.') sys.exit(1) th_factories = (transport.DNSQueryTransportHandlerWebSocketServerFactory(url.path),) elif url.scheme == 'ssh': th_factories = (transport.DNSQueryTransportHandlerRemoteCmdFactory(opts['-u']),) else: usage('Unsupported URL scheme: "%s"' % opts['-u']) sys.exit(1) else: th_factories = None if '-l' in opts: try: dlv_domain = dns.name.from_text(opts['-l']) except dns.exception.DNSException: usage('The domain name was invalid: "%s"' % opts['-l']) sys.exit(1) else: dlv_domain = None # the following option is not documented in usage, as it doesn't # apply to most users try: cache_level = int(opts['-c']) except (KeyError, ValueError): cache_level = None try: processes = int(opts.get('-t', 1)) except ValueError: usage('The number of threads used must be greater than 0.') sys.exit(1) if processes < 1: usage('The number of threads used must be greater than 0.') sys.exit(1) try: val = int(opts.get('-d', 2)) except ValueError: usage('The debug value must be an integer between 0 and 3.') sys.exit(1) if val < 0 or val > 3: usage('The debug value must be an integer between 0 and 3.') sys.exit(1) if val > 2: debug_level = logging.DEBUG elif val > 1: debug_level = logging.INFO elif val > 0: debug_level = logging.WARNING else: debug_level = logging.ERROR handler = logging.StreamHandler() handler.setLevel(debug_level) logger.addHandler(handler) logger.setLevel(debug_level) if '-A' in opts: if try_ipv4 and get_client_address(A_ROOT_IPV4) is None: logger.warning('No global IPv4 connectivity detected') if try_ipv6 and get_client_address(A_ROOT_IPV6) is None: logger.warning('No global IPv6 connectivity detected') if '-r' in opts: if opts['-r'] == '-': opt_r = sys.stdin.fileno() else: opt_r = opts['-r'] try: analysis_str = io.open(opt_r, 'r', encoding='utf-8').read() except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts.get('-r', '-'))) sys.exit(3) try: analysis_structured = json.loads(analysis_str) except ValueError: logger.error('There was an error parsing the json input: "%s"' % opts['-r']) sys.exit(3) # check version if '_meta._dnsviz.' not in analysis_structured or 'version' not in analysis_structured['_meta._dnsviz.']: logger.error('No version information in JSON input.') sys.exit(3) try: major_vers, minor_vers = [int(x) for x in str(analysis_structured['_meta._dnsviz.']['version']).split('.', 1)] except ValueError: logger.error('Version of JSON input is invalid: %s' % analysis_structured['_meta._dnsviz.']['version']) sys.exit(3) # ensure major version is a match and minor version is no greater # than the current minor version curr_major_vers, curr_minor_vers = [int(x) for x in str(DNS_RAW_VERSION).split('.', 1)] if major_vers != curr_major_vers or minor_vers > curr_minor_vers: logger.error('Version %d.%d of JSON input is incompatible with this software.' % (major_vers, minor_vers)) sys.exit(3) names = [] if '-f' in opts: if opts['-f'] == '-': opts['-f'] = sys.stdin.fileno() try: f = io.open(opts['-f'], 'r', encoding='utf-8') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-f'])) sys.exit(3) for line in f: name = line.strip() try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) f.close() else: if args: # python3/python2 dual compatibility if isinstance(args[0], bytes): args = [codecs.decode(x, sys.getfilesystemencoding()) for x in args] else: try: args = analysis_structured['_meta._dnsviz.']['names'] except KeyError: logger.error('No names found in json input!') sys.exit(3) for name in args: try: name = dns.name.from_text(name) except UnicodeDecodeError as e: logger.error('%s: "%s"' % (e, name)) except dns.exception.DNSException: logger.error('The domain name was invalid: "%s"' % name) else: names.append(name) if '-p' in opts: kwargs = { 'indent': 4, 'separators': (',', ': ') } else: kwargs = {} meta_only = '-m' in opts if '-o' not in opts or opts['-o'] == '-': opts['-o'] = sys.stdout.fileno() try: fh = io.open(opts['-o'], 'wb') except IOError as e: logger.error('%s: "%s"' % (e.strerror, opts['-o'])) sys.exit(3) def _flush(name_obj): d = OrderedDict() name_obj.serialize(d) s = json.dumps(d, **kwargs) lindex = s.index('{') rindex = s.rindex('}') fh.write(s[lindex+1:rindex]+',') dnsviz_meta = { 'version': DNS_RAW_VERSION, 'names': [lb2s(n.to_text()) for n in names] } flush = '-F' in opts if '-n' in opts or '-e' in opts: CustomQueryMixin.edns_options = [] if '-e' in opts: CustomQueryMixin.edns_options.append(_get_ecs_option(opts['-e'])) if '-n' in opts: CustomQueryMixin.edns_options.append(_get_nsid_option()) query_class_mixin = CustomQueryMixin else: query_class_mixin = None name_objs = [] if '-r' in opts: cache = {} for name in names: if name.canonicalize().to_text() not in analysis_structured: logger.error('The domain name was not found in the analysis input: "%s"' % name.to_text()) continue name_objs.append(OnlineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) else: if '-t' in opts: a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, query_class_mixin, ceiling, edns_diagnostics, stop_at_explicit, cache_level, rdtypes, explicit_only, dlv_domain, processes) else: if cls.use_full_resolver: _init_full_resolver() else: _init_stub_resolver() a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, query_class_mixin, ceiling, edns_diagnostics, stop_at_explicit, cache_level, rdtypes, explicit_only, dlv_domain) if flush: fh.write('{') a.analyze(names, _flush) fh.write('"_meta._dnsviz.":%s}' % json.dumps(dnsviz_meta, **kwargs)) sys.exit(0) name_objs = a.analyze(names) name_objs = [x for x in name_objs if x is not None] if not name_objs: sys.exit(4) d = OrderedDict() for name_obj in name_objs: name_obj.serialize(d, meta_only) d['_meta._dnsviz.'] = dnsviz_meta try: fh.write(json.dumps(d, ensure_ascii=False, **kwargs).encode('utf-8')) except IOError as e: logger.error('Error writing analysis: %s' % e) sys.exit(3) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4) # tm is global (because of possible multiprocessing), so we need to # explicitly close it here finally: if tm is not None: tm.close()
def main(argv): try: test_pygraphviz() arghelper = build_helper(logger, sys.argv[0], argv[0]) arghelper.parse_args(argv[1:]) logger.setLevel(logging.WARNING) try: arghelper.check_args() arghelper.set_buffers() arghelper.aggregate_trusted_key_info() arghelper.ingest_input() arghelper.ingest_names() except argparse.ArgumentTypeError as e: arghelper.parser.error(str(e)) except AnalysisInputError as e: s = str(e) if s: logger.error(s) sys.exit(3) latest_analysis_date = None name_objs = [] cache = {} for name in arghelper.names: name_str = lb2s(name.canonicalize().to_text()) if name_str not in arghelper.analysis_structured or arghelper.analysis_structured[ name_str].get('stub', True): logger.error( 'The analysis of "%s" was not found in the input.' % lb2s(name.to_text())) continue name_obj = TTLAgnosticOfflineDomainNameAnalysis.deserialize( name, arghelper.analysis_structured, cache, strict_cookies=arghelper.args.enforce_cookies, allow_private=arghelper.args.allow_private) name_objs.append(name_obj) if latest_analysis_date is None or latest_analysis_date > name_obj.analysis_end: latest_analysis_date = name_obj.analysis_end if not name_objs: sys.exit(4) arghelper.update_trusted_key_info(latest_analysis_date) G = DNSAuthGraph() for name_obj in name_objs: name_obj.populate_status( arghelper.trusted_keys, supported_algs=arghelper.args.algorithms, supported_digest_algs=arghelper.args.digest_algorithms, validate_prohibited_algs=arghelper.args. validate_prohibited_algs) for qname, rdtype in name_obj.queries: if arghelper.args.rr_types is None: # if rdtypes was not specified, then graph all, with some # exceptions if name_obj.is_zone() and rdtype in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV): continue else: # if rdtypes was specified, then only graph rdtypes that # were specified if qname != name_obj.name or rdtype not in arghelper.args.rr_types: continue G.graph_rrset_auth(name_obj, qname, rdtype) if arghelper.args.rr_types is not None: for rdtype in arghelper.args.rr_types: if (name_obj.name, rdtype) not in name_obj.queries: logger.error( 'No query for "%s/%s" was included in the analysis.' % (lb2s(name_obj.name.to_text()), dns.rdatatype.to_text(rdtype))) if arghelper.args.derive_filename: if name_obj.name == dns.name.root: name = 'root' else: name = lb2s( name_obj.name.canonicalize().to_text()).rstrip('.') name = name.replace(os.sep, '--') finish_graph(G, [name_obj], arghelper.args.rr_types, arghelper.trusted_keys, arghelper.args.algorithms, '%s.txt' % name) G = DNSAuthGraph() if not arghelper.args.derive_filename: finish_graph(G, name_objs, arghelper.args.rr_types, arghelper.trusted_keys, arghelper.args.algorithms, arghelper.args.output_file.fileno()) except KeyboardInterrupt: logger.error('Interrupted.') sys.exit(4)
d = collections.OrderedDict() name_obj.serialize(d) s = json.dumps(d, **kwargs) lindex = s.index('{') rindex = s.rindex('}') fh.write(s[lindex+1:rindex]+',') dnsviz_meta = { 'version': DNS_RAW_VERSION, 'names': [n.to_text() for n in names] } flush = '-F' in opts name_objs = [] if '-r' in opts: cache = {} for name in names: if name.canonicalize().to_text() not in analysis_structured: logger.error('The domain name was not found in the analysis input: "%s"' % name.to_text()) continue 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, explicit_delegations, rdtypes, explicit_only, dlv_domain, th_factories, processes) else: a = cls(try_ipv4, try_ipv6, client_ipv4, client_ipv6, ceiling, edns_diagnostics, cache_level, explicit_delegations, rdtypes, explicit_only, dlv_domain, th_factories) if flush: fh.write('{') a.analyze(names, _flush) fh.write('"_meta._dnsviz.":%s}' % json.dumps(dnsviz_meta, **kwargs)) sys.exit(0) name_objs = a.analyze(names)