def test_authority_domain(self):
     question = Question(Name("server1.gumpe"), Type.A, Class.IN)
     header = Header(1337, 0, 1, 0, 0, 0)
     query = Message(header, questions=[question])
     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     s.sendto(query.to_bytes(), (SERVER, PORT))
     data = s.recv(512)
     s.close()
     message = Message.from_bytes(data)
     self.assertCountEqual(message.answers, [
         ResourceRecord(
             name=Name("server1.gumpe."),
             type_=Type.A,
             class_=Class.IN,
             ttl=0,
             rdata=ARecordData("10.0.1.5"),
         ),
         ResourceRecord(
             name=Name("server1.gumpe."),
             type_=Type.A,
             class_=Class.IN,
             ttl=0,
             rdata=ARecordData("10.0.1.4"),
         ),
     ])
コード例 #2
0
ファイル: message.py プロジェクト: W-M-T/py3DNS
    def from_bytes(cls, packet):
        """Create Message from bytes.

        Args:
            packet (bytes): byte representation of the message.
        """
        header, offset = Header.from_bytes(packet), 12

        questions = []
        for _ in range(header.qd_count):
            question, offset = Question.from_bytes(packet, offset)
            questions.append(question)

        answers = []
        for _ in range(header.an_count):
            answer, offset = ResourceRecord.from_bytes(packet, offset)
            answers.append(answer)

        authorities = []
        for _ in range(header.ns_count):
            authority, offset = ResourceRecord.from_bytes(packet, offset)
            authorities.append(authority)

        additionals = []
        for _ in range(header.ar_count):
            additional, offset = ResourceRecord.from_bytes(packet, offset)
            additionals.append(additional)

        return cls(header, questions, answers, authorities, additionals)
コード例 #3
0
 def consult_cache(self, questions):
     answers = []
     for q in questions:
         res, iplist, namelist = self.check_cache(q.qname)
         if res:
             for ip in iplist:
                 answers.append(ResourceRecord(q.qname, Type.A, Class.IN, self.ttl, ARecordData(ip)))
             for n in namelist:
                 answers.append(ResourceRecord(q.qname, Type.CNAME, Class.IN, self.ttl, CNAMERecordData(n)))
     return answers
コード例 #4
0
ファイル: test_resource.py プロジェクト: kliyer-ai/NDS-DNS
 def test_resource_to_bytes(self):
     name = MagicMock()
     name.to_bytes.return_value = b"\x07example\x03com\x00"
     rdata = MagicMock()
     rdata.to_bytes.return_value = b"\x04\x05\x06\x07"
     record = ResourceRecord(name, Type.A, Class.CS, 3, rdata)
     compress = {}
     self.assertEqual(
         record.to_bytes(0, compress),
         (b"\x07example\x03com\x00\x00\x01\x00\x02\x00\x00\x00\x03\x00"
          b"\x04\x04\x05\x06\x07"))
