Esempio n. 1
0
    def cloak(self, request, handler):

        domain = GetDomainNameFromRequest(request)

        for rule in self.cloakrules:
            if rule.search(domain):

                reply = request.reply()

                # Return an A record if target is IPV4 address
                if rule.targetIsIp4():
                    reply.add_answer(
                        RR(request.questions[0].qname,
                           rtype=QTYPE.A,
                           rdata=dnslib.A(rule.target),
                           ttl=self.DEFAULT_TTL))
                    return reply

                # Add a CNAME if the target domain is different
                if domain != rule.target:
                    reply.add_answer(
                        RR(request.questions[0].qname,
                           rtype=QTYPE.CNAME,
                           rdata=dnslib.CNAME(rule.target),
                           ttl=self.DEFAULT_TTL))

                subquery = DNSRecord.question(rule.target)
                subresp = self.upstream_resolve(subquery, handler)

                for record in subresp.rr:
                    reply.add_answer(record)

                return reply
Esempio n. 2
0
def pack_dns(dns, answers, soa=None):
    def content_type(x):
        #  valid ip
        if socket.inet_aton(x):
            return 'A'
        else:
            return 'CNAME'

    if answers:
        for ans in answers:
            # logger.info('ans ' + ans)
            if content_type(ans[1]) == 'A':
                dns.add_answer(
                    dnslib.RR(ans[0], dnslib.QTYPE.A, rdata=dnslib.A(ans[1])))
            elif content_type(ans[1]) == 'CNAME':
                dns.add_answer(
                    dnslib.RR(ans[0],
                              dnslib.QTYPE.CNAME,
                              rdata=dnslib.CNAME(ans[1])))
    elif soa:
        soa_content = soa[1].split()
        dns.add_auth(
            dnslib.RR(soa[0],
                      dnslib.QTYPE.SOA,
                      rdata=dnslib.SOA(soa_content[0], soa_content[1],
                                       (int(i) for i in soa_content[2:]))))
    return dns
Esempio n. 3
0
 def pack_dns(self, dns, answers, soa=None):
     content_type = lambda x: 'A' if re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', x) else 'CNAME'
     if answers:
         for ans in answers:
             if content_type(ans[1]) == 'A':
                 dns.add_answer(dnslib.RR(ans[0], dnslib.QTYPE.A, rdata=dnslib.A(ans[1])))
             elif content_type(ans[1]) == 'CNAME':
                 dns.add_answer(dnslib.RR(ans[0], dnslib.QTYPE.CNAME, rdata=dnslib.CNAME(ans[1])))
     elif soa:
         soa_content = soa[1].split()
         dns.add_auth(dnslib.RR(soa[0], dnslib.QTYPE.SOA,
                                rdata=dnslib.SOA(soa_content[0], soa_content[1], (int(i) for i in soa_content[2:]))))
 
     return dns
def test_on_upstream_response_not_A(greendns):
    qname = "www.microsoft.com"
    qresult = "www.microsoft.com-c-2.edgekey.net."
    s = init_greendns_session(greendns, qname, dnslib.QTYPE.CNAME)
    res = dnslib.DNSRecord(dnslib.DNSHeader(qr=1, aa=1, ra=1),
                           q=dnslib.DNSQuestion(qname),
                           a=dnslib.RR(qname,
                                       rtype=dnslib.QTYPE.CNAME,
                                       rdata=dnslib.CNAME(qresult),
                                       ttl=3))
    s.server_resps[local_dns1] = bytes(res.pack())
    resp = greendns.on_upstream_response(s, local_dns1)
    assert resp
    d = dnslib.DNSRecord.parse(resp)
    assert str(d.rr[0].rdata) == qresult
