示例#1
0
文件: search.py 项目: jwsi/dns-server
def _add_authority(domain, auth_list):
    """
    Given a domain and an authority set,
    this function will add the UH DNS nameservers to the set if they don't already exist.
    :param domain: Domain to be authoritative over.
    :param auth_list: Auth set to add to.
    """
    record1 = dnslib.RR(rname=domain,
                  rtype=dnslib.QTYPE.NS,
                  rdata=dnslib.NS("ns1.uh-dns.com"),
                  ttl=3600)
    record2 = dnslib.RR(rname=domain,
                  rtype=dnslib.QTYPE.NS,
                  rdata=dnslib.NS("ns2.uh-dns.com"),
                  ttl=3600)
    if record1 not in auth_list:
        auth_list.append(record1)
    if record2 not in auth_list:
        auth_list.append(record2)
示例#2
0
def gen_response(qt, qn):
    global serving_domains
    prefix_ = list(
        filter(lambda d: qn == d or qn.endswith('.' + d), serving_domains))
    if len(prefix_) != 1:
        # print("Error: invalid request domain {} in {}".format(qn, serving_domains))
        return None
    prefix = prefix_[0]
    print('REQ: ', qt, qn)

    if qt == 'SOA':
        generated_soa = dnslib.SOA(
            mname="todo." + domain_text,
            rname="*****@*****.**",
            times=(
                201307231,  # serial number
                10000,  # refresh
                2400,  # retry
                604800,  # expire
                3600,  # minimum
            ))
        return RR(rname=prefix,
                  rtype=QTYPE.SOA,
                  rclass=1,
                  ttl=86400,
                  rdata=generated_soa)
        # return {"mname": "todo."+domain_text, "rname": "*****@*****.**", "serial": "10", "refresh": 3600, "retry": 600, "expire": 604800, "minimum": 86400}
    elif qt == 'A':
        requested_ip = qn[:len(qn) - len(prefix)].strip('.')
        if not re.match(r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$', requested_ip):
            print("Invalid requested_ip: " + requested_ip)
            return None
        generated_a = dnslib.A(requested_ip)
        return RR(rname=qn,
                  rtype=QTYPE.A,
                  rclass=1,
                  ttl=86400,
                  rdata=generated_a)
    elif qt == 'NS':
        generated_ns = dnslib.NS(ns_ipaddr)
        return RR(rname=prefix,
                  rtype=QTYPE.NS,
                  rclass=1,
                  ttl=86400,
                  rdata=generated_ns)
    else:
        print("Invalid qt=" + qt)
        return None
示例#3
0
文件: search.py 项目: jwsi/dns-server
def _ns_search(record, rr_list, addi_list):
    """
    Searches and adds any NS records for the domain.
    :param record: Overall record for domain
    :param rr_list: Current record list for the domain
    :param addi_list: Additional list for the domain
    """
    try:
        ns_record = record["NS"]
        ttl = int(ns_record["ttl"])
        for ns in ns_record["value"]:
            rr_list.append(dnslib.RR(rname = record["domain"],
                                     rtype = dnslib.QTYPE.NS,
                                     rdata = dnslib.NS(label = ns),
                                     ttl   = ttl))
            _add_additional(addi_list)
    except:
        pass
示例#4
0
    def __init__(self, upstream):
        super().__init__(upstream, 53, 5)
        if confs.SOA_MNAME and confs.SOA_RNAME:
            self.SOA = dnslib.SOA(
                mname=DNSLabel(confs.SOA_MNAME),
                rname=DNSLabel(confs.SOA_RNAME.replace(
                    '@', '.')),  # TODO: . before @ should be escaped
                times=(
                    confs.SOA_SERIAL,  # serial number
                    60 * 60 * 1,  # refresh
                    60 * 60 * 2,  # retry
                    60 * 60 * 24,  # expire
                    60 * 60 * 1,  # minimum
                ))
        else:
            self.SOA = None

        if confs.NS_SERVERS:
            self.NS = [dnslib.NS(i) for i in confs.NS_SERVERS]
        else:
            self.NS = []
示例#5
0
def add_answer_to_query(required_data, query):
    qtype = query.q.qtype
    q = query.q

    # Для каждого типа запроса добавляем интересующий ответ
    if qtype == dnslib.QTYPE.A:
        # Добавляем все A адреса
        for addr in required_data.addresses:
            query.add_answer(
                dnslib.RR(rname=q.qname,
                          rclass=q.qclass,
                          rtype=q.qtype,
                          ttl=required_data.remain_ttl(),
                          rdata=dnslib.A(addr)))
    if qtype == dnslib.QTYPE.AAAA:
        # Добавляем все AAAA адреса
        for addr in required_data.addresses:
            query.add_answer(
                dnslib.RR(rname=q.qname,
                          rclass=q.qclass,
                          rtype=q.qtype,
                          ttl=required_data.remain_ttl(),
                          rdata=dnslib.AAAA(addr)))
    if qtype == dnslib.QTYPE.NS:
        # Добавляем все NS серверы
        for addr in required_data.servers:
            query.add_answer(
                dnslib.RR(rname=q.qname,
                          rclass=q.qclass,
                          rtype=q.qtype,
                          ttl=required_data.remain_ttl(),
                          rdata=dnslib.NS(addr)))
    if qtype == dnslib.QTYPE.PTR:
        # Добавляем PTR
        query.add_answer(
            dnslib.RR(rname=q.qname,
                      rclass=q.qclass,
                      rtype=q.qtype,
                      ttl=required_data.remain_ttl(),
                      rdata=dnslib.PTR(required_data.name)))
示例#6
0
    def resolve(self, request, handler):
        question = request.get_q()
        req_name = str(question.get_qname())
        # TXT = 16
        reply = request.reply()

        pivot = req_name.rfind("_tox.")
        if pivot == -1:
            reply.header.rcode = dnslib.RCODE.NXDOMAIN
            return reply

        name = req_name[:pivot].rstrip(".")
        suffix = req_name[pivot:]
        domain = suffix[5:].rstrip(".")

        if question.qtype == 16:
            if not name and domain in self.workable_domains:
                data = self.cryptocore.public_key.encode("ascii")

                reply.add_answer(
                    dnslib.RR(req_name, 16, ttl=0, rdata=dnslib.TXT(data)))
                return reply

            first_try = self.try_tox3_resolve(reply, name, domain, req_name)
            if not first_try:
                return self.try_tox1_resolve(reply, name, domain, req_name)
            else:
                return first_try
        elif question.qtype == 2:
            reply.add_answer(
                dnslib.RR(req_name, 2, ttl=86400, rdata=dnslib.NS(self.home)))
            return reply
        else:
            reply.header.rcode = dnslib.RCODE.NXDOMAIN
            return reply
        return reply
示例#7
0
    def resolve(self, request, handler):
        question = request.get_q()
        req_name = str(question.get_qname())
        # TXT = 16
        reply = request.reply()
        suffix = "._tox.{0}".format(self.ireg)

        if question.qtype != 16 and not req_name.endswith(self.ireg):
            reply.header.rcode = dnslib.RCODE.NXDOMAIN
            return reply

        if question.qtype == 16:
            if req_name == suffix[1:]:
                reply.add_answer(dnslib.RR(req_name, 16, ttl=0,
                    rdata=dnslib.TXT(self.cryptocore.public_key.encode("ascii"))))
                return reply
            if not req_name.endswith(suffix):
                reply.header.rcode = dnslib.RCODE.NXDOMAIN
                return reply
            user_name = req_name[:req_name.rfind(suffix)]
            if len(user_name) > NAME_LIMIT_HARD and user_name[0] == "_":
                encrypted = user_name.replace(".", "")[1:]
                try:
                    b = notsecure32_decode(encrypted)
                    nonce = b[:4] + (b"\0" * 20)
                    ck = b[4:36]
                    payload = b[36:]
                    name = self.cryptocore.dsrep_decode_name(ck, nonce, payload)
                except Exception:
                    print("error >_<")
                    reply.header.rcode = dnslib.RCODE.NXDOMAIN
                    return reply

                rec = self.store.get(name.decode("utf8"))
                if not rec:
                    reply.header.rcode = dnslib.RCODE.NXDOMAIN
                    return reply
                base = b"v=tox3;id="
                if rec.pin:
                    r_payload = "{0}{1}{2}".format(rec.public_key, rec.pin,
                                                   rec.checksum)
                else:
                    r_payload = "{0}00000000{1}".format(rec.public_key,
                                                        rec.checksum)
                msg = binascii.unhexlify(r_payload)
                nonce_reply = b[:4] + b"\x01" + (b"\0" * 19)
                ct = self.cryptocore.dsrec_encrypt_key(ck, nonce_reply, msg)

                key_part = notsecure32_encode(ct)
                reply.add_answer(dnslib.RR(req_name, 16, ttl=0,
                                 rdata=dnslib.TXT(b"".join((base, key_part)))))
                return reply
            else:
                rec = self.store.get(user_name)
                if not rec:
                    reply.header.rcode = dnslib.RCODE.NXDOMAIN
                    return reply
                else:
                    reply.add_answer(dnslib.RR(req_name, 16, ttl=0,
                                               rdata=dnslib.TXT(rec.record(0)
                                                            .encode("utf8"))))
                    return reply
        elif question.qtype == 6:
            self.update_soa()
            reply.add_answer(self.soa)
            return reply
        elif question.qtype == 2:
            for name in self.authority_list:
                reply.add_answer(dnslib.RR(req_name, 2, ttl=86400,
                                           rdata=dnslib.NS(name.encode("utf8"))
                                           ))
            return reply
        elif question.qtype == 1 and self.home_addresses:
            for ip in self.home_addresses:
                reply.add_answer(dnslib.RR(req_name, 1, ttl=3600,
                                           rdata=dnslib.A(ip)))
        elif question.qtype == 28 and self.home_addresses_6:
            for ip in self.home_addresses_6:
                reply.add_answer(dnslib.RR(req_name, 28, ttl=3600,
                                           rdata=dnslib.AAAA(ip)))
        else:
            reply.header.rcode = dnslib.RCODE.NXDOMAIN
            return reply
        return reply
示例#8
0
class BaseRequestHandler(socketserver.BaseRequestHandler):
    fIP = {}

    D = DomainName('0h0.us.')
    IP = '18.219.234.8'
    TTL = 60 * 1

    soa_record = dnslib.SOA(
        mname=D.ns1,  # primary name server
        times=(
            22118400,  # serial number
            60 * 60 * 1,  # refresh
            60 * 60 * 3,  # retry
            1 * 1 * 1,  # expire
            1 * 1 * 1,  # minimum
        ))
    ns_records = [dnslib.NS(D.ns1), dnslib.NS(D.ns2)]
    records = {
        D: [dnslib.A(IP), dnslib.AAAA((0, ) * 16), soa_record] + ns_records,
        D.ns1: [
            dnslib.A(IP)
        ],  # MX and NS records must never point to a CNAME alias (RFC 2181 section 10.3)
        D.ns2: [dnslib.A(IP)]
    }

    def progressBar(self, c, tot, status):
        bar = 40
        filled = int(round(bar * (tot - c) / float(tot)))

        pct = round(100.0 * (tot - c) / float(tot), 1)
        barstr = '=' * filled + '-' * (bar - filled)

        sys.stdout.write('[%s] %s%s ...%s\r' % (barstr, pct, '%', status))
        sys.stdout.flush()

    def processRequest(self, request):

        reply = dnslib.DNSRecord(dnslib.DNSHeader(id=request.header.id,
                                                  qr=1,
                                                  aa=1,
                                                  ra=1),
                                 q=request.q)

        qname = request.q.qname
        qn = str(qname)
        qtype = request.q.qtype
        qt = dnslib.QTYPE[qtype]
        if qn == self.D or qn.endswith('.' + self.D):

            for name, rrs in self.records.items():
                if name == qn:
                    for rdata in rrs:
                        rqt = rdata.__class__.__name__
                        if qt in ['*', rqt]:
                            reply.add_answer(
                                dnslib.RR(rname=qname,
                                          rtype=getattr(dnslib.QTYPE, rqt),
                                          rclass=1,
                                          ttl=self.TTL,
                                          rdata=rdata))

            for rdata in self.ns_records:
                reply.add_ar(
                    dnslib.RR(rname=self.D,
                              rtype=dnslib.QTYPE.NS,
                              rclass=1,
                              ttl=self.TTL,
                              rdata=rdata))

            reply.add_auth(
                dnslib.RR(rname=self.D,
                          rtype=dnslib.QTYPE.SOA,
                          rclass=1,
                          ttl=self.TTL,
                          rdata=self.soa_record))

        for question in request.questions:

            if (question.qtype == dnslib.QTYPE.TXT):
                #only process TXT record requests
                content = str(question.qname)[:-1]
                if content.endswith(self.D[:-1]):
                    content = content[:-len(self.D[:-1]) - 1]

                key = content[:4]

                if key in self.fIP:
                    content = str(content[4:])
                    self.fIP[key][3] += content
                    self.fIP[key][1] -= len(content)
                    #print(key, content,len(content),self.fIP[key][1] )

                    #print("Left: "+str(self.fIP[sIP][1]))
                    self.progressBar(
                        self.fIP[key][1], self.fIP[key][4], "Receiving '" +
                        self.fIP[key][0] + "' with index " + key)
                    reply.add_answer(
                        dnslib.RR(rname=qname,
                                  rtype=question.qtype,
                                  rclass=1,
                                  ttl=self.TTL,
                                  rdata=dnslib.TXT(content)))
                    #reply.add_answer(dnslib.RR(rname=qname, rtype=question.qtype, rclass=1, ttl=self.TTL, rdata=dnslib.TXT("OK")))
                    if (self.fIP[key][1] == 0):
                        #we have received the entire file. Time to write it.
                        content_decoded = base64.standard_b64decode(
                            self.fIP[key][3])
                        with open(self.fIP[key][0], 'wb') as newfile:
                            newfile.write(content_decoded)

                        hashedWord = md5(content_decoded).hexdigest()
                        if (self.fIP[key][2] == hashedWord):
                            print("\nFile successfully received")
                            reply.add_answer(
                                dnslib.RR(rname=qname,
                                          rtype=question.qtype,
                                          rclass=1,
                                          ttl=self.TTL,
                                          rdata=dnslib.TXT("OK")))

                        else:
                            print("\nFile received but failed hash:")
                            reply.add_answer(
                                dnslib.RR(rname=qname,
                                          rtype=question.qtype,
                                          rclass=1,
                                          ttl=self.TTL,
                                          rdata=dnslib.TXT("FAIL HASH")))

                        del self.fIP[key]

                else:
                    # new connection. we expect a file name
                    print("New file:", content)
                    parts = content.split("|")
                    if (len(parts) == 3):
                        #we have valid request
                        print("new file upload: ", content)
                        self.fIP[parts[2][:4]] = [
                            os.path.basename(parts[0]),
                            int(parts[1]), parts[2], "",
                            int(parts[1])
                        ]
                    reply.add_answer(
                        dnslib.RR(rname=qname,
                                  rtype=question.qtype,
                                  rclass=1,
                                  ttl=self.TTL,
                                  rdata=dnslib.TXT("OK")))

            else:
                reply.add_answer(
                    dnslib.RR(rname=qname,
                              rtype=question.qtype,
                              rclass=1,
                              ttl=self.TTL,
                              rdata=dnslib.A(self.IP)))

            #print("responding:",reply)
            return reply.pack()
示例#9
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.')
示例#10
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
示例#11
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