diff options
author | Camil Staps | 2016-05-30 15:21:17 +0200 |
---|---|---|
committer | Camil Staps | 2016-05-30 15:21:17 +0200 |
commit | 61c1214dce59fd19e86bd9362207fb5e658d9a88 (patch) | |
tree | e0b004e97b33f111bed6f1255ab74161ec748f0f | |
parent | Simple DNS server (diff) |
Fixes for resolver & server; tests for resolver; cloogle zonefile
-rw-r--r-- | project2/proj2_s4498062/cloogle.zone | 13 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/cache.py | 7 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/resolver.py | 42 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/resource.py | 4 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/server.py | 18 | ||||
-rwxr-xr-x | project2/proj2_s4498062/dns_server.py | 4 | ||||
-rwxr-xr-x | project2/proj2_s4498062/dns_tests.py | 68 | ||||
-rw-r--r-- | project2/proj2_s4498062/named.root | 90 |
8 files changed, 105 insertions, 141 deletions
diff --git a/project2/proj2_s4498062/cloogle.zone b/project2/proj2_s4498062/cloogle.zone new file mode 100644 index 0000000..807b3f8 --- /dev/null +++ b/project2/proj2_s4498062/cloogle.zone @@ -0,0 +1,13 @@ +; vim: ft=bindzone: +; The Cloogle zone file + +cloogle.org. 3600000 NS ns1.p01.antagonist.nl +cloogle.org. 3600000 NS ns2.p01.antagonist.net +cloogle.org. 3600000 NS ns3.p01.antagonist.de + +cloogle.org. 3600000 A 84.22.111.158 +cloogle.org. 3600000 AAAA 2a02:2770:17:0:21a:4aff:fe1d:9a23 + +www.cloogle.org. 3600000 CNAME cloogle.org + +; End of file diff --git a/project2/proj2_s4498062/dns/cache.py b/project2/proj2_s4498062/dns/cache.py index 9cde66f..a8b62be 100644 --- a/project2/proj2_s4498062/dns/cache.py +++ b/project2/proj2_s4498062/dns/cache.py @@ -53,7 +53,7 @@ class RecordCache(object): FILE = '.dns.cache' - def __init__(self): + def __init__(self, ttl): """ Initialize the RecordCache Args: @@ -61,15 +61,16 @@ class RecordCache(object): """ self.records = [] self.read_cache_file() + self.ttl = ttl def __del__(self): self.write_cache_file() def remove_old(self): """Remove entries for which the TTL has expired""" - now = int(time.clock()) + now = int(time.time()) for record in reversed(self.records): - if record.ttl + record.timestamp < now: + if min(self.ttl, record.ttl) + record.timestamp < now: self.records.remove(record) def lookup(self, dname, type_, class_): diff --git a/project2/proj2_s4498062/dns/resolver.py b/project2/proj2_s4498062/dns/resolver.py index 2c22adb..4c09681 100644 --- a/project2/proj2_s4498062/dns/resolver.py +++ b/project2/proj2_s4498062/dns/resolver.py @@ -48,7 +48,7 @@ class Resolver(object): self.timeout = timeout if self.caching: - self.cache = RecordCache() + self.cache = RecordCache(ttl) def do_query(self, hint, hostname, type_, class_=Class.IN, caching=True): """Do a query to a hint""" @@ -98,9 +98,6 @@ class Resolver(object): Returns: (str, [str], [str]): (hostname, aliaslist, ipaddrlist) """ - domains = hostname.split('.') - hints = self.ROOT_SERVERS - if self.caching: addrs = self.cache.lookup(hostname, Type.A, Class.IN) cnames = self.cache.lookup(hostname, Type.CNAME, Class.IN) @@ -109,66 +106,45 @@ class Resolver(object): [r.rdata.data for r in cnames], \ [r.rdata.data for r in addrs] for cname in cnames: - print 'trying', cname.rdata.data cname, aliases, addrs = self.gethostbyname(cname.rdata.data) if addrs != []: return str(cname), aliases, addrs - if domains == []: + if hostname == '': return hostname, [], [] - domain = domains.pop(-1) + hints = self.ROOT_SERVERS[:] aliases = [] while hints != []: - hints, info = self.do_query_to_multiple(hints, domain, Type.A) + hints, info = self.do_query_to_multiple(hints, hostname, Type.A) aliases += [ r.rdata.data for r in info - if r.match(type_=Type.CNAME, class_=Class.IN, name=domain)] + if r.match(type_=Type.CNAME, class_=Class.IN, name=hostname)] # Case 1: answer ips = [ r.rdata.data for r in info - if r.match(type_=Type.A, class_=Class.IN, name=domain)] + if r.match(type_=Type.A, class_=Class.IN, name=hostname)] if ips != []: return hostname, aliases, ips - # Case 2: name servers for this domain + # Case 2: name servers auths = [ r.rdata.data for r in info - if r.match(type_=Type.NS, class_=Class.IN, name=domain)] + if r.match(type_=Type.NS, class_=Class.IN)] ips = [ add.rdata.data for ns in auths for add in info if add.match(name=ns, type_=Type.A)] if ips != []: hints += ips - if domain != hostname: - domain = domains.pop(-1) + '.' + domain continue if auths != []: auths = [h for a in auths for h in self.gethostbyname(a)[2]] hints += auths - if domain != hostname: - domain = domains.pop(-1) + '.' + domain - continue - - # Case 3: name servers for the same domain - parent = '.'.join(domain.split('.')[1:]) - auths = [ - r.rdata.data for r in info - if r.match(type_=Type.NS, class_=Class.IN, name=parent)] - ips = [ - add.rdata.data for ns in auths for add in info - if add.match(name=ns, type_=Type.A)] - if ips != []: - hints += ips - continue - if auths != []: - auths = [h for r in auths for h in self.gethostbyname(r)[2]] - hints += auths continue - # Case 4: aliases + # Case 3: aliases for alias in aliases: _, extra_aliases, alias_addresses = self.gethostbyname(alias) if alias_addresses != []: diff --git a/project2/proj2_s4498062/dns/resource.py b/project2/proj2_s4498062/dns/resource.py index b1c8ae4..e552c22 100644 --- a/project2/proj2_s4498062/dns/resource.py +++ b/project2/proj2_s4498062/dns/resource.py @@ -14,7 +14,7 @@ from dns.types import Type class ResourceRecord(object): """ DNS resource record """ - def __init__(self, name, type_, class_, ttl, rdata, timestamp=time.time()): + def __init__(self, name, type_, class_, ttl, rdata, timestamp=None): """ Create a new resource record Args: @@ -28,7 +28,7 @@ class ResourceRecord(object): self.class_ = class_ self.ttl = ttl self.rdata = rdata - self.timestamp = timestamp + self.timestamp = int(timestamp or time.time()) def match(self, name=None, type_=None, class_=None, ttl=None): """Check if the record matches properties""" diff --git a/project2/proj2_s4498062/dns/server.py b/project2/proj2_s4498062/dns/server.py index f830651..10cad8b 100644 --- a/project2/proj2_s4498062/dns/server.py +++ b/project2/proj2_s4498062/dns/server.py @@ -12,7 +12,8 @@ from dns.classes import Class from dns.types import Type from dns.message import Header, Message from dns.resolver import Resolver -from dns.resource import ResourceRecord, ARecordData, CNAMERecordData +from dns.resource import \ + ResourceRecord, ARecordData, NSRecordData, CNAMERecordData class RequestHandler(Thread): @@ -112,12 +113,21 @@ class Server(object): ttl, class_ = 3600000, Class.IN for match in re.finditer(rgx.ZONE_LINE_DOMAIN, zone, re.MULTILINE): match = match.groups() - name = match[0] - ttl = int(match[1] or match[4] or ttl) + name = match[0][:-1] + ttl = int(match[1] or match[4] or ttl * 1000) / 1000 class_ = Class.from_string( match[2] or match[3] or Class.to_string(class_)) type_ = Type.from_string(match[5]) data = match[6] - record = ResourceRecord(name, type_, class_, ttl, data) + if type_ == Type.A: + cls = ARecordData + elif type_ == Type.NS: + cls = NSRecordData + elif type_ == Type.CNAME: + cls = CNAMERecordData + else: + continue + + record = ResourceRecord(name, type_, class_, ttl, cls(data)) self.zone.append(record) diff --git a/project2/proj2_s4498062/dns_server.py b/project2/proj2_s4498062/dns_server.py index 41d837a..3bdd04d 100755 --- a/project2/proj2_s4498062/dns_server.py +++ b/project2/proj2_s4498062/dns_server.py @@ -20,13 +20,13 @@ def main(): "-t", "--ttl", metavar="time", type=int, default=0, help="TTL value of cached entries (if > 0)") parser.add_argument( - "-p", "--port", type=int, default=5353, + "-p", "--port", type=int, default=5300, help="Port which server listens on") args = parser.parse_args() # Start server server = dns.server.Server(args.port, args.caching, args.ttl) - server.parse_zone_file('named.root') + server.parse_zone_file('cloogle.zone') try: server.serve() diff --git a/project2/proj2_s4498062/dns_tests.py b/project2/proj2_s4498062/dns_tests.py index 26bc00b..4a054b6 100755 --- a/project2/proj2_s4498062/dns_tests.py +++ b/project2/proj2_s4498062/dns_tests.py @@ -1,16 +1,70 @@ #!/usr/bin/env python2 +""" Tests for the DNS resolver and server """ -""" Tests for your DNS resolver and server """ +import sys +import time +import unittest -portnr = 5353 -server = "localhost" +from dns.cache import RecordCache +from dns.classes import Class +from dns.resolver import Resolver +from dns.resource import ResourceRecord, CNAMERecordData +from dns.types import Type + +portnr = 5300 +server = '127.0.0.1' class TestResolver(unittest.TestCase): - pass + """Test cases for the resolver with caching disabled""" + + def setUp(self): + self.resolv = Resolver(False, 0) + + def test_solve(self): + """Test solving some FQDN""" + host, aliases, addrs = self.resolv.gethostbyname('camilstaps.nl') + self.assertEqual(host, 'camilstaps.nl') + self.assertEqual(aliases, []) + self.assertEqual(addrs, ['84.22.111.158']) + + def test_nonexistant(self): + """Test solving a nonexistant FQDN""" + host, aliases, addrs = self.resolv.gethostbyname('nothing.ru.nl') + self.assertEqual(host, 'nothing.ru.nl') + self.assertEqual(aliases, []) + self.assertEqual(addrs, []) class TestResolverCache(unittest.TestCase): - pass + """Test cases for the resolver with caching enabled""" + + TTL = 3 + + def setup_resolver(self): + """Setup a resolver with an invalid cache""" + self.resolv = Resolver(True, self.TTL) + self.cache = RecordCache(self.TTL) + self.cache.add_record(ResourceRecord( + 'nothing.ru.nl', Type.CNAME, Class.IN, self.TTL, + CNAMERecordData('camilstaps.nl'))) + self.resolv.cache = self.cache + + def test_solve_invalid(self): + """Test solving an invalid cached FQDN""" + self.setup_resolver() + host, aliases, addrs = self.resolv.gethostbyname('nothing.ru.nl') + self.assertEqual(host, 'camilstaps.nl') + self.assertEqual(aliases, []) + self.assertEqual(addrs, ['84.22.111.158']) + + def test_solve_invalid_after_expiration(self): + """Test solving an invalid cached FQDN after TTL expiration""" + self.setup_resolver() + time.sleep(self.TTL + 1) + host, aliases, addrs = self.resolv.gethostbyname('nothing.ru.nl') + self.assertEqual(host, 'nothing.ru.nl') + self.assertEqual(aliases, []) + self.assertEqual(addrs, []) class TestServer(unittest.TestCase): @@ -22,11 +76,11 @@ if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="HTTP Tests") parser.add_argument("-s", "--server", type=str, default="localhost") - parser.add_argument("-p", "--port", type=int, default=5001) + parser.add_argument("-p", "--port", type=int, default=5300) args, extra = parser.parse_known_args() portnr = args.port server = args.server - + # Pass the extra arguments to unittest sys.argv[1:] = extra diff --git a/project2/proj2_s4498062/named.root b/project2/proj2_s4498062/named.root deleted file mode 100644 index 3c82146..0000000 --- a/project2/proj2_s4498062/named.root +++ /dev/null @@ -1,90 +0,0 @@ -; This file holds the information on root name servers needed to -; initialize cache of Internet domain name servers -; (e.g. reference this file in the "cache . <file>" -; configuration file of BIND domain name servers). -; -; This file is made available by InterNIC -; under anonymous FTP as -; file /domain/named.cache -; on server FTP.INTERNIC.NET -; -OR- RS.INTERNIC.NET -; -; last update: March 23, 2016 -; related version of root zone: 2016032301 -; -; formerly NS.INTERNIC.NET -; -. 3600000 NS A.ROOT-SERVERS.NET. -A.ROOT-SERVERS.NET. 3600000 A 198.41.0.4 -A.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:ba3e::2:30 -; -; FORMERLY NS1.ISI.EDU -; -. 3600000 NS B.ROOT-SERVERS.NET. -B.ROOT-SERVERS.NET. 3600000 A 192.228.79.201 -B.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:84::b -; -; FORMERLY C.PSI.NET -; -. 3600000 NS C.ROOT-SERVERS.NET. -C.ROOT-SERVERS.NET. 3600000 A 192.33.4.12 -C.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2::c -; -; FORMERLY TERP.UMD.EDU -; -. 3600000 NS D.ROOT-SERVERS.NET. -D.ROOT-SERVERS.NET. 3600000 A 199.7.91.13 -D.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2d::d -; -; FORMERLY NS.NASA.GOV -; -. 3600000 NS E.ROOT-SERVERS.NET. -E.ROOT-SERVERS.NET. 3600000 A 192.203.230.10 -; -; FORMERLY NS.ISC.ORG -; -. 3600000 NS F.ROOT-SERVERS.NET. -F.ROOT-SERVERS.NET. 3600000 A 192.5.5.241 -F.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2f::f -; -; FORMERLY NS.NIC.DDN.MIL -; -. 3600000 NS G.ROOT-SERVERS.NET. -G.ROOT-SERVERS.NET. 3600000 A 192.112.36.4 -; -; FORMERLY AOS.ARL.ARMY.MIL -; -. 3600000 NS H.ROOT-SERVERS.NET. -H.ROOT-SERVERS.NET. 3600000 A 198.97.190.53 -H.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:1::53 -; -; FORMERLY NIC.NORDU.NET -; -. 3600000 NS I.ROOT-SERVERS.NET. -I.ROOT-SERVERS.NET. 3600000 A 192.36.148.17 -I.ROOT-SERVERS.NET. 3600000 AAAA 2001:7fe::53 -; -; OPERATED BY VERISIGN, INC. -; -. 3600000 NS J.ROOT-SERVERS.NET. -J.ROOT-SERVERS.NET. 3600000 A 192.58.128.30 -J.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:c27::2:30 -; -; OPERATED BY RIPE NCC -; -. 3600000 NS K.ROOT-SERVERS.NET. -K.ROOT-SERVERS.NET. 3600000 A 193.0.14.129 -K.ROOT-SERVERS.NET. 3600000 AAAA 2001:7fd::1 -; -; OPERATED BY ICANN -; -. 3600000 NS L.ROOT-SERVERS.NET. -L.ROOT-SERVERS.NET. 3600000 A 199.7.83.42 -L.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:9f::42 -; -; OPERATED BY WIDE -; -. 3600000 NS M.ROOT-SERVERS.NET. -M.ROOT-SERVERS.NET. 3600000 A 202.12.27.33 -M.ROOT-SERVERS.NET. 3600000 AAAA 2001:dc3::35 -; End of file |