Esempio n. 5
0
def _cname_search(record, rr_list, auth_list, addi_list):
    """
    Searches and adds any CNAME records for the domain.
    :param record: Overall record for domain
    :param rr_list: Current record list for the domain
    :param auth_list: Authority list for the domain
    :param addi_list: Additional list for the domain
    """
    try:
        cname_record = record["CNAME"]
        ttl = int(cname_record["ttl"])
        rr_list.append(dnslib.RR(rname = record["domain"],
                                 rtype = dnslib.QTYPE.CNAME,
                                 rdata = dnslib.CNAME(label = cname_record["domain"]),
                                 ttl   = ttl))
        _add_authority(record["domain"], auth_list)
        _add_additional(addi_list)
    except:
        pass
def test_shuffer_A(greendns):
    qname = "qq.com"
    id = 1024
    s = init_greendns_session(greendns, qname, dnslib.QTYPE.A, id)
    res = dnslib.DNSRecord(dnslib.DNSHeader(qr=1, aa=1, ra=1),
                           q=dnslib.DNSQuestion(qname),
                           a=dnslib.RR(qname,
                                       dnslib.QTYPE.CNAME,
                                       rdata=dnslib.CNAME("https.qq.com"),
                                       ttl=3))
    res.add_answer(dnslib.RR(qname, rdata=dnslib.A("101.226.103.106"), ttl=3))
    res.add_answer(dnslib.RR(qname, rdata=dnslib.A("101.226.103.107"), ttl=3))
    greendns.cache.add(("qq.com.", 1), res, 3)
    d = None
    for i in range(10):
        is_continue, raw_resp = greendns.on_client_request(s)
        assert not is_continue
        assert raw_resp
        d = dnslib.DNSRecord.parse(raw_resp)
        if str(d.rr[1].rdata) == "101.226.103.107":
            break
    assert d.rr[0].rtype == dnslib.QTYPE.CNAME
    assert str(d.rr[1].rdata) == "101.226.103.107"