コード例 #5
0
ファイル: test_resource.py プロジェクト: kliyer-ai/NDS-DNS
 def test_resource_from_bytes(self, MockName, MockRData):
     MockName.from_bytes.return_value = (Name("example.com"), 13)
     MockRData.create_from_bytes.return_value = ARecordData("1.1.1.1")
     packet = (b"\x07example\x03com\x00\x00\x01\x00\x02\x00\x00\x00\x03\x00"
               b"\x04\x01\x01\x01\x01")
     record1, offset = ResourceRecord.from_bytes(packet, 0)
     record2 = ResourceRecord(Name("example.com"), Type.A, Class.CS, 3,
                              ARecordData("1.1.1.1"))
     self.assertEqual(record1, record2)
     MockName.from_bytes.assert_called_with(packet, 0)
     MockRData.create_from_bytes.assert_called_with(Type.A, packet, 23, 4)
 def test_concurrent_requests(self):
     queries = []
     answers = []
     question = Question(Name("gaia.cs.umass.edu"), Type.A, Class.IN)
     header = Header(1337, 0, 1, 0, 0, 0)
     header.rd = 1
     queries.append(Message(header, questions=[question]))
     answers.append([
         ResourceRecord(name=Name("gaia.cs.umass.edu"),
                        type_=Type.A,
                        class_=Class.IN,
                        ttl=0,
                        rdata=ARecordData("128.119.245.12")),
     ])
     question = Question(Name("server2.gumpe"), Type.A, Class.IN)
     header = Header(420, 0, 1, 0, 0, 0)
     queries.append(Message(header, questions=[question]))
     answers.append([
         ResourceRecord(name=Name("server2.gumpe"),
                        type_=Type.A,
                        class_=Class.IN,
                        ttl=0,
                        rdata=ARecordData("10.0.1.7")),
     ])
     header = Header(69, 0, 1, 0, 0, 0)
     question = Question(Name("www.gumpe"), Type.A, Class.IN)
     queries.append(Message(header, questions=[question]))
     answers.append([
         ResourceRecord(name=Name("www.gumpe"),
                        type_=Type.A,
                        class_=Class.IN,
                        ttl=0,
                        rdata=ARecordData("10.0.1.7")),
         ResourceRecord(name=Name("www.gumpe"),
                        type_=Type.CNAME,
                        class_=Class.IN,
                        ttl=0,
                        rdata=CNAMERecordData(Name("server2.gumpe"))),
     ])
     sockets = [
         socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         for _ in range(len(queries))
     ]
     for i in range(len(sockets)):
         sockets[i].sendto(queries[i].to_bytes(), (SERVER, PORT))
     responses = []
     for i in range(len(sockets)):
         responses.append(Message.from_bytes(sockets[i].recv(1024)))
     for i in range(len(sockets)):
         sockets[i].close()
     for i in range(len(queries)):
         self.assertCountEqual(responses[i].answers, answers[i])
コード例 #7
0
 def testCache(self):
     cac = RecordCache(0)
     self.assertEqual(cac.lookup("abcdefghqqqq.com", Type.A, Class.IN), [])
     test = ResourceRecord("blabla.com", Type.A, Class.IN, 0,
                           ARecordData("111.111.111.111"))
     cac.add_record(test)
     self.assertEqual(cac.lookup("blabla.com", Type.A, Class.IN), test)
コード例 #8
0
    def read_master_file(self, filename):
        """Read the zone from a master file

        See section 5 of RFC 1035.

        Args:
            filename (str): the filename of the master file
        """
        temp = []
        """Read the cache file from disk"""
        with open("roothints.md") as file_:
            lines = file_.readlines()
        for l in lines:
            #remove comments
            b = re.sub(r';[^\n]*', "", l)
            te = l.split()
            if (te[0] != ';'):
                temp.append(te)
            if ("." in te[0]):
                type_ = self.getType(te[2])
                if (type_ == Type.A):
                    rdata = ARecordData(te[3])
                elif (type_ == Type.NS):
                    rdata = NSRecordData(te[3])
                elif (type_ == Type.CNAME):
                    rdata = CNAMERecordData(te[3])
                rr = ResourceRecord(te[0], type_, Class.IN, te[1], rdata)
                self.records.update({te[0]: rr})
コード例 #9
0
    def read_cache_file(self, cache_file=Consts.CACHE_FILE):
        """ Read the cache file from disk """
        #Empty current cache
        self.records = []

        #Load from file
        try:
            with open(cache_file + ".timestamp") as infile:
                self.lastCleanup = int(infile.readline())

            with open(cache_file, "r") as infile:
                curTime = int(time.time())
                dcts = json.load(infile)
                self.records = [ResourceRecord.from_dict(dct) for dct in dcts]
                #Don't add the entries whose TTL is expired and update the ttls
                self.cleanup()

        except (ValueError, IOError, FileNotFoundError) as e:
            print("An error has occured while loading cache from disk: " +
                  str(e))

            with open(cache_file, 'w') as outfile:
                json.dump([], outfile, indent=2)

            with open(cache_file + ".timestamp", 'w') as outfile:
                outfile.write(str(self.lastCleanup))

            if isinstance(e, FileNotFoundError):
                print("Missing files were created")
            self.records = []
