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"), ), ])
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])
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)
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})
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_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)
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")), ])
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"]))
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())
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)
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
def test_testOne(self): RR = ResourceRecord(Name("invalid_address.asdas"), Type.A, Class.IN, 2, ARecordData("1.4.1")) self.resolver.cache.add_record(RR) hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("invalid_address.asdas") self.assertEqual(ipaddrlist[0], "1.4.1")