Esempio n. 7
0
def py3dns(serverip='', serverport=0):
    class DNSify(str):
        def __getattr__(self, item):
            return DNSify(item + '.' + self)

    def get_lan_ip4(forcelocalhost=False):
        if forcelocalhost: return '127.0.0.1'
        s = dnslib.socket.socket(dnslib.socket.AF_INET,
                                 dnslib.socket.SOCK_DGRAM)
        try:
            s.connect(('10.255.255.255', 0))
            IP = s.getsockname()[0]
        except:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP

    def is_domain_blacklisted(sqname, domain_blacklist):
        for test_domain in domain_blacklist:
            if test_domain in sqname:
                return True
        return False

    # Init server settings
    killcommand = 'stop.py3dns.now'
    serve_forever = True
    udp_buffer_size = 1024
    server_name = dnslib.socket.getfqdn()
    server_ip = get_lan_ip4()
    if serverip: server_ip = serverip
    reverse_server_ip = '.'.join(reversed(
        server_ip.split('.'))) + '.in-addr.arpa'
    server_port = 53
    if serverport: server_port = int(serverport)
    server_protocol = 'UDP'
    public_dns_resolvers = [
        '91.239.100.100', '89.233.43.71', '8.8.8.8', '8.8.4.4'
    ]

    # Init simple host cache
    host_cache = {}
    host_cache[server_ip] = server_name

    # Init blacklists
    use_blacklists = True
    domain_blacklist = make_domain_blacklist()
    ipaddr_blacklist = make_ipaddr_blacklist()
    rpz_domain = DNSify('getthefuckaway.net')
    rpz_ip4 = '10.20.30.40'
    rpz_ip6 = '10:20:30:40:50:60:70:80'

    # Init UDP socket server
    udpsrv = dnslib.socket.socket(dnslib.socket.AF_INET,
                                  dnslib.socket.SOCK_DGRAM)
    udpsrv.bind((server_ip, server_port))
    udpsrv.setblocking(False)

    # Init external resolvers
    external_resolver = dns.resolver.Resolver()
    external_resolver_cache = dns.resolver.Cache(cleaning_interval=600.0)
    external_resolver.cache = external_resolver_cache
    external_resolver.nameservers = public_dns_resolvers
    external_resolver.retry_servfail = False
    external_resolver.port = 53
    ##external_resolver.timeout = 1.0
    ##external_resolver.lifetime = 2.0

    # Timestamp UTC
    now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')

    # App Header
    print('+' + ('-' * 71))
    print('| PY3DNS v/1.0 by BikerDroid')
    print('+' + ('-' * 71))
    print('| Server    :', server_name)
    print('| Address   :', server_ip)
    print('| Port Used :', server_port)
    print('| Protocol  :', server_protocol)
    print('| Recv Size :', udp_buffer_size, 'bytes')
    print('| Solvers   :',
          str(public_dns_resolvers).strip("[]").replace("'", ""))
    print('+' + ('-' * 71))
    print('| Stop PY3DNS by sending "nslookup ' + killcommand + ' ' +
          server_ip + '"')
    print('+' + ('-' * 71))
    print(now, ': Ready to serve...')

    # Main Loop
    while serve_forever:

        # Clear vars
        sres = sip4 = sip6 = smx = scname = sns = stxt = sptr = ssoa = sany = hostip = ''

        # Main: Get client request, add hostip and host name to host_cache
        try:
            data, addr = udpsrv.recvfrom(udp_buffer_size)
            hostip = str(addr[0])
            if not hostip in host_cache:
                host_cache[hostip] = dnslib.socket.getfqdn(
                    str(dnslib.socket.gethostbyaddr(hostip)[0]))
            now = datetime.datetime.utcnow().strftime(
                '%Y-%m-%d %H:%M:%S.%f')  # UTC
        except:
            continue

        # Client request -> id, qname (domain), qtype (A,AAAA,MX etc)
        request = dnslib.DNSRecord.parse(data)
        qid = request.header.id
        qname = request.q.qname
        qtype = request.q.qtype
        slabel = str(qname.label)
        sqname = str(qname)
        sqtype = str(dnslib.QTYPE[qtype])

        # Rem this line if rpz_domain is to overwrite
        # blacklisted domains with their real names.
        sdomain = sqname

        # Dirty trick to shut down server from commandline:
        # Syntax : nslookup stop.dns.srv <server_ip>
        # Example: nslookup stop.dns.srv 127.0.0.1
        # Must be before external_resolver.query()
        if sqname.rstrip('.') == killcommand:
            serve_forever = False
            continue

        # Dirty Reverse Lookup of local server
        # Allows requesting client to get server_name
        if qtype == dnslib.QTYPE.PTR:
            if sqname.rstrip('.') == reverse_server_ip:
                reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid,
                                                                 qr=1,
                                                                 aa=1,
                                                                 ra=1,
                                                                 rcode=0),
                                         q=dnslib.DNSQuestion(sqname,
                                                              qtype)).reply()
                reply.add_answer(
                    dnslib.RR(sqname,
                              dnslib.QTYPE.PTR,
                              rdata=dnslib.PTR(server_name),
                              ttl=3600))
                udpsrv.sendto(reply.pack(), addr)
                print(now, ':', sqname, '|', sqtype, '=', qtype, '|',
                      server_name, '|', hostip, '=', host_cache[hostip])
                continue

        # Get DNS record from public_dns_resolvers.
        # This section can be changed to serve from
        # own database, stationary files or similar.
        try:
            if not sqname.rstrip('.') in domain_blacklist:
                external_resolver_result = external_resolver.query(
                    sqname.rstrip('.'), sqtype)
            found = True
        except:
            print(now, '> qtype', sqtype,
                  '(' + str(qtype) + ') was not found for', sqname)
            external_resolver_result = []
            sres = sip4 = sip6 = ''
            found = False

        if not found:
            # Create DNSRecord Header reply: rcode = 5 (Query Refused). See RFC2136 for rcode's.
            reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid,
                                                             qr=1,
                                                             aa=1,
                                                             ra=1,
                                                             rcode=5),
                                     q=dnslib.DNSQuestion(sdomain,
                                                          qtype)).reply()
        else:

            # Create DNSRecord Header reply: rcode = 0 (No Error)
            reply = dnslib.DNSRecord(header=dnslib.DNSHeader(id=qid,
                                                             qr=1,
                                                             aa=1,
                                                             ra=1,
                                                             rcode=0),
                                     q=dnslib.DNSQuestion(sdomain,
                                                          qtype)).reply()

            # Add A record answer for domain and IP
            # Filter blacklisted IP4/6 addresses.
            if qtype == dnslib.QTYPE.A:
                if is_domain_blacklisted(
                        sqname.rstrip('.'),
                        domain_blacklist):  # Simple domain blacklist check
                    sres = sip4 = rpz_ip4
                    reply.add_answer(
                        dnslib.RR(sdomain,
                                  dnslib.QTYPE.A,
                                  rdata=dnslib.A(sip4),
                                  ttl=60))
                else:
                    for data in external_resolver_result:
                        sres = sip4 = str(data).strip()
                        if sip4:
                            if sip4 in ipaddr_blacklist:  # Simple IP (4+6) blacklist check
                                sres = sip4 = rpz_ip4
                            reply.add_answer(
                                dnslib.RR(sdomain,
                                          dnslib.QTYPE.A,
                                          rdata=dnslib.A(sip4),
                                          ttl=60))

            # Add AAAA record answer for domain and IP
            # Filter blacklisted IP4/6 addresses.
            elif qtype == dnslib.QTYPE.AAAA:
                if is_domain_blacklisted(
                        sqname.rstrip('.'),
                        domain_blacklist):  # Simple domain blacklist check
                    sres = sip6 = rpz_ip6
                    reply.add_answer(
                        dnslib.RR(sdomain,
                                  dnslib.QTYPE.AAAA,
                                  rdata=dnslib.AAAA(sip6),
                                  ttl=60))
                else:
                    for data in external_resolver_result:
                        sres = sip6 = str(data).strip()
                        if sip6:
                            if sip6 in ipaddr_blacklist:  # Simple IP (4+6) blacklist check
                                sres = sip6 = rpz_ip6
                            reply.add_answer(
                                dnslib.RR(sdomain,
                                          dnslib.QTYPE.AAAA,
                                          rdata=dnslib.AAAA(sip6),
                                          ttl=60))

            # Add NS record answer for domain
            elif qtype == dnslib.QTYPE.NS:
                for data in external_resolver_result:
                    sres = sns = str(data).strip()
                    if sns:
                        reply.add_answer(
                            dnslib.RR(sdomain,
                                      dnslib.QTYPE.NS,
                                      rdata=dnslib.NS(sns),
                                      ttl=60))

            # Add MX record answer for domain and IP
            elif qtype == dnslib.QTYPE.MX:
                for data in external_resolver_result:
                    sres = smx = str(data).strip()
                    if smx:
                        reply.add_answer(
                            dnslib.RR(sdomain,
                                      dnslib.QTYPE.MX,
                                      rdata=dnslib.MX(smx),
                                      ttl=60))

            # Add CNAME record answer for domain
            elif qtype == dnslib.QTYPE.CNAME:
                for data in external_resolver_result:
                    sres = scname = str(data).strip()
                    if scname:
                        reply.add_answer(
                            dnslib.RR(sdomain,
                                      dnslib.QTYPE.CNAME,
                                      rdata=dnslib.CNAME(scname),
                                      ttl=60))

            # Add TXT record answer for domain
            elif qtype == dnslib.QTYPE.TXT:
                for data in external_resolver_result:
                    sres = stxt = str(data).strip()
                    if stxt:
                        reply.add_answer(
                            dnslib.RR(sdomain,
                                      dnslib.QTYPE.TXT,
                                      rdata=dnslib.TXT(stxt),
                                      ttl=60))

            # Add PTR record answer for domain
            elif qtype == dnslib.QTYPE.PTR:
                for data in external_resolver_result:
                    sres = sptr = str(data).strip()
                    if sptr:
                        reply.add_answer(
                            dnslib.RR(sdomain,
                                      dnslib.QTYPE.PTR,
                                      rdata=dnslib.PTR(sptr),
                                      ttl=60))

            # Add ANY record answer for domain
            elif qtype == dnslib.QTYPE.ANY:
                for data in external_resolver_result:
                    sres = sany = str(data).strip()
                    if sany:
                        reply.add_answer(
                            dnslib.RR(sdomain,
                                      dnslib.QTYPE.ANY,
                                      rdata=dnslib.ANY(sany),
                                      ttl=60))

            # Add SOA record answer for domain
            elif qtype == dnslib.QTYPE.SOA:
                for data in external_resolver_result:
                    if str(data).strip():
                        soa_data = str(data).strip().split(' ')
                        soa_mname = soa_data[0]
                        soa_rname = soa_data[1]
                        soa_serial = soa_data[2]
                        soa_refresh = soa_data[3]
                        soa_retry = soa_data[4]
                        soa_expire = soa_data[5]
                        soa_minimum = soa_data[6]
                        soa_time = (int(soa_serial), int(soa_refresh),
                                    int(soa_retry), int(soa_expire),
                                    int(soa_minimum))
                        sres = soa_mname + ',' + soa_rname + ',' + soa_serial + ',' + soa_refresh + ',' + soa_retry + ',' + soa_expire + ',' + soa_minimum
                        reply.add_answer(
                            dnslib.RR(sdomain,
                                      dnslib.QTYPE.SOA,
                                      rdata=dnslib.SOA(soa_mname, soa_rname,
                                                       soa_time),
                                      ttl=60))
            else:
                # Unknown qtype - add CNAME as answer :)
                reply.add_answer(
                    dnslib.RR(qname,
                              dnslib.QTYPE.CNAME,
                              rdata=dnslib.CNAME(server_name),
                              ttl=60))

        # Send DNS reply to client address using UDP
        udpsrv.sendto(reply.pack(), addr)

        # Show status in console
        print(now, ':', sqname, '|', sqtype, '=', qtype, '|', sres, '|',
              hostip, '=', host_cache[hostip])  #,reply.pack()

    # Shutting down
    print(now, ': Shutting down...')
    udpsrv.shutdown(0)
    print(now, ': Done.')
