summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCamil Staps2016-05-30 15:21:17 +0200
committerCamil Staps2016-05-30 15:21:17 +0200
commit61c1214dce59fd19e86bd9362207fb5e658d9a88 (patch)
treee0b004e97b33f111bed6f1255ab74161ec748f0f
parentSimple DNS server (diff)
Fixes for resolver & server; tests for resolver; cloogle zonefile
-rw-r--r--project2/proj2_s4498062/cloogle.zone13
-rw-r--r--project2/proj2_s4498062/dns/cache.py7
-rw-r--r--project2/proj2_s4498062/dns/resolver.py42
-rw-r--r--project2/proj2_s4498062/dns/resource.py4
-rw-r--r--project2/proj2_s4498062/dns/server.py18
-rwxr-xr-xproject2/proj2_s4498062/dns_server.py4
-rwxr-xr-xproject2/proj2_s4498062/dns_tests.py68
-rw-r--r--project2/proj2_s4498062/named.root90
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