コード例 #10
0
    def read_master_file(self, filename):
        """Read the zone from a master file

        See section 5 of RFC 1035.

        Args:
            filename (str): the filename of the master file
        """
        records = re.finditer(
            Zone.record_re, open(filename, "r").read(), flags=re.MULTILINE
        )
        for r in records:
            domain, ttl, class_, type_, rdata = r.groups()
            domain = domain or self.last_domain
            self.last_domain = domain
            record = ResourceRecord(
                name=Name(domain),
                type_=Type[type_],
                class_=Class[class_],
                ttl=int(ttl) if ttl is not None else Zone.default_ttl,
                rdata=RecordData.create_from_str(Type[type_], rdata)
            )
            if domain in self.records:
                self.records[domain].append(record)
            else:
                self.records[domain] = [record]
コード例 #11
0
    def serve(self):
        """Start serving requests"""
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.bind(("", self.port))

        while not self.done:
            data, address = sock.recvfrom(65565)
            message = Message.from_bytes(data)

            rd = message.header.rd
            rcode = 0
            aa = 1

            self.log("REQUEST RECIEVED:", address)
            answers, authorities, additionals = self.zone_resolution(message.questions)

            if answers == []:
                if authorities == [] and additionals == []:
                    self.log("\tZONE RESOLUTION FAILED")
                    answers = self.consult_cache(message.questions)

                    if answers == []:
                        self.log("\tCACHE LOOKUP FAILED")
                        rcode = 3
                    else:
                        aa = 0

                if rcode == 3 and rd == 1:
                    rcode = 0
                    self.log("\tCALLING RESOLVER")
                    resolver = Resolver(5, True, 0)
                    resolver.rd = 0
                    resolver.rootip = "198.41.0.4"
                    for q in message.questions:
                        self.log("\t\tRESOLVING:", q.qname)

                        hostname, namelist, iplist = resolver.gethostbyname(str(q.qname))
                        if hostname == str(q.qname):
                            for ip in iplist:
                                answers.append(ResourceRecord(q.qname, Type.A, Class.IN, self.ttl, ARecordData(ip)))
                            for n in namelist:
                                answers.append(ResourceRecord(q.qname, Type.CNAME, Class.IN, self.ttl, CNAMERecordData(n)))

            self.log("SENDING RESPONSE:", rcode, "\n")
            mess = self.build_message(message.header.ident, rd, aa, rcode, message.questions, answers, authorities, additionals)
            sock.sendto(mess.to_bytes(), address)
コード例 #12
0
    def setUp(self):
        # put invalid record in cache file
        record_data = RecordData.create(Type.A, "192.168.123.456")
        self.rr = ResourceRecord("invalid.invalid", Type.A, Class.IN, 3,
                                 record_data)

        cache = RecordCache()
        cache.add_record(self.rr)
        cache.write_cache_file()
コード例 #13
0
 def read_cache_file(self):
     """Read the cache file from disk"""
     dcts = []
     try:
         with open("cache", "r") as file_:
             dcts = json.load(file_)
     except:
         print("could not read cache")
     self.records = [ResourceRecord.from_dict(dct) for dct in dcts]
コード例 #14
0
 def test_cache_lookup(self):
     """
     Add a record to the cache and look it up
     """
     rr = ResourceRecord("wiki.nl", Type.A, Class.IN, self.ttl,
                         RecordData.create(Type.A, "192.168.123.456"))
     cache = RecordCache()
     cache.add_record(rr)
     lookup_vals = cache.lookup("wiki.nl", Type.A, Class.IN)
     self.assertEqual([rr], lookup_vals)
