Beispiel #1
0
def _add_additional(addi_list):
    """
    Given a domain and an additional set,
    this function will add the A records for the UH DNS nameservers to the set.
    :param addi_list: Additional set to add to.
    """
    if addi_list == []:
        addi_list.append(
            dnslib.RR(rname="ns1.uh-dns.com.",
                      rtype=dnslib.QTYPE.A,
                      rdata=dnslib.A("18.130.161.247"),
                      ttl=3600))
        addi_list.append(
            dnslib.RR(rname="ns1.uh-dns.com.",
                      rtype=dnslib.QTYPE.AAAA,
                      rdata=dnslib.AAAA("2a05:d01c:35b:7601::4"),
                      ttl=3600))
        addi_list.append(
            dnslib.RR(rname="ns2.uh-dns.com.",
                      rtype=dnslib.QTYPE.A,
                      rdata=dnslib.A("18.130.86.161"),
                      ttl=3600))
        addi_list.append(
            dnslib.RR(rname="ns2.uh-dns.com.",
                      rtype=dnslib.QTYPE.AAAA,
                      rdata=dnslib.AAAA("2a05:d01c:35b:7600::4"),
                      ttl=3600))
Beispiel #2
0
    async def _get_record(self, request, client_writer):
        domain = str(request.questions[0].qname)[:-1]
        qtype = request.questions[0].qtype
        logger.info('dns_request: %s, %s', domain, qtype)

        if not self.conf.GET_PROXY.isgfwed_resolver(domain):
            # try resolve with getaddrinfo first
            logger.debug('not gfwed.')
            if qtype in (dnslib.QTYPE.A, dnslib.QTYPE.AAAA, dnslib.QTYPE.ANY):
                result_list = await resolve(domain, 0)
                response = request.reply()
                for result in result_list:
                    if result[0] == socket.AF_INET and qtype in (
                            dnslib.QTYPE.A, dnslib.QTYPE.ANY):
                        response.add_answer(
                            dnslib.RR(domain,
                                      dnslib.QTYPE.A,
                                      rdata=dnslib.A(result[1])))

                    elif result[0] == socket.AF_INET6 and qtype in (
                            dnslib.QTYPE.AAAA, dnslib.QTYPE.ANY):
                        response.add_answer(
                            dnslib.RR(domain,
                                      dnslib.QTYPE.AAAA,
                                      rdata=dnslib.AAAA(result[1])))
                return response

        await self.tcp_dns_record(request, client_writer)
Beispiel #3
0
def _alias_search(q_type, record, rr_list, auth_list, addi_list):
    """
    If no A or AAAA records exist this function will add any fixed alias records.
    :param q_type: Query type (A or AAAA) alias records accepted.
    :param record: Record from DB.
    :param rr_list: resource record list.
    :param auth_list: authority list.
    :param addi_list: additional list.
    """
    try:
        alias_record = record["ALIAS"]
        ttl = int(alias_record["ttl"])
        question = dnslib.DNSRecord.question(alias_record["domain"], qtype=dnslib.QTYPE[q_type])
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(1)
        sock.bind(("", 0)) # Bind to any available IP and port.
        sock.sendto(question.pack(), ("10.0.0.2", 53))
        res = dnslib.DNSRecord.parse(sock.recv(4096))
        sock.close()
        for r in res.rr:
            ip = str(r.rdata)
            if q_type == dnslib.QTYPE.A:
                rdata = dnslib.A(ip)
            elif q_type == dnslib.QTYPE.AAAA:
                rdata = dnslib.AAAA(ip)
            rr_list.append(dnslib.RR(rname=record["domain"],
                                     rtype=q_type,
                                     rdata=rdata,
                                     ttl=ttl))
            _add_authority(record["domain"], auth_list)
            _add_additional(addi_list)
    except:
        pass