Esempio n. 8
0
    def parse_server_config(server_config):
        import copy

        _server_config = copy.deepcopy(server_config)
        dns_servers = _server_config.get('dns_servers', [])
        for server in dns_servers:
            # parse url
            scheme, hostname, port = DNSServerLoader.parse_url(server['url'])
            server['scheme'] = scheme
            server['hostname'] = hostname
            server['port'] = port

            # parse rules
            for rule in server['rules']:
                rtype = rule['type']
                if rule['domain-type'] in ('FQDN', 'PREFIX', 'SUFFIX'):
                    rule['domain'] = DNSLabel(rule['domain'])
                if rtype == 'FORWARD':
                    _scheme, _hostname, _port = DNSServerLoader.parse_url(rule['value'])
                    rule['pvalue'] = {
                        'scheme': _scheme,
                        'hostname': _hostname,
                        'port': _port,
                        'url': _scheme + '://' + _hostname + ':' + str(_port)
                    }
                elif rtype in ('A', 'CNAME', 'MX', 'NS', 'PTR', 'AAAA', 'SRV', 'SOA'):
                    if isinstance(rule['value'], six.string_types):
                        rule['value'] = [rule['value']]
                    if rtype == 'A':
                        rule['pvalue'] = [dnslib.A(item) for item in rule['value']]
                    elif rtype == 'CNAME':
                        rule['pvalue'] = [dnslib.CNAME(DNSLabel(item)) for item in rule['value']]
                    elif rtype == 'MX':
                        rule['pvalue'] = [dnslib.MX(DNSLabel(item)) for item in rule['value']]
                    elif rtype == 'NS':
                        rule['pvalue'] = [dnslib.NS(DNSLabel(item)) for item in rule['value']]
                    elif rtype == 'PTR':
                        rule['pvalue'] = [dnslib.PTR(DNSLabel(item)) for item in rule['value']]
                    elif rtype == 'AAAA':
                        rule['pvalue'] = [dnslib.AAAA(item) for item in rule['value']]
                    elif rtype == 'SRV':
                        srv_arr = []
                        for item in rule['value']:
                            item_arr = item.split(' ')
                            srv_arr.append(dnslib.SRV(
                                priority=num.safe_int(item_arr[0]),
                                weight=num.safe_int(item_arr[1]),
                                port=num.safe_int(item_arr[2]),
                                target=item_arr[3]))
                        rule['pvalue'] = srv_arr
                    elif rtype == 'SOA':
                        soa_arr = []
                        for item in rule['value']:
                            item_arr = item.split(' ')
                            soa_arr.append(dnslib.SOA(
                                mname=DNSLabel(item_arr[0]),
                                rname=DNSLabel(item_arr[1]),
                                times=(num.safe_int(t) for t in item_arr[2:])  # serial, refresh, retry, expire, minimun
                            ))
                        rule['pvalue'] = soa_arr
        return dns_servers
