Beispiel #1
0
    def __init__(self, dns_ip):
        """Setup RecordChecker object.

        Args:
            dns_ip: DNS server IP to query.
        """
        self._dns_ip = dns_ip
        self._resolver = ProxyResolver()
        try:
            self._resolver.set_proxies([self._dns_ip])
        except async_dns.address.InvalidHost as e:
            msg = f'RecordChecker got invalid DNS server IP: {e}.'
            raise exceptions.InvalidDNSHost(msg)
Beispiel #2
0
async def dns_coroutine(domain, record_type, server):
    """
    Use async_dns to make a non-blocking DNS query to a given server for the
    desired record. Returns a dict with the various parameters of the response
    that we care about such as the value of the answers, number of answers,
    status code, etc

    Inputs:
        - domain        : str, name of domain
        - record_type   : str, record type
        - server        : list, server to query

    Returns:
        -res            : dict, details of the DNS response
    """
    res = {
        "answers": [],
        "ans_count": 0,
        "ttl": None,
        "rcode": None,
        "query_time": None,
        "flags": None,
    }
    # Testing shows that I need to create a new resolver object in the
    # coroutine and I cant just pass it in as an argument
    resolver = ProxyResolver()
    resolver.set_proxies(server)
    response = None
    retries = 0
    max_retries = 5
    while not response:
        retries += 1
        response = await resolver.query(domain, rrtype_codes[record_type])
        if retries > max_retries:
            return res
        if not response:
            await asyncio.sleep(5)

    res["rcode"] = response.r
    try:
        res["ttl"] = response.an[0].ttl
        for ans in response.an:
            res["answers"].append(ans.data)
            res["ans_count"] = res.get("ans_count", 0) + 1
    except IndexError:
        # This means that the field was empty and there were no answers
        # (possibly a SERVFAIL response)
        res["ans_count"] = 0
    return res
Beispiel #3
0
 def __init__(self, resolver=None, default_method='GET'):
     if resolver is None:
         from async_dns import get_nameservers
         from async_dns.resolver import ProxyResolver
         resolver = ProxyResolver(proxies=get_nameservers())
     self.resolver = resolver
     self.default_method = default_method
Beispiel #4
0
async def is_resolver_working(test_ip):
    # loop = asyncio.get_event_loop()
    resolver = ProxyResolver()
    resolver.set_proxies([
        test_ip,
    ])
    # res = loop.run_until_complete(resolver.query('www.baidu.com', types.A))

    res = await resolver.query('www.google.com', types.A)
    # print('scanning: %s' % test_ip)
    # print(res)
    if res and len(res.an) > 0:  # response is exists and have A-records in it
        # print(test_ip + ' is open resolver')
        # print(res)

        # this is works, 5000 thread size processed in 10 seconds. without redis - 5 seconds, delta is 5 seconds,
        # so it will be 0.1 sec to async redis call
        redis = await aioredis.create_redis(('localhost', 6379))
        await redis.rpush('resolvers', test_ip)
        redis.close()
        return True
    # print(test_ip + ' is NOT an open resolver')
    return False
Beispiel #5
0
async def start_dns_server(bind=':53',
                           enable_tcp=True,
                           enable_udp=True,
                           hosts=None,
                           proxies=None,
                           spf={}):
    '''Start a DNS server.'''

    cache = CacheNode()
    cache.add('1.0.0.127.in-addr.arpa',
              qtype=types.PTR,
              data='async-dns.local')
    cache.add('localhost', qtype=types.A, data='127.0.0.1')
    if hosts != 'none':
        for rec in parse_hosts_file(None if hosts == 'local' else hosts):
            cache.add(record=rec)
    if proxies is None:
        # recursive resolver
        resolver = Resolver(cache=cache, spf=spf)
    else:
        # proxy resolver
        # if proxy is falsy, default proxies will be used
        resolver = ProxyResolver(cache=cache, proxies=proxies, spf=spf)
    loop = asyncio.get_event_loop()
    host = Host(bind)
    urls = []
    if enable_tcp:
        server = await start_server(TCPHandler(resolver).handle_tcp, bind)
        urls.extend(get_server_hosts([server], 'tcp:'))
    else:
        server = None
    if enable_udp:
        hostname = host.hostname or '::'  # '::' includes both IPv4 and IPv6
        transport, _protocol = await loop.create_datagram_endpoint(
            lambda: DNSDatagramProtocol(resolver),
            local_addr=(hostname, host.port))
        urls.append(
            get_url_items([transport.get_extra_info('sockname')], 'udp:'))
    else:
        transport = None
    for line in repr_urls(urls):
        logger.info('%s', line)
    logger.info('%s started', resolver.name)
    return resolver, server, transport
