def test_no_cache_entry(self): cache = RecordCache(0) resolver = Resolver(5, cache) self.assertEqual( resolver.gethostbyname("google-public-dns-a.google.com"), ("google-public-dns-a.google.com", [], ["8.8.8.8"]), ) self.assertEqual( resolver.gethostbyname("google-public-dns-b.google.com"), ("google-public-dns-b.google.com", [], ["8.8.4.4"]), )
def test_gethostbyname_non_existent(self): resolver = Resolver(5, None) self.assertEqual(resolver.gethostbyname("bonobo.putin"), ("bonobo.putin", [], [])) self.assertEqual(resolver.gethostbyname("gumpenfisch.net"), ("gumpenfisch.net", [], [])) self.assertEqual( resolver.gethostbyname("ThisDomainDoesNotExist.false"), ("ThisDomainDoesNotExist.false", [], [])) self.assertEqual( resolver.gethostbyname("JustSoWeHaveMoreThanThree.domains"), ("JustSoWeHaveMoreThanThree.domains", [], []))
class TestResolver(TestCase): """Resolver tests""" def setUp(self): self.resolver = Resolver(5, True, 0) 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") def test_testTwo(self): time.sleep(4) hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("invalid_address.asdas") self.assertEqual(ipaddrlist, [])
class TestServer(TestCase): def setUp(self): self.resolver = Resolver(5, False, 0, "127.0.0.1") def test_testOne(self): hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("kaas.lol") self.assertEqual("1.1.1.1", ipaddrlist[0]) def test_testTwo(self): hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("ru.nl") self.assertEqual("131.174.78.60", ipaddrlist[0]) def test_testThree(self): hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname("google.com") self.assertEqual([], ipaddrlist)
def resolve(): """Resolve a hostname using the resolver """ parser = ArgumentParser(description="DNS Client") parser.add_argument("hostname", help="hostname to resolve") parser.add_argument("--timeout", metavar="time", type=int, default=5, help="resolver timeout") parser.add_argument("-c", "--caching", action="store_true", help="Enable caching") parser.add_argument("-t", "--ttl", metavar="time", type=int, default=0, help="TTL value of cached entries (if > 0)") args = parser.parse_args() s = SocketWrapper(53) s.start() rc = RecordCache(3600) resolver = Resolver(args.timeout, args.caching, args.ttl, s, rc) hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname) s.shutdown() rc.write_cache_file() print(hostname) print([rr.rdata.address for rr in aliaslist]) print([rr.rdata.address for rr in ipaddrlist])
def test_check_query(self): res = Resolver(5, False, 3600) hostname, alias, ips = res.gethostbyname("nickstracke.xyz") ip1 = ips[0].rdata.address ip2 = socket.gethostbyname("nickstracke.xyz") self.assertEqual(ip1, ip2) res.shutdown()
def resolve(): """Resolve a hostname using the resolver """ parser = ArgumentParser(description="DNS Client") parser.add_argument("hostname", help="hostname to resolve") parser.add_argument("--timeout", metavar="time", type=int, default=5, help="resolver timeout") parser.add_argument("-c", "--caching", action="store_true", help="Enable caching") parser.add_argument("-t", "--ttl", metavar="time", type=int, default=0, help="TTL value of cached entries (if > 0)") args = parser.parse_args() cache = RecordCache(args.ttl) if args.caching: cache.read_cache_file() resolver = Resolver(args.timeout, cache) else: resolver = Resolver(args.timeout) hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname) if args.caching: cache.write_cache_file() print(hostname) print(aliaslist) print(ipaddrlist)
def resolve(): """Resolve a hostname using the resolver """ parser = ArgumentParser(description="DNS Client") parser.add_argument("hostname", help="hostname to resolve") parser.add_argument("--timeout", metavar="time", type=int, default=5, help="resolver timeout") parser.add_argument("-c", "--caching", action="store_true", help="Enable caching") parser.add_argument("-t", "--ttl", metavar="time", type=int, default=0, help="TTL value of cached entries (if > 0)") parser.add_argument("-n", "--nameserver", type=str, default="198.41.0.4", help="set nameserver") args = parser.parse_args() resolver = Resolver(args.timeout, args.caching, args.ttl, args.nameserver) resolver.doLogging = True hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname) print(hostname) print(aliaslist) print(ipaddrlist)
def run(self): """ Run the handler thread """ print "*Ping* We've got a message!" # Handle DNS request resolver = Resolver(self.caching, self.ttl) aliasRecords = [] addressRecords = [] # Read and resolve the questions one-by-one questions = self.request.questions for question in questions: hostname = question.qname (hostname, aliases, addresses) = resolver.gethostbyname(hostname) for alias in aliases: aliasData = dns.resource.RecordData.create(Type.CNAME, alias) aliasRecord = dns.resource.ResourceRecord(hostname, Type.CNAME, Class.IN, 9001, aliasData) # TODO fix ttl aliasRecords.append(aliasRecord) for address in addresses: addressData = dns.resource.RecordData.create(Type.A, address) addressRecord = dns.resource.ResourceRecord(hostname, Type.A, Class.IN, 9001, addressData) addressRecords.append(addressRecord) # Crafting of the response respHeader = self.request.header respHeader.qr = 1 respHeader.qd_count = 0 respHeader.an_count = 1 respMessage = dns.message.Message(respHeader, [], addressRecords + aliasRecords, [], []) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) respMessageByte = respMessage.to_bytes() sock.sendto(respMessageByte, self.clientAddr) print "Ended request: " + hostname sock.close()
def test_gethostbyname(self): resolver = Resolver(5, None) self.assertEqual( resolver.gethostbyname("google-public-dns-a.google.com"), ("google-public-dns-a.google.com", [], ["8.8.8.8"]), ) self.assertEqual( resolver.gethostbyname("google-public-dns-b.google.com"), ("google-public-dns-b.google.com", [], ["8.8.4.4"]), ) self.assertEqual( resolver.gethostbyname("con1.nipr.mil"), ("con1.nipr.mil", [], ["199.252.157.234"]), ) self.assertEqual( # recommended domain to test resolver.gethostbyname("gaia.cs.umass.edu"), ("gaia.cs.umass.edu", [], ["128.119.245.12"]), )
class TestResolverCache(TestCase): """Resolver tests with cache enabled""" def setUp(self): self.RC = RecordCache(100, "dns/ResolverTestCache.cache") #never written to self.res = Resolver(5, True, -1) def test_resolver_caching(self): hostname = "google.com" t = time.time() self.res.gethostbyname(hostname) d1 = time.time() - t t = time.time() self.res.gethostbyname(hostname) d2 = time.time() - t self.assertTrue(d2 < d1) def tearDown(self): self.res.shutdown()
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 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 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", [], []))
metavar="time", type=int, default=Consts.DEFAULT_TIMEOUT, help="resolver timeout") parser.add_argument("-c", "--caching", action="store_true", help="Enable caching") parser.add_argument("-t", "--ttl", metavar="time", type=int, default=0, help="TTL value of cached entries") args = parser.parse_args() if not args.hostname: parser.print_help() exit() # Resolve hostname resolver = Resolver(args.timeout, args.caching, args.ttl) hostname, aliaslist, ipaddrlist = resolver.gethostbyname(args.hostname) if args.caching: resolver.cache.write_cache_file() # Print output print(hostname) print(aliaslist) print(ipaddrlist)
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
class RequestHandler(Thread): """A handler for requests to the DNS server""" def __init__(self, data, addr, catalog, sock, caching, cache, ttl=0): """Initialize the handler thread""" super().__init__() self.daemon = True self.data = data self.addr = addr self.catalog = catalog self.cache = cache self.resolver = Resolver(5, caching, ttl, sock, self.cache) self.sock = sock def run(self): """ Run the handler thread""" mess = self.data rd = mess.header.rd questions = mess.questions for q in questions: name = q.qname class_ = q.qclass type_ = q.qtype zone_resolution = self.resolveZone(str(name), type_, class_) if zone_resolution: mess.additionals += zone_resolution["additionals"] mess.authorities += zone_resolution["authorities"] mess.answers += zone_resolution["answers"] if type_ != Type.CNAME: cnames = [ rr for rr in zone_resolution["answers"] if rr.type_ == Type.CNAME ] for cn in cnames: questions.append( Question(cn.rdata.cname, Type.A, cn.class_)) mess.header.aa = 1 continue cached_rrs = self.cache.lookup(str(name), type_, class_) cached_cname = self.cache.lookup(str(name), Type.CNAME, class_) if cached_rrs: mess.answers += cached_rrs continue elif cached_cname and type_ != Type.CNAME: for rr in cached_cname: mess.answer.append(rr) questions.append(Question(rr.rdata.cname, type_, class_)) continue elif not rd: matched = self.cache.matchByLabel(str(name), Type.NS, class_) mess.authorities += matched for m in matched: glue = self.cache.lookup(str(m.rdata.nsdname), Type.A, class_) mess.additionals += glue continue if rd: hostname, aliaslist, ipaddrlist = self.resolver.gethostbyname( str(name)) mess.answers += aliaslist mess.answers += ipaddrlist mess.header.ra = 1 continue # adjust header mess.header.qr = 1 mess.header.qd_count = len(mess.questions) mess.header.an_count = len(mess.answers) mess.header.ns_count = len(mess.authorities) mess.header.ar_count = len(mess.additionals) msg = (mess, self.addr[0], self.addr[1]) self.sock.send(msg) self.cache.write_cache_file( ) #write the cached records so they dont get lost def resolveZone(self, name, type_, class_): name = Name(name) root_domain = name.labels[-2:] root_domain = root_domain[0] + "." + root_domain[1] if root_domain not in self.catalog.zones: return {} zone = self.catalog.zones[root_domain] current_domain = name if str(current_domain) in zone.records: records = zone.records[str(current_domain)] rrs_a = [ rr for rr in records if (rr.type_ == Type.A or rr.type_ == Type.CNAME) and rr.class_ == Class.IN ] if rrs_a: return {"answers": rrs_a, "additionals": [], "authorities": []} while True: if str(current_domain) in zone.records: records = zone.records[str(current_domain)] rrs_ns = [ rr for rr in records if rr.type_ == Type.NS and rr.class_ == Class.IN ] if rrs_ns: ret = { "answers": [], "authorities": rrs_ns, "additionals": [] } for rr_ns in rrs_ns: ns_name = str(rr_ns.rdata.nsdname) if ns_name in zone.records: ns_records = zone.records[ns_name] glue = [ rr for rr in ns_records if rr.type_ == Type.A and rr.class_ == Class.IN ] ret["additionals"] += glue return ret current_domain.labels = current_domain.labels[1:] if not current_domain.labels: break return {}
def testResolver(self): res = Resolver(0, False, 0) self.assertEqual(res.gethostbyname("google.com")[0], "google.com") self.assertEqual( res.gethostbyname("symposium.thalia.nu")[2], res.gethostbyname("reis.thalia.nu")[2])