コード例 #15
0
    def analyze_response(self, response):
        additionals = list(
        )  # this list makes sure no cache lookups for additional information are necessary.
        for additional_rr in response.additionals:
            try:
                self.CACHE.add_record(additional_rr)
                additionals.append(additional_rr)
            except CacheException:
                pass

        for answer_rr in response.answers:
            if answer_rr.type_ == Type.A:
                self.CACHE.add_record(answer_rr)
                self.addresses.append(answer_rr.rdata.data)
            elif answer_rr.type_ == Type.CNAME:
                self.CACHE.add_record(answer_rr)
                new_sname = answer_rr.rdata.data
                try:
                    cname_resolver = Resolver(self.caching, self.CACHE)
                    self.SNAME, self.addresses, self.aliases = cname_resolver.gethostbyname(
                        new_sname)
                except ResolverException:
                    pass
                return
            else:
                raise ResolverException(RCode.FormErr)
        if response.answers:
            for additional in additionals:
                self.aliases.append(additional.rdata.data)
            return

        new_slist = list()
        for authority in response.authorities:
            rr = ResourceRecord(authority.name, authority.type_,
                                authority.class_, authority.ttl,
                                authority.rdata)
            if rr.type_ == Type.NS:
                self.CACHE.add_record(rr)
                ip = None
                for additional in additionals:
                    if additional.name == rr.rdata.data and additional.type_ == Type.A:
                        ip = additional.rdata.data
                new_slist.append((rr.rdata.data, ip))
            elif rr.type_ == Type.SOA:
                pass
            else:
                raise ResolverException(RCode.FormErr)
        if new_slist:
            try:
                next_resolver = Resolver(self.caching, self.CACHE)
                self.SNAME, self.addresses, self.aliases = next_resolver.gethostbyname(
                    self.SNAME, new_slist)
            except ResolverException:
                pass
 def test_expired_cache_entry(self):
     cache = RecordCache(0)
     record = ResourceRecord(
         name=Name("bonobo.putin"),
         type_=Type.A,
         class_=Class.IN,
         ttl=0,
         rdata=ARecordData("1.0.0.1"),
     )
     cache.add_record(record)
     self.assertEqual(cache.lookup(Name("bonobo.putin"), Type.A, Class.IN),
                      None)
 def test_invalid_domain_from_cache(self):
     cache = RecordCache(0)
     record = ResourceRecord(
         name=Name("bonobo.putin"),
         type_=Type.A,
         class_=Class.IN,
         ttl=60,
         rdata=ARecordData("1.0.0.1"),
     )
     cache.add_record(record)
     self.assertEqual(cache.lookup(Name("bonobo.putin"), Type.A, Class.IN),
                      record)
 def test_expired_cache_entry(self):
     cache = RecordCache(0)
     resolver = Resolver(5, cache)
     cache.add_record(
         ResourceRecord(
             name=Name("hw.gumpe"),
             type_=Type.A,
             class_=Class.IN,
             ttl=0,
             rdata=ARecordData("1.0.0.2"),
         ))
     cache.add_record(
         ResourceRecord(
             name=Name("hw.gumpe"),
             type_=Type.CNAME,
             class_=Class.IN,
             ttl=0,
             rdata=CNAMERecordData(Name("gumpe.hw")),
         ))
     self.assertEqual(resolver.gethostbyname("hw.gumpe"),
                      ("hw.gumpe", [], []))
 def test_invalid_domain_from_cache(self):
     cache = RecordCache(0)
     resolver = Resolver(5, cache)
     cache.add_record(
         ResourceRecord(
             name=Name("bonobo.putin"),
             type_=Type.A,
             class_=Class.IN,
             ttl=60,
             rdata=ARecordData("1.0.0.1"),
         ))
     cache.add_record(
         ResourceRecord(
             name=Name("bonobo.putin"),
             type_=Type.CNAME,
             class_=Class.IN,
             ttl=60,
             rdata=CNAMERecordData(Name("putin.bonobo")),
         ))
     self.assertEqual(resolver.gethostbyname("bonobo.putin"),
                      ("bonobo.putin", ["putin.bonobo."], ["1.0.0.1"]))
コード例 #20
0
    def read_master_file(self, filename):
        """Read the zone from a master file

        See section 5 of RFC 1035.

        Args:
            filename (str): the filename of the master file
        """
        typeData = {"NS": "nsdname", "A": "address", "CNAME": "cname"}
        try:
            with open(filename, "r") as file_:
                for l in file_:
                    rr = l.split(";")[0]
                    if not rr:
                        continue
                    entries = re.split("[\\n]?[\ +]*[\\t+]*", rr)[:-1]
                    name = entries[0]
                    ttl = int(entries[1])
                    type_ = entries[2]
                    address = entries[3]

                    if type_ not in typeData:
                        continue

                    rr = {
                        "type": type_,
                        "name": name,
                        "class": "IN",
                        "ttl": ttl,
                        "rdata": {
                            typeData[type_]: address
                        }
                    }
                    if name not in self.records:
                        self.records[name] = [ResourceRecord.from_dict(rr)]
                    else:
                        self.records[name].append(ResourceRecord.from_dict(rr))
        except:
            print("could not read zone file")
        return self