Beispiel #6
0
async def get_dns_info(cli_args: argparse.Namespace, domain: str,
                       recursion_level: int, input_queue: asyncio.Queue):

    debug = cli_args.debug

    if cli_args.dns_resolver:
        dns_servers = [(None, cli_args.dns_resolver.split(","))]
    else:
        dns_servers = None
    try:
        resolver = ProxyResolver(proxies=dns_servers)
    except Exception as e:
        pass

    for _ in range(3):
        try:
            cname_response = await resolver.query(domain, types.CNAME)
        except Exception as e:
            if debug:
                print(f"[{PDE}] Error in 'get_dns_info': : {str(e)}")
            return

        try:
            for resp in cname_response.an:
                if resp.data and resp.qtype == types.CNAME:
                    print(
                        f"[{PD}] Found new CNAME. '{domain}' -> "
                        f"'{resp.data}'",
                        flush=True)

                    if message := valid_domain_or_link(resp.data):
                        print(message)
                        continue

                    await input_queue.put((resp.data, recursion_level - 1))

            break

        except AttributeError:
            await asyncio.sleep(1)
Beispiel #7
0
async def start_server(
    host='', port=53, protocol_classes=(DNSProtocol, DNSDatagramProtocol),
    hosts=None, resolve_protocol=UDP, proxies=None):
    '''Start a DNS server.'''

    if not isinstance(resolve_protocol, InternetProtocol):
        resolve_protocol = InternetProtocol.get(resolve_protocol)
    tcp_protocol, udp_protocol = protocol_classes
    cache = CacheNode()
    cache.add('1.0.0.127.in-addr.arpa', qtype=types.PTR, data='async-dns.local')
    cache.add('localhost', qtype=types.A, data='127.0.0.1')
    if hosts != 'none':
        for rec in parse_hosts_file(None if hosts == 'local' else hosts):
            cache.add(record=rec)
    if proxies is None:
        # recursive resolver
        resolver = Resolver(resolve_protocol, cache)
    else:
        # proxy resolver
        # if proxy is falsy, default proxies will be used
        resolver = ProxyResolver(resolve_protocol, cache, proxies=proxies)
    loop = asyncio.get_event_loop()
    if tcp_protocol:
        server = await loop.create_server(
            lambda: tcp_protocol(resolver), host, port)
    else:
        server = None
    transport_arr = []
    if udp_protocol:
        if host:
            host_arr = [host] if isinstance(host, str) else host
        else:
            host_arr = ['::'] # '::' means both IPv4 and IPv6
        for host_bind in host_arr:
            transport, protocol = await loop.create_datagram_endpoint(
                lambda: udp_protocol(resolver),
                local_addr=(host_bind, port))
            transport_arr.append(transport)
    return server, transport_arr, resolver
Beispiel #8
0
import asyncio
from async_dns import types
from async_dns.resolver import ProxyResolver
"""loop = asyncio.get_event_loop()
resolver = ProxyResolver()
res = loop.run_until_complete(resolver.query('www.baidu.com', types.A))
print(res)"""

