Пример #1
0
    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))
Пример #2
0
    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
Пример #3
0
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)
Пример #4
0
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)
Пример #5
0
        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)
Пример #6
0
        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)
Пример #7
0
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)
Пример #8
0
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)
Пример #9
0
            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
Пример #10
0
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)
Пример #11
0
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)
Пример #12
0
                    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)