コード例 #21
0
    def test_TTL_expiration(self):
        """
        cache a record, wait till ttl expires, see if record is removed from cache
        """
        rr = ResourceRecord("wiki.nl", Type.A, Class.IN, self.ttl,
                            RecordData.create(Type.A, "192.168.123.456"))
        cache = RecordCache()
        cache.add_record(rr)

        time.sleep(rr.ttl)

        lookup_vals = cache.lookup("wiki.nl", Type.A, Class.IN)
        self.assertFalse(lookup_vals)
コード例 #22
0
    def resource_from_json(dct):
        """ Convert JSON object to ResourceRecord

        Usage:
            records = json.loads(string, object_hook=resource_from_json)
        """
        name = dct["name"]
        type_ = Type.from_string(dct["type"])
        class_ = Class.from_string(dct["class"])
        ttl = dct["ttl"]
        rdata = RecordData.create(type_, dct["rdata"])
        t = dct["time"]
        return ResourceRecord(name, type_, class_, ttl, rdata, t)
 def test_ttl_overwrite(self):
     cache = RecordCache(60)
     record = ResourceRecord(
         name=Name("bonobo.putin"),
         type_=Type.A,
         class_=Class.IN,
         ttl=0,
         rdata=ARecordData("1.0.0.1"),
     )
     cache.add_record(record)
     cache_entry = cache.lookup(Name("bonobo.putin"), Type.A, Class.IN)
     self.assertEqual(cache_entry, record)
     self.assertEqual(cache_entry.ttl, 60)
コード例 #24
0
    def from_bytes(cls, packet):
        """ Create Message from bytes

        Args:
            packet (bytes): byte representation of the message
        """
        parser = Parser()

        # Parse header
        header, offset = Header.from_bytes(packet), 12

        # Parse questions
        questions = []
        for _ in range(header.qd_count):
            question, offset = Question.from_bytes(packet, offset, parser)
            questions.append(question)

        # Parse answers
        answers = []
        for _ in range(header.an_count):
            answer, offset = ResourceRecord.from_bytes(packet, offset, parser)
            answers.append(answer)

        # Parse authorities
        authorities = []
        for _ in range(header.ns_count):
            authority, offset = ResourceRecord.from_bytes(packet, offset, parser)
            authorities.append(authority)

        # Parse additionals
        additionals = []
        for _ in range(header.ar_count):
            additional, offset = ResourceRecord.from_bytes(packet, offset, parser)
            additionals.append(additional)

        return cls(header, questions, answers, authorities, additionals)