resolver = ProxyResolver()
res = resolver.query('www.baidu.com', types.A)
print(res)
Beispiel #9
0
class RecordChecker(object):
    def __init__(self, dns_ip):
        """Setup RecordChecker object.

        Args:
            dns_ip: DNS server IP to query.
        """
        self._dns_ip = dns_ip
        self._resolver = ProxyResolver()
        try:
            self._resolver.set_proxies([self._dns_ip])
        except async_dns.address.InvalidHost as e:
            msg = f'RecordChecker got invalid DNS server IP: {e}.'
            raise exceptions.InvalidDNSHost(msg)

    def _extract_record_data(self, record):
        """Extract record data from a record dict.

        Args:
            record (dict): DNS record as a dict.

        Returns:
            The record data: name, rrdata, type and ttl.
        """
        return record.values()

    async def check_record(self, record, timeout=60):
        """Measures the time for a DNS record to become available.

        Query a provided DNS server multiple times until the reply matches the
        information in the record or until timeout is reached.

        Args:
            record (dict): DNS record as a dict with record properties.
            timeout (int): Time threshold to query the DNS server.
        """
        start_time = time.time()

        name, rr_data, r_type, ttl = self._extract_record_data(record)
        r_type_code = async_dns.types.get_code(r_type)

        resolvable_record = False
        retries = 0
        sleep_time = 5

        while not resolvable_record and \
                timeout > retries * sleep_time:

            retries += 1
            resolver_res = await self._resolver.query(name, r_type_code)
            possible_ans = resolver_res.an

            resolvable_record = \
                await self._check_resolver_ans(possible_ans, name,
                                               rr_data, ttl, r_type_code)

            if not resolvable_record:
                await asyncio.sleep(sleep_time)

        if not resolvable_record:
            logging.info(f'Sending metric record-checker-failed: {record}.')
        else:
            final_time = float(time.time() - start_time)
            success_msg = (f'This record: {record} took {final_time} to '
                           'register.')
            logging.info(success_msg)

    async def _check_resolver_ans(self, dns_answer_list, record_name,
                                  record_data_list, record_ttl,
                                  record_type_code):
        """Check if resolver answer is equal to record data.

        Args:
            dns_answer_list (list): DNS answer list contains record objects.
            record_name (str): Record name.
            record_data_list (list): List of data values for the record.
            record_ttl (int): Record time-to-live info.
            record_type_code (int): Record type code.

        Returns:
            boolean indicating if DNS answer data is equal to record data.
        """
        type_filtered_list = [
            ans for ans in dns_answer_list if ans.qtype == record_type_code
        ]

        # check to see that type_filtered_lst has
        # the same number of records as record_data_list
        if len(type_filtered_list) != len(record_data_list):
            return False

        # check each record data is equal to the given data
        for rec in type_filtered_list:
            conditions = [
                rec.name == record_name, rec.ttl == record_ttl, rec.data
                in record_data_list
            ]

            # if ans record data is not equal
            # to the given data return False
            if not all(conditions):
                return False

        return True
Beispiel #10
0
 def test_query(self):
     loop = asyncio.get_event_loop()
     resolver = ProxyResolver()
     res = loop.run_until_complete(resolver.query('www.baidu.com', types.A))
     self.assertTrue(res.an)
Beispiel #11
0
async def main():
    parser = OptionParser()
    parser.add_option("-f",
                      "--file",
                      dest="targets_file",
                      help="file containning names to resolve")
    parser.add_option("-r",
                      "--resolvers",
                      dest="resolvers_file",
                      help="file containning names to resolve")
    parser.add_option('-t',
                      '--types',
                      action="append",
                      default=[],
                      help='query types, default as `any`')
    parser.add_option("-v",
                      "--verbose",
                      action="store_true",
                      dest="verbose",
                      default=False,
                      help="print INFO level messages to stdout")
    parser.add_option("-w",
                      "--workers",
                      type=int,
                      default=128,
                      dest="workers",
                      help="number of async workers (default: 128)")
    parser.add_option("-d",
                      "--debug",
                      action="store_true",
                      dest="debug",
                      default=False,
                      help="print DEBUG level messages to stdout")

    (options, _) = parser.parse_args()

    if options.verbose:
        logging.basicConfig(level=logging.INFO)
    elif options.debug:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.WARNING)

    targets = []
    with open(options.targets_file, 'r') as targets_file:
        targets = [line.strip() for line in targets_file.readlines()]

    resolver = ProxyResolver()
    with open(options.resolvers_file, 'r') as resolvers_file:
        resolver.set_proxies(
            [line.strip() for line in resolvers_file.readlines()])
    logging.info(f"Loaded {len(resolver.ns_pairs[0][1].data)} resolvers")
    logging.debug(resolver.ns_pairs[0][1].data)

    if len(options.types) == 0:
        options.types = ['A']

    args_list = []
    for target in targets:
        for qtype_name in options.types:
            qtype = types.get_code(qtype_name.upper())
            if qtype is None:
                logging.warn('Unknown type: %s', qtype_name)
                continue
            args_list.append({
                'resolver': resolver,
                'hostname': target,
                'qtype': qtype
            })

    # tasks = []
    # logging.debug(f'# OF TASKS: {len(args_list)}')
    # for args in args_list:
    #     task = asyncio.create_task(resolve_hostname(**args))
    #     tasks.append(task)

    input_queue = asyncio.Queue(maxsize=len(args_list))

    workers = []
    for _ in range(0, options.workers):
        worker = asyncio.create_task(consumer(input_queue))
        workers.append(worker)

    for args in args_list:
        await input_queue.put(args)

    await input_queue.join()