Exemplo n.º 1
0
def get_name_server_ips(name_servers: []) -> {}:
    """
    Get the ips of the given domain names

    :param name_servers:
    :return: dictl keys are the items in the passed list, the values are the IPs (4 and 6) of the key
    """
    result = {}
    if not name_servers:
        return result
    for name_server in name_servers:
        ns_results = []
        a_results = safe_query(name_server, 'a')
        if a_results:
            ns_results += a_results
        aaaa_results = safe_query(name_server, 'aaaa')
        if aaaa_results:
            ns_results += aaaa_results
        result[name_server] = ns_results

    return result
Exemplo n.º 2
0
def _get_redirect_record(record):
    record = record.replace('"', '')
    parts = record.split(' ')
    for part in parts:
        if part.startswith('redirect='):
            sub = part.split('=')
            if len(sub) == 2:
                ans = safe_query(sub[1], 'txt')
                if ans:
                    for r in ans:
                        if r.startswith('"v=spf'):
                            return r
    return ''
Exemplo n.º 3
0
def site_stat(site_id: int, run_id: int):
    logger.debug('start site stat site {} run id {}'.format(site_id, run_id))
    result = dict()
    result['start_time'] = datetime.datetime.now()
    site = db_session.query(models.Site).filter(models.Site.id == site_id).scalar()
    logger.debug('got site for {}'.format(site.domain))
    result['mx'] = dnutils.safe_query(site.domain, 'mx')
    logger.debug('got mx for {}'.format(site.domain))
    result['txt'] = dnutils.safe_query(site.domain, 'txt')
    logger.debug('got txtf or {}'.format(site.domain))
    result['caa'] = dnutils.safe_query(site.domain, 'caa')
    logger.debug('got caa for {}'.format(site.domain))
    result['ds'] = dnutils.safe_query(site.domain, 'ds')
    result['dnskey'] = dnutils.safe_query(site.domain, 'dnskey')
    logger.debug('got dnskey for {}'.format(site.domain))
    result['ns'] = dnutils.safe_query(site.domain, 'ns')
    logger.debug('got ns')
    result['dmarc'] = dnutils.safe_query('_dmarc.' + site.domain, 'txt')
    logger.debug('got dmarc for {}'.format(site.domain))
    result['has_dnssec'] = None
    logger.debug('got security.txt for {}'.format(site.domain))
    result['is_msdcs'] = dnstats.dnsutils.is_a_msft_dc(site.domain)
    logger.debug('got has msdc for {}'.format(site.domain))
    result['site_id'] = site.id
    logger.debug('set site id {}'.format(site.domain))
    result['rank'] = site.current_rank
    logger.debug('set rank {}'.format(site.domain))
    result['run_id'] = run_id
    logger.debug('set run id {} -- done'.format(site.domain))
    result['name_server_ips'] = get_name_server_ips(result['ns'])
    logger.debug('got the IP addresses for all the name servers')
    result['ns_server_ns_results'] = get_name_server_results(result['name_server_ips'], site.domain)
    logger.debug('got name server results from each name server')
    result['soa'] = dnutils.safe_query(site.domain, 'soa')
    logger.debug('got soa for {}'.format(site.domain))
    result['bimi'] = dnutils.safe_query('default._bimi.{}'.format(site.domain), 'txt')
    logger.debug('got bimi records %', site.domain)
    result['end_time'] = datetime.datetime.now()
    return result
Exemplo n.º 4
0
def test(site: str):
    ans = safe_query(site, 'mx')
    print(get_provider_from_mx_records(ans, site))