コード例 #25
0
    def load_and_parse(self, content):
        content = re.sub(re.compile(";.*?\n"), "\n", content)  #Remove comments
        content = re.sub(re.compile("\n\n*\n"), "\n",
                         content)  #Remove whitespaces
        content = re.sub(re.compile("  * "), " ",
                         content)  #Remove multiple spaces between words
        content = re.sub(re.compile("\t\t*\t"), " ",
                         content)  #Remove tabs between words
        content = re.sub(re.compile("\n *"), "\n",
                         content)  #Remove spaces at start of line
        content = re.sub(re.compile("\n\t*"), "\n",
                         content)  #Remove tabs at start of line
        content = re.compile(r'\(.*?\)', re.DOTALL)\
            .sub(lambda x: x.group().replace('\n', ''), content) #Remove newlines between ()
        content = re.sub(re.compile("\t+"), " ",
                         content)  #Remove tabs between words
        default_ttl = None
        origin = None

        recordSet = []

        for line in content.split('\n'):
            if line[:4] == "$TTL":
                prev_ttl = self.time_to_seconds(line[4:].strip())
            elif line[:7] == "$ORIGIN":
                origin = line[7:].strip()
            elif "SOA" not in line:
                parts = line.split(' ')
                rr_name = parts[0]

                rr_ttl = self.time_to_seconds(parts[1])
                offset = int(rr_ttl == 0)
                if offset:
                    rr_ttl = prev_ttl

                rr_class = Class[parts[1 + offset]]
                rr_type = parts[2 + offset]
                if Type[rr_type] == Type.CNAME or Type[rr_type] == Type.NS:
                    rr_data = RecordData.create(
                        Type[rr_type], Name(parts[3 + offset].rstrip('.')))
                else:
                    rr_data = RecordData.create(Type[rr_type],
                                                parts[3 + offset].rstrip('.'))
                self.add_node(
                    rr_name,
                    ResourceRecord(Name(rr_name), Type[rr_type], rr_class,
                                   rr_ttl, rr_data))
 def test_outside_zone(self):
     question = Question(Name("gaia.cs.umass.edu"), Type.A, Class.IN)
     header = Header(1337, 0, 1, 0, 0, 0)
     header.rd = 1
     query = Message(header, questions=[question])
     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
     s.sendto(query.to_bytes(), (SERVER, PORT))
     data = s.recv(512)
     s.close()
     message = Message.from_bytes(data)
     self.assertEqual(message.answers, [
         ResourceRecord(name=Name("gaia.cs.umass.edu"),
                        type_=Type.A,
                        class_=Class.IN,
                        ttl=0,
                        rdata=ARecordData("128.119.245.12")),
     ])
コード例 #27
0
    def test_cache_disk_io(self):
        """
        Add a record to the cache, write to disk, read from disk, do a lookup
        """
        rr = ResourceRecord("wiki.nl", Type.A, Class.IN, self.ttl,
                            RecordData.create(Type.A, "192.168.123.456"))
        cache = RecordCache()
        cache.write_cache_file()  # overwrite the current cache file

        # add rr to cache and write to disk
        cache.add_record(rr)
        cache.write_cache_file()

        # read from disk again
        new_cache = RecordCache()
        new_cache.read_cache_file()
        lookup_vals = new_cache.lookup("wiki.nl", Type.A, Class.IN)
        self.assertEqual([rr], lookup_vals)
コード例 #28
0
ファイル: cache.py プロジェクト: kliyer-ai/NDS-DNS
    def lookup(self, dname, type_, class_):
        """Lookup resource records in cache

        Lookup for the resource records for a domain name with a specific type
        and class.

        Args:
            dname (str): domain name
            type_ (Type): type
            class_ (Class): class
        """
        dname = Name(dname)
        rrs = [
            ResourceRecord.from_dict(r) for r in self.records
            if (time.time() - r["timestamp"]) < r["ttl"]
        ]
        rs = [
            r for r in rrs
            if r.name == dname and r.class_ == class_ and r.type_ == type_
        ]
        return rs
コード例 #29
0
 def setUpClass(cls):
     cls.ttl = 3
     rr = ResourceRecord("wiki.nl", Type.A, Class.IN, cls.ttl,
                         RecordData.create(Type.A, "192.168.123.456"))
コード例 #30
0
def getType(t):
    if(t == 'A'):
        return Type.A
    if(t == 'NS'):
        return Type.NS
    if(t == 'CNAME'):
        return Type.CNAME

temp = []
"""Read the cache file from disk"""
with open("roothints.md") as file_:
    lines = file_.readlines()
for l in lines:
    #remove comments
    b = re.sub(r';[^\n]*', "", l)
    te = l.split()
    if(te[0] != ';'):
        temp.append(te)
    if("." in te[0]):
        type_ = getType(te[2])
        if(type_ == Type.A):
            rdata = ARecordData(te[3])
        elif(type_ == Type.NS):
            rdata = NSRecordData(te[3])
        elif(type_ == Type.CNAME):
            rdata = CNAMERecordData(te[3])
        rr = ResourceRecord(te[0], type_, Class.IN, te[1], rdata)
        print(rr.to_dict())

    
コード例 #31
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, []))