Esempio n. 9
0
    def dns_resolve(self, query, tcp):
        """ 
            Resolves DNS request from one client at the time.
            Encodes its actual data and forms DNS response from it.
        """
        request = dns.DNSRecord.parse(query)
        reply = request.reply()
        
        domain = request.q.get_qname()
        qtype =  request.q.qtype
        data = exf.domain_decode(str(domain), base64.urlsafe_b64decode)
        
        # If encryption key is present - decode it for futher data decryption
        if (len(request.questions) > 1):
            enc_domain = str(request.questions[1].get_qname())
            enc_key = exf.domain_decode(enc_domain, base64.urlsafe_b64decode)
            # Descramble key
            enc_key = exf.scramble(enc_key, (4, 12), True)

            # Check if the key is scramble offset
            if len(enc_key) < 3:
                enc_key = tuple(enc_key) 
                data = exf.scramble(data, enc_key, True)
            # Or AES decryption key
            else:
                enc_key = enc_key.decode()
                data = exf.aes_decrypt(data, enc_key)
            # reply.add_question(request.questions[1])

        if DEBUG:
            print_with_time("***", f"DNS QTYPE is {qtype}")
            print_with_time("***", f"Original data length {len(data)} bytes")
            print_with_time("***", f"{data[:24]}...")

        data = base64.b64encode(data)

        core_domain = deepcopy(domain)
        # Get TLD domain from original object
        core_domain.label = domain.label[-2:]

        if (qtype == dns.QTYPE.A):
            data = exf.ip_encode(data, False)
        
        elif (qtype == dns.QTYPE.AAAA):
            data = exf.ip_encode(data, True)

        elif (qtype ==  dns.QTYPE.TXT):
            data = [dns.TXT(data)]
        
        elif (qtype == 10):     # NULL type
            data = [dns.RD(data)]
        
        else:
            data = exf.domain_encode(data, str(core_domain), base64.urlsafe_b64encode)
            if (qtype == dns.QTYPE.CNAME):
                data = [dns.CNAME(data)]
            elif (qtype ==  dns.QTYPE.MX):
                data = [dns.MX(data)]
            elif (qtype == dns.QTYPE.NS):
                data = [dns.NS(data)]

        for rd in data:
            reply.add_answer(dns.RR(str(domain), rtype=qtype, rdata=rd))
        
        raw_reply = reply.pack()
        # Truncate large (> 512 bytes) data for UDP payload
        if (len(raw_reply) > exf.MAX_DNS_LEN and not tcp):
            print_with_time("DNS", f"Response message is big! Truncate it...")
            reply.header.set_tc(1)
            raw_reply = reply.pack()[:exf.MAX_DNS_LEN]
        
        print_with_time("DNS", f"Sending back the request in size {len(raw_reply)} bytes\n")
        return raw_reply