Beispiel #4
0
    def handle(self):
        packet_bytes = self.request[0]
        packet_socket = self.request[1]
        parsed = False
        try:
            dnsreq = dnslib.DNSRecord.parse(packet_bytes)
            parsed = True
        except dnslib.DNSError:
            pass
        if parsed:
            logging.debug('IN FROM ADDRESS: %s, INTERFACE: %s, LLMNR DNS packet:\n%s' % (
                self.client_address,
                self.server.ifindex,
                repr(dnsreq)
            ))
            if dnslib.OPCODE.get(dnsreq.header.opcode) != 'QUERY':
                return
            if dnsreq.header.qr:
                # this is response
                if dnsreq.header.q != 1:
                    return
            else:
                # this is query
                if dnsreq.header.q != 1:
                    return
                if dnsreq.header.a != 0:
                    return
                if dnsreq.header.auth != 0:
                    return
                if dnsreq.header.aa:  # RFC 4795: flag C
                    return

                hostname = str(dnsreq.q.qname)
                if functools.reduce(
                        operator.or_,
                        (hostname == _hostname for _hostname in self.server.hostname_list),
                        False
                ):
                    dnsresp = dnsreq.reply(0, 0)
                    if dnsreq.q.qclass == dnslib.CLASS.IN:
                        if dnsreq.q.qtype == dnslib.QTYPE.AAAA:
                            for ipaddress in self.server.dispatcher.get_addresses_ipv6(self.server.ifindex):
                                dnsresp.add_answer(dnslib.RR(
                                    dnsreq.q.qname.idna(),
                                    dnslib.QTYPE.AAAA,
                                    ttl=60,
                                    rdata=dnslib.AAAA(ipaddress)
                                ))
                        else:
                            return
                    else:
                        return
                    dnsresp.header.aa = 0  # RFC 4795: flag C
                    packet_socket.sendto(dnsresp.pack(), self.client_address)
                    logging.debug('OUT TO ADDRESS: %s, LLMNR DNS packet:\n%s' % (
                        self.client_address, repr(dnsresp)
                    ))
Beispiel #5
0
def ip_encode(data, ipv6) -> list:
    """ 
        Encodes data to AAAA or A rdata types.
    """
    chunk_size = IPV6_LENGTH if ipv6 else IPV4_LENGTH
    data = pad_bytes(data, chunk_size)

    if (len(data) > chunk_size):
        data = chunk(data, chunk_size)
    else:
        data = [data]

    if (ipv6):
        qdata = [dns.AAAA(socket.inet_ntop(socket.AF_INET6, i)) for i in data]
    else:
        qdata = [dns.A(socket.inet_ntop(socket.AF_INET, i)) for i in data]

    return qdata
Beispiel #6
0
def _aaaa_search(record, rr_list, auth_list, addi_list):
    """
    Searches and adds any AAAA 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:
        _alias_search(dnslib.QTYPE.AAAA, record, rr_list, auth_list, addi_list)
        aaaa_record = record["AAAA"]
        ttl = int(aaaa_record["ttl"])
        for ip in aaaa_record["value"]:
            rr_list.append(dnslib.RR(rname = record["domain"],
                                     rtype = dnslib.QTYPE.AAAA,
                                     rdata = dnslib.AAAA(ip),
                                     ttl   = ttl))
            _add_authority(record["domain"], auth_list)
            _add_additional(addi_list)
    except:
        pass
Beispiel #7
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)))
Beispiel #8
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
Beispiel #9
0
    def handle(self):
        packet_bytes = self.request[0]
        packet_socket = self.request[1]
        iface_index = self.request[2]
        parsed = False
        try:
            dnsreq = dnslib.DNSRecord.parse(packet_bytes)
            parsed = True
        except dnslib.DNSError:
            pass
        if parsed:
            logging.debug(
                'IN FROM ADDRESS: %s, INTERFACE: %s, LLMNR DNS packet:\n%s' %
                (self.client_address, iface_index, repr(dnsreq)))
            if dnslib.OPCODE.get(dnsreq.header.opcode) != 'QUERY':
                return
            if dnsreq.header.qr:
                # this is response
                if dnsreq.header.q != 1:
                    return
            else:
                # this is query
                if dnsreq.header.q != 1:
                    return
                if dnsreq.header.a != 0:
                    return
                if dnsreq.header.auth != 0:
                    return
                if dnsreq.header.aa:  # RFC 4795: flag C
                    return

                hostname = str(dnsreq.q.qname)
                if functools.reduce(
                        operator.or_,
                    (hostname == _hostname
                     for _hostname in self.server.hostname_list), False):
                    dnsresp = dnsreq.reply(0, 0)
                    if dnsreq.q.qclass == dnslib.CLASS.IN:
                        if dnsreq.q.qtype == dnslib.QTYPE.AAAA:
                            if iface_index is None:
                                return

                            ifaces = netifaces.interfaces()
                            try:
                                iface = ifaces[iface_index - 1]
                            except IndexError:
                                return

                            try:
                                ifaddresses = netifaces.ifaddresses(iface)[
                                    netifaces.AF_INET6]
                            except (KeyError, ValueError):
                                return

                            for ifaddress in ifaddresses:
                                # IPv6 address may be link-local and might have interface suffix
                                ipaddress = ifaddress['addr'].split('%', 1)[0]

                                dnsresp.add_answer(
                                    dnslib.RR(dnsreq.q.qname.idna(),
                                              dnslib.QTYPE.AAAA,
                                              ttl=60,
                                              rdata=dnslib.AAAA(ipaddress)))
                        else:
                            return
                    else:
                        return
                    dnsresp.header.aa = 0  # RFC 4795: flag C
                    packet_socket.sendto(dnsresp.pack(), self.client_address)
                    logging.debug('OUT TO ADDRESS: %s, LLMNR DNS packet:\n%s' %
                                  (self.client_address, repr(dnsresp)))
Beispiel #10
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()
def main():

    # Creates internet UDP socket.
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Binds to the specified IP and port.
    sock.bind((IP, PORT))

    while True:

        try:

            # Receives data (DNS request) and address from a client. buffer size 512 as mentioned in DNS RFC.
            data, addr = sock.recvfrom(BUFFER_SIZE)
        except:
            continue

        # Informs in the console about a request received.
        print('Received request from {0} at port {1}.'.format(
            addr[0], addr[1]))

        try:

            # Decodes data to DNS request.
            dns_req = dnslib.DNSRecord.parse(data)

        except:

            # Informs in the console that the request is corrupted.
            print("Failed decoding the request due to corruption.")

        else:

            # For each question in the clients DNS request:
            for question in dns_req.questions:

                # Gets the name queried in the question.
                q_name = str(question.get_qname()).rstrip('.')

                # If the query type is PTR (reverse query).
                if dnslib.QTYPE.get(question.qtype) == 'PTR':
                    pass

                # If the query type is A (IPv4).
                if dnslib.QTYPE.get(question.qtype) == 'A':

                    # Generates reply.
                    dns_rep = dnslib.DNSRecord(
                        dnslib.DNSHeader(id=dns_req.header.id,
                                         qr=1,
                                         aa=1,
                                         ra=1),
                        q=dnslib.DNSQuestion(q_name, dnslib.QTYPE.A))

                    # Looks up answers, operates on each one if there are any.
                    for answer in lookup(q_name, 'A'):

                        # Adds the answer to the reply.
                        dns_rep.add_answer(
                            dnslib.RR(q_name,
                                      dnslib.QTYPE.A,
                                      rdata=dnslib.A(answer)))

                # If the query type is AAAA (IPv6).
                if dnslib.QTYPE.get(question.qtype) == 'AAAA':

                    # Generates reply.
                    dns_rep = dnslib.DNSRecord(
                        dnslib.DNSHeader(id=dns_req.header.id,
                                         qr=1,
                                         aa=1,
                                         ra=1),
                        q=dnslib.DNSQuestion(q_name, dnslib.QTYPE.AAAA))

                    # Looks up answers, operates on each one if there are any.
                    for answer in lookup(q_name, 'AAAA'):

                        # Adds the answer to the reply.
                        dns_rep.add_answer(
                            dnslib.RR(q_name,
                                      dnslib.QTYPE.AAAA,
                                      rdata=dnslib.AAAA(answer)))

                try:

                    # Sends the reply generated to the client.
                    sock.sendto(bytes(dns_rep.pack()), addr)

                except:

                    # Informs in the console that sending the reply failed.
                    print("Failed sending reply.")

                else:

                    # Informs in the console about a reply sent.
                    print('Sent reply to {0} at port {1}.\n'.format(
                        addr[0], addr[1]))
Beispiel #12
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.')
Beispiel #13
0
 def addr_to_qdata(addr: TAddress) -> dnslib.RD:
     ip = addr.compressed
     return dnslib.A(ip) if addr.version == 4 else dnslib.AAAA(ip)
Beispiel #14
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