Exemplo n.º 5
0
def _validate_spf(spf: str, domain: str) -> {}:
    errors = list()
    if not spf.startswith('v=spf1 '):
        errors.append(SpfError.INVALID_RECORD_START)
    parts = spf.split(' ')
    parts_to_consider = list()
    parts_to_consider.extend(parts)
    count = 1
    inter = 0
    result = dict()
    end_again = False
    start_again = False
    for part in parts_to_consider:
        # Ignore whitespace
        if not part:
            break
        inter += 1
        if count >= 10:
            errors.append(SpfError.TOO_MANY_DNS_LOOKUPS)
            break
    # START Mechanisms as defined in RFC 7208 Sec. 5
        if part.startswith('all'):
            # TODO: check for others and reduce grade if others mechanism are after (RFC 7209 5.1)
            result['errors'] = errors
            return result
        elif part.startswith('include'):
            count += 1
            sub_parts = part.split(':')
            if len(sub_parts) != 2:
                errors.append(SpfError.INVALID_INCLUDE_FORMAT)
                break
        elif part.startswith('a'):
            count += 1
            a_result = safe_query(domain, 'a')
            if not a_result:
                errors.append(SpfError.NO_A_RECORDS_IN_MECHANISM)
                break
            if len(a_result) > 10:
                errors.append(SpfError.TOO_MANY_A_RECORDS_RETURNED)
                break
            # TODO: Process if this mech has :
        elif part.startswith('mx'):
            count += 1
            mx_result = safe_query(domain, 'mx')
            if not mx_result:
                errors.append(SpfError.NO_MX_RECORDS)
                continue
            if not mx_result:
                errors.append(SpfError.NO_MX_RECORDS_IN_MECHANISM)
                break
            if len(mx_result) > 10:
                errors.append(SpfError.TOO_MANY_MX_RECORDS_RETURNED)
                break
            # TODO: Process if this mech has :
        elif part.startswith('ip4'):
            ip = part.split(':', 1)
            try:
                if len(ip) < 2:
                    errors.append(SpfError.INVALID_IPV4_MECHANISM)
                    break
                ip_parts = ip[1].split('/', 1)
                if len(ip_parts) > 1:
                    if not ipaddress.IPv4Network(ip[1]).is_global:
                        errors.append(SpfError.INVALID_IPV4_MECHANISM)
                        break
                else:
                    if not ipaddress.IPv4Network(ip[1],
                                                 strict=False).is_global:
                        errors.append(SpfError.INVALID_IPV4_MECHANISM)
                        break
            except ipaddress.NetmaskValueError:
                errors.append(SpfError.INVALID_IPV4_CIDR)
            except ipaddress.AddressValueError:
                errors.append(SpfError.INVALID_IPV4_VALUE)
            except:
                errors.append(SpfError.INVALID_IPV6_MECHANISM)

        elif part.startswith('ip6'):
            ip = part.split(':', 1)
            if len(ip) < 2:
                errors.append(SpfError.INVALID_IPV6_MECHANISM)
                break
            ip_parts = ip[1].split('/', 1)
            try:
                if len(ip_parts) > 1:
                    if not ipaddress.IPv6Network(ip[1]).is_global:
                        errors.append(SpfError.INVALID_IPV6_MECHANISM)
                        break
                else:
                    if not ipaddress.IPv6Address(ip[0]).is_global:
                        errors.append(SpfError.INVALID_IPV6_VALUE)
                        break
            except ipaddress.NetmaskValueError:
                errors.append(SpfError.INVALID_IPV6_CIDR)
            except ipaddress.AddressValueError:
                errors.append(SpfError.INVALID_IPV6_VALUE)
            except:
                errors.append(SpfError.INVALID_IPV6_MECHANISM)
        elif part.startswith('ptr'):
            # Count as one DNS query. No way to valid this without an email
            count += 1
            errors.append(SpfError.HAS_PTR)
            # RFC 7208 states "ptr (do not use)"
        elif part.startswith('exists'):
            # We don't need to valid the name exists, as not existing is a valid part of the flow
            count += 1
    # END Mechanisms as defined in RFC 7208 Sec. 5
    # START Modifiers as defined in RFC 7208 Sec. 6
        elif part.startswith('redirect'):
            sub_parts = part.split('=')
            if len(sub_parts) != 2:
                errors.append(SpfError.INVALID_REDIRECT_MECHANISM)
                break
            # TODO: check if valid DNS Name
            if len(sub_parts) == 2:
                redirect_query = safe_query(sub_parts[1], 'txt')
                if redirect_query is None or len(redirect_query):
                    errors.append(SpfError.INVALID_REDIRECT_MECHANISM)
                has_spf = False
                for record in redirect_query:
                    record = record.replace('"', '')
                    if record.startswith('v=spf1 '):
                        if not has_spf:
                            for spf_part in record.split(' '):
                                parts_to_consider.append(spf_part)
                            has_spf = True
                if not has_spf:
                    errors.append(SpfError.NO_RECORD_AT_REDIRECT)
            else:
                errors.append(SpfError.INVALID_REDIRECT_MECHANISM)
            count += 1
        elif part.startswith('exp='):
            pass
        elif part.startswith('unknown-modifier='):
            pass
        elif part.endswith('all'):
            if end_again:
                errors.append(SpfError.TOO_MANY_ENDINGS)
            end_again = True
            pass
        elif part.startswith('v='):
            if start_again:
                errors.append(SpfError.TOO_MANY_STARTS)
            sub_parts = part.split('=')
            if sub_parts[1] != 'spf1':
                errors.append(SpfError.INVALID_RECORD_START)
                break
            start_again = True
        else:
            errors.append(SpfError.INVALID_MECHANISM)
            # TODO: account for new modifiers
            break
    # END Modifiers as defined in RFC 7208 Sec. 6

    result['errors'] = errors
    return result