Example #1
0
 def test_header_from_bytes(self):
     packet = b"\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06"
     header = Header(1, 2, 3, 4, 5, 6)
     self.assertEqual(Header.from_bytes(packet), header)
Example #2
0
 def test_qr(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.qr = 1
     self.assertEqual(header.qr, 1)
Example #3
0
 def test_flags_rcode(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.rcode = 15
     self.assertEqual(header.flags, 15)
Example #4
0
 def test_header_to_bytes(self):
     header = Header(1, 2, 3, 4, 5, 6)
     self.assertEqual(header.to_bytes(),
                      b"\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06")
Example #5
0
    def handle_request(self):
        """ Attempts to answer the received query """
        #Check this next to the given algorithm

        #print("Catalog:",self.catalog.zones)
        #for zone in self.catalog.zones:
        #    print("Records:",self.catalog.zones[zone].records)

        if self.message.header.opcode != 0:  #Send a not implemented error, we don't need to support those kinds of queries
            print("[-] - Received a nonstandard query. This is unsupported.")
            header = Header(ident, 0, 1, 0, 0, 0)
            header.qr = 1
            header.rd = self.message.header.rd
            header.ra = 1
            header.rcode = 4
            self.sendResponse(Message(header, self.message.questions, []))
            return

        #print("[*] - Handling request.")
        if len(self.message.questions) != 1:  #Send a format error response
            print("[-] - Invalid request.")
            header = Header(ident, 0, 1, 0, 0, 0)
            header.qr = 1
            header.rd = self.message.header.rd
            header.ra = 1
            header.rcode = 1
            self.sendResponse(Message(header, self.message.questions, []))
            return
        #print("MSG:",self.message)
        #print("RECEIVED QUESTION",self.message.questions[0])
        hname = str(self.message.questions[0].qname)
        #print("Solving",hname,type(hname))
        ident = self.message.header.ident
        #print("Checking zone")
        answer, authority, found = self.check_zone(hname)
        #print("Wat we in de zone hebben gevonden")
        #print("ANS:",answer,"AUTH:",authority,"FOUND:",found)
        #found = False
        if found:
            print("Found in zone")
            header = Header(ident, 0, 1, len(answer), len(authority), 0)
            header.qr = 1
            header.aa = 1
            header.rd = self.message.header.rd
            header.ra = 1

            self.sendResponse(
                Message(header, self.message.questions, answer, authority))

        elif self.message.header.rd == 1:
            h, al, ad = self.resolver.gethostbyname(hname)

            #Make and send th appropriate response
            header = Header(ident, 0, 1, len(al) + len(ad), 0, 0)
            header.qr = 1
            header.rd = self.message.header.rd
            header.ra = 1

            aliases = [
                ResourceRecord(Name(h), Type.CNAME, Class.IN, self.ttl,
                               RecordData.create(Type.CNAME, Name(alias)))
                for alias in al
            ]
            addresses = [
                ResourceRecord(Name(h), Type.A, Class.IN, self.ttl,
                               RecordData.create(Type.A, address))
                for address in ad
            ]

            self.sendResponse(
                Message(header, self.message.questions, aliases + addresses))
        else:  #Send an empty response
            header = Header(ident, 0, 1, 0, 0, 0)
            header.qr = 1
            header.rd = self.message.header.rd
            header.ra = 1
            header.rcode = 0
            self.sendResponse(Message(header, self.message.questions, []))
Example #6
0
 def test_flags_ra(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.ra = 1
     self.assertEqual(header.flags, 1 << 7)
Example #7
0
 def test_rd(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.rd = 1
     self.assertEqual(header.rd, 1)
Example #8
0
 def test_flags_opcode(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.opcode = 15
     self.assertEqual(header.flags, 15 << 11)
Example #9
0
 def test_tc(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.tc = 1
     self.assertEqual(header.tc, 1)
Example #10
0
 def test_flags_tc(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.tc = 1
     self.assertEqual(header.flags, 1 << 9)
Example #11
0
 def test_flags_aa(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.aa = 1
     self.assertEqual(header.flags, 1 << 10)
Example #12
0
    def gethostbyname(self, hostname, dnsserv='192.112.36.4'):
        """Translate a host name to IPv4 address.

        Currently this method contains an example. You will have to replace
        this example with the algorithm described in section 5.3.3 in RFC 1034.

        Args:
            hostname (str): the hostname to resolve

        Returns:
            (str, [str], [str]): (hostname, aliaslist, ipaddrlist)
        """
        ipaddrlist = []
        cnames = []
        temp = []
        if (self.caching):
            rcache = RecordCache(self.ttl)
            rcord = rcache.lookup(hostname, Type.ANY, Class.IN)
            if (rcord):
                for rec in rcord:
                    if rec.type_ == Type.A:
                        arec = rec.rdata
                        ipaddrlist.append(arec.address)
                    elif rec.type_ == Type.CNAME:
                        crec = rec.rdata
                        cnames.append(crec.cname)
            if ipaddrlist:
                return hostname, cnames, ipaddrlist
            elif cnames:
                return self.gethostbyname(cnames[0], dnsserv)

        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(self.timeout)

        # Create and send query
        question = Question(Name(str(hostname)), Type.A, Class.IN)
        header = Header(9001, 0, 1, 0, 0, 0)
        header.qr = 0
        header.opcode = 0
        header.rd = 1
        query = Message(header, [question])
        sock.sendto(query.to_bytes(), (str(dnsserv), 53))

        # Receive response
        data = sock.recv(2048)
        response = Message.from_bytes(data)
        print("Number of answers: " + str(len(response.answers)))
        print("Number of authorities: " + str(len(response.authorities)))
        print("Number of additionals: " + str(len(response.additionals)))

        # Get data
        aliaslist = cnames
        ipaddrlist = []
        dnslist = []

        while response.answers:
            for answer in response.answers:
                if answer.type_ == Type.A:
                    print("found A RR")
                    if (self.caching):
                        rcache.add_record(answer)
                    ipaddrlist.append(answer.rdata.address)
                if answer.type_ == Type.CNAME:
                    aliaslist.append(answer.rdata.cname)
                if answer.type_ == Type.NS:
                    dnslist.append(answer.rdata.nsdname)
            if ipaddrlist:
                return hostname, aliaslist, ipaddrlist
            elif aliaslist:
                question = Question(Name(aliaslist[0]), Type.A, Class.IN)
                query = Message(header, [question])
                sock.sendto(query.to_bytes(), (dnsserv, 53))
                data = sock.recv(2048)
                response = Message.from_bytes(data)
            elif dnslist:
                nsname = dnslist.pop()
                maybe_dnsserv = self.getnsaddr(nsname, response.additionals)
                if maybe_dnsserv:
                    dnsserv = maybe_dnsserv
                else:
                    pass
                sock.sendto(query.to_bytes(), (dnsserv, 53))
                data = sock.recv(2048)
                response = Message.from_bytes(data)
            else:
                break

        if response.authorities:
            for authority in response.authorities:
                if authority.type_ != Type.NS:
                    pass
                dnslist.append(authority.rdata.nsdname)
            while dnslist:
                nsname = dnslist.pop()
                maybe_next_dnsserv = self.getnsaddr(nsname,
                                                    response.additionals)
                if maybe_next_dnsserv:
                    next_dns_serv = maybe_next_dnsserv
                else:
                    pass
                (hname, aliasl, ipaddrl) = self.gethostbyname(hostname, nsname)
                if ipaddrl:
                    return hname, aliasl, ipaddrl
Example #13
0
    def gethostbyname(self, hostname):
        """Translate a host name to IPv4 address.

        Currently this method contains an example. You will have to replace
        this example with the algorithm described in section 5.3.3 in RFC 1034.

        Args:
            hostname (str): the hostname to resolve

        Returns:
            (str, [str], [str]): (hostname, aliaslist, ipaddrlist)
        """
        alias_list = []
        a_list = []
        slist = []
        found = False

        acs = self.getRecordsFromCache(hostname, Type.A, Class.IN)
        if acs:
            a_list += acs
            return hostname, alias_list, a_list

        nscs = self.matchByLabel(hostname, Type.NS, Class.IN)
        for ns in nscs:
            glue = self.getRecordsFromCache(str(ns.rdata.nsdname))
            if glue:
                slist += glue
            else:
                slist += [ns]

        id = self._make_id()

        # Create and send query
        question = Question(Name(hostname), Type.A, Class.IN)
        header = Header(id, 0, 1, 0, 0, 0)
        header.qr = 0  # 0 for query
        header.opcode = 0  # standad query
        header.rd = 0  # not recursive
        query = Message(header, [question])

        self.zone.read_master_file('dns/root.zone')

        sbelt = []
        for root in list(self.zone.records.values()):
            sbelt += [r for r in root if r.type_ == Type.A]

        while not found:
            if slist:
                rr = slist.pop()
                if rr.type_ == Type.A:
                    addr = rr.rdata.address
                    self.sock.send((query, addr, 53))
                elif rr.type_ == Type.NS:
                    fqdn = str(rr.rdata.nsdname)
                    _, _, a_rrs = self.gethostbyname(fqdn)
                    slist += a_rrs
                    continue
                elif rr.type_ == Type.CNAME:
                    fqdn = str(rr.rdata.cname)
                    _, cname_rrs, a_rrs = self.gethostbyname(fqdn)
                    a_list += a_rrs
                    alias_list += cname_rrs
                    break

            elif sbelt:
                rr = sbelt.pop()
                addr = rr.rdata.address
                self.sock.send((query, addr, 53))
            else:
                break

            # Receive response
            data = None
            while not data:
                data = self.sock.msgThere(id)
            response, _ = data[0]
            #response = Message.from_bytes(data)

            for answer in response.answers:
                if answer.type_ == Type.A:
                    self.addRecordToCache(answer)
                    a_list.append(answer)
                    found = True
                if answer.type_ == Type.CNAME:
                    self.addRecordToCache(answer)
                    alias_list.append(answer)
                    slist += [answer]
                    continue

            nss = []
            for auth in response.authorities:
                if auth.type_ == Type.NS:
                    nss.append(auth)
                    self.addRecordToCache(auth)

            a_add = {}
            for add in response.additionals:
                if add.type_ == Type.A:
                    name = str(add.name)
                    a_add[name] = add
                    self.addRecordToCache(add)

            for ns in nss:
                name = str(ns.rdata.nsdname)
                if name in a_add:
                    slist += [a_add[name]]
                else:
                    slist += [ns]

        return hostname, alias_list, a_list
Example #14
0
 def test_flags_qr(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.qr = 1
     self.assertEqual(header.flags, 1 << 15)
Example #15
0
 def test_flags_rd(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.rd = 1
     self.assertEqual(header.flags, 1 << 8)
Example #16
0
 def test_opcode(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.opcode = 1
     self.assertEqual(header.opcode, 1)
Example #17
0
 def test_ra(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.ra = 1
     self.assertEqual(header.ra, 1)
Example #18
0
 def test_aa(self):
     header = Header(0, 0, 0, 0, 0, 0)
     header.aa = 1
     self.assertEqual(header.aa, 1)
Example #19
0
    def run(self):
        """ Run the handler thread"""
        msg = Message.from_bytes(self.data)
        header = msg.header
        recursion = header.rd != 0
        questions = msg.questions

        answers = []
        authorative = []
        additional = []
        for question in questions:
            qname = question.qname
            qtype = question.qtype
            if question.qclass != Class.IN:
                pass
            domains = self.getdomains(str(qname))
            for domain in domains:
                if not self.zone.records.get(domain, False):
                    continue
                for rr in self.zone.records[domain]:
                    if (rr.type_ == Type.A or rr.type_
                            == Type.CNAME) and domain == str(qname):
                        answers.append(rr)
                    if rr.type_ == Type.NS:
                        authorative.append(rr)
                        for rec in self.zone.records[str(rr.rdata.nsdname)]:
                            if rec not in additional:
                                if rec.qtype == Type.A:
                                    additional.append(rec)
            if authorative or answers:
                header_response = Header(9001, 0, 1, len(answers),
                                         len(authorative), len(additionals))
                header_response.qr = True
                header_response.opcode(1)
                header_response.aa(False)
                header_respones.tc(False)
                header_response.rd(False)
                header_response.ra(True)
                header_response.z(False)
                header_respones.rcode(False)

                respons = Message(header_response, [question], answers,
                                  authorities, additionals)

                self.sock.sendto(respons.to_bytes(), self.addr)
                break

            if recursion and (qtype == Type.A or qtype == Type.CNAME):
                answers = []
                resolver = Resolver(100, False, 0, True)
                (hostname, aliaslist,
                 ipaddrlist) = resolver.gethostbyname(question.qname)
                header_response = Header(9001, 0, 1,
                                         len(aliaslist) + len(ipaddrlist), 0,
                                         0)
                header_response.qr = 1
                header_response.opcode = 1
                header_response.aa = 0
                header_response.tc = 0
                header_response.rd = 0
                header_response.ra = 1
                header_response.rcode = 0

                for addr in ipaddrlist:
                    answers.append(
                        ResourceRecord.from_dict({
                            "name": str(hostname),
                            "type": str(Type.A),
                            "class": str(Class.IN),
                            "ttl": 0,
                            "rdata": {
                                "address": str(addr)
                            }
                        }))
                for alias in aliaslist:
                    answers.append(
                        ResourceRecord.from_dict({
                            "name": str(hostname),
                            "type": str(Type.CNAME),
                            "class": str(Class.IN),
                            "ttl": 0,
                            "rdata": {
                                "cname": str(alias)
                            }
                        }))
                response = Message(header_response, questions, answers)
                self.sock.sendto(response.to_bytes(), self.addr)
                break