def _get(self, request, name_obj, timestamp, url_subdir, date_form): options_form, values = get_dnssec_options_form_data(request.GET) use_js = 'no_js' not in request.GET if use_js: notices = {} else: rdtypes = set(values['rr']) denial_of_existence = values['doe'] dnssec_algorithms = set(values['a']) ds_algorithms = set(values['ds']) trusted_keys_explicit = values['tk'] trusted_zones = values['ta'] redundant_edges = values['red'] # disable IANA root keys, if there is an explicit delegation of the root # (i.e., ignore root KSK ta setting) if name_obj.group is not None and name_obj.group.name == dns.name.root and \ name_obj.group.analysis_type == ANALYSIS_TYPE_AUTHORITATIVE and name_obj.group.explicit_delegation: trusted_zones = filter(lambda x: x[0] != dns.name.root, trusted_zones) if '.' in options_form.fields['ta'].initial: options_form.fields['ta'].initial.remove('.') trusted_keys = trusted_keys_explicit + trusted_zones G = DNSAuthGraph() name_obj.retrieve_all() name_obj.populate_status(trusted_keys, supported_algs=dnssec_algorithms, supported_digest_algs=ds_algorithms) G = self._graph_name(name_obj, trusted_keys, rdtypes, denial_of_existence) G.add_trust(trusted_keys, supported_algs=dnssec_algorithms) #G.remove_extra_edges(redundant_edges) notices = get_notices(G.node_info) analyzed_name_obj = name_obj template = 'dnssec.html' return render_to_response(template, { 'name_obj': name_obj, 'analyzed_name_obj': analyzed_name_obj, 'timestamp': timestamp, 'url_subdir': url_subdir, 'title': name_obj, 'options_form': options_form, 'date_form': date_form, 'notices': notices, 'use_js': use_js, 'query_string': request.META['QUERY_STRING'] }, context_instance=RequestContext(request))
def _graph_name(self, name_obj, trusted_keys, rdtypes, denial_of_existence): G = DNSAuthGraph() if not name_obj.zone.get_responsive_auth_or_designated_servers(): G.graph_zone_auth(name_obj.zone, False) self._graph_dane_related_name(G, name_obj, trusted_keys, rdtypes, denial_of_existence) # get names/types queried in conjunction with the analysis, other than # DNSSEC-related types and those not explicitly requested in the options # form. qnamestypes = set( filter( lambda x: x[1] not in (dns.rdatatype.DNSKEY, dns.rdatatype.DS, dns.rdatatype.DLV) and x[1] in rdtypes, name_obj.queries)) # if no qnames/qtypes resulted, it is possible that this is the result of # an NXDOMAIN found by querying for the referral_rdtype, which might not have # been among the rdtypes explicitly requested for view. if not qnamestypes and name_obj.referral_rdtype is not None and name_obj.queries[ (name_obj.name, name_obj.referral_rdtype)].is_nxdomain_all(): qnamestypes.add((name_obj.name, name_obj.referral_rdtype)) # if denial of existence was not specified, don't include the explicit # nxdomain/nxrrset queries if not denial_of_existence: qnamestypes.difference_update([ (name_obj.nxdomain_name, name_obj.nxdomain_rdtype), (name_obj.nxrrset_name, name_obj.nxrrset_rdtype) ]) # identify queries with positive responses, negative responses or error responses pos_namestypes = name_obj.yxrrset.intersection(qnamestypes) neg_namestypes = name_obj.nxrrset.intersection(qnamestypes) err_namestypes = set( filter(lambda x: name_obj.queries[x].error_info, qnamestypes)) # if denial_of_existence is selected, then graph everything if denial_of_existence: qnamestypes_to_graph = qnamestypes else: # otherwise graph only positive responses and errors not associated # with negative responses qnamestypes_to_graph = pos_namestypes.union( err_namestypes.difference(neg_namestypes)) # if nothing matches, then graph everything if not qnamestypes_to_graph: qnamestypes_to_graph = qnamestypes for qname, rdtype in qnamestypes_to_graph: G.graph_rrset_auth(name_obj, qname, rdtype) return G
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): 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)
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 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)
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) d = collections.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)
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 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)
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 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
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)
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)
name.to_text()) continue name_objs.append( OfflineDomainNameAnalysis.deserialize(name, analysis_structured, cache)) if not name_objs: sys.exit(4) d = collections.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)