diff options
Diffstat (limited to 'project2/proj2_s4498062')
-rw-r--r-- | project2/proj2_s4498062/dns/__init__.py | 1 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/cache.py | 18 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/classes.py | 6 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/domainname.py | 29 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/message.py | 81 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/rcodes.py | 6 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/resolver.py | 23 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/resource.py | 42 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/server.py | 10 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns/types.py | 6 | ||||
-rw-r--r-- | project2/proj2_s4498062/dns_tests.py | 8 |
11 files changed, 126 insertions, 104 deletions
diff --git a/project2/proj2_s4498062/dns/__init__.py b/project2/proj2_s4498062/dns/__init__.py index 18ff536..e69de29 100644 --- a/project2/proj2_s4498062/dns/__init__.py +++ b/project2/proj2_s4498062/dns/__init__.py @@ -1 +0,0 @@ -#!/usr/bin/env python2 diff --git a/project2/proj2_s4498062/dns/cache.py b/project2/proj2_s4498062/dns/cache.py index eab51c5..3ef14b3 100644 --- a/project2/proj2_s4498062/dns/cache.py +++ b/project2/proj2_s4498062/dns/cache.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 - """A cache for resource records This module contains a class which implements a cache for DNS resource records, @@ -17,7 +15,7 @@ from dns.classes import Class class ResourceEncoder(json.JSONEncoder): """ Conver ResourceRecord to JSON - + Usage: string = json.dumps(records, cls=ResourceEncoder, indent=4) """ @@ -35,7 +33,7 @@ class ResourceEncoder(json.JSONEncoder): def resource_from_json(dct): """ Convert JSON object to ResourceRecord - + Usage: records = json.loads(string, object_hook=resource_from_json) """ @@ -52,7 +50,7 @@ class RecordCache(object): def __init__(self, ttl): """ Initialize the RecordCache - + Args: ttl (int): TTL of cached entries (if > 0) """ @@ -64,22 +62,22 @@ class RecordCache(object): 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 """ pass - + def add_record(self, record): """ Add a new Record to the cache - + Args: record (ResourceRecord): the record added to the cache """ pass - + def read_cache_file(self): """ Read the cache file from disk """ pass @@ -87,5 +85,3 @@ class RecordCache(object): def write_cache_file(self): """ Write the cache file to disk """ pass - - diff --git a/project2/proj2_s4498062/dns/classes.py b/project2/proj2_s4498062/dns/classes.py index 767b2f6..9446f01 100644 --- a/project2/proj2_s4498062/dns/classes.py +++ b/project2/proj2_s4498062/dns/classes.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 - """ DNS CLASS and QCLASS values This module contains an Enum of CLASS and QCLASS values. The Enum also contains @@ -10,7 +8,7 @@ a method for converting values to strings. See sections 3.2.4 and 3.2.5 of RFC class Class(object): """ Enum of CLASS and QCLASS values - + Usage: >>> Class.IN 1 @@ -36,8 +34,10 @@ class Class(object): @staticmethod def to_string(class_): + """Convert a class to a string""" return Class.by_value[class_] @staticmethod def from_string(string): + """Convert a string to a class""" return Class.by_string[string] diff --git a/project2/proj2_s4498062/dns/domainname.py b/project2/proj2_s4498062/dns/domainname.py index 85e14bf..6dbb039 100644 --- a/project2/proj2_s4498062/dns/domainname.py +++ b/project2/proj2_s4498062/dns/domainname.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 - """ Parsing and composing domain names This module contains two classes for converting domain names to and from bytes. @@ -14,20 +12,20 @@ import struct class Composer(object): def __init__(self): self.offsets = dict() - + def to_bytes(self, offset, dnames): # Convert each domain name in to bytes result = b"" - for i, dname in enumerate(dnames): + for _, dname in enumerate(dnames): # Split domain name into labels labels = dname.split(".") - + # Determine keys of subdomains in offset dict keys = [] for label in reversed(labels): name = label if keys: - name += "." + keys[-1] + name += "." + keys[-1] keys.append(name) keys.reverse() @@ -43,9 +41,10 @@ class Composer(object): break else: self.offsets[keys[j]] = offset - result += struct.pack("!B{}s".format(len(label)), - len(label), - label) + result += struct.pack( + "!B{}s".format(len(label)), + len(label), + label) offset += 1 + len(label) # Add null character at end @@ -61,11 +60,10 @@ class Parser(object): self.labels = dict() def from_bytes(self, packet, offset, num): - begin_offset = offset dnames = [] # Read the domain names - for i in range(num): + for _ in range(num): # Read a new domain name dname = "" prev_offsets = [] @@ -78,7 +76,7 @@ class Parser(object): if llength == 0: offset += 1 break - + # Compression label elif (llength >> 6) == 3: new_offset = offset + 2 @@ -90,8 +88,9 @@ class Parser(object): # Normal label else: new_offset = offset + llength + 1 - label = struct.unpack_from("{}s".format(llength), - packet, offset+1)[0] + label = struct.unpack_from( + "{}s".format(llength), + packet, offset+1)[0] # Add label to dictionary self.labels[offset] = label @@ -109,5 +108,5 @@ class Parser(object): # Append domain name to list dnames.append(dname) - + return dnames, offset diff --git a/project2/proj2_s4498062/dns/message.py b/project2/proj2_s4498062/dns/message.py index 3c86443..9f8ead4 100644 --- a/project2/proj2_s4498062/dns/message.py +++ b/project2/proj2_s4498062/dns/message.py @@ -1,26 +1,23 @@ -#!/usr/bin/env python2 - """ DNS messages This module contains classes for DNS messages, their header section and question fields. See section 4 of RFC 1035 for more info. """ -import socket import struct -from dns.classes import Class from dns.domainname import Parser, Composer from dns.resource import ResourceRecord -from dns.types import Type class Message(object): """ DNS message """ - def __init__(self, header, questions=[], answers=[], authorities=[], additionals=[]): + def __init__( + self, header, questions=[], answers=[], authorities=[], + additionals=[]): """ Create a new DNS message - + Args: header (Header): the header section questions ([Question]): the question section @@ -82,40 +79,40 @@ class Message(object): # Parse questions questions = [] - for i in range(header.qd_count): + for _ in range(header.qd_count): question, offset = Question.from_bytes(packet, offset, parser) questions.append(question) # Parse answers answers = [] - for i in range(header.an_count): + for _ in range(header.an_count): answer, offset = ResourceRecord.from_bytes(packet, offset, parser) answers.append(answer) # Parse authorities authorities = [] - for i in range(header.ns_count): - authority, offset = ResourceRecord.from_bytes(packet, offset, parser) - authorities.append(authority) + for _ in range(header.ns_count): + auth, offset = ResourceRecord.from_bytes(packet, offset, parser) + authorities.append(auth) # Parse additionals additionals = [] - for i in range(header.ar_count): - additional, offset = ResourceRecord.from_bytes(packet, offset, parser) - additionals.append(additional) + for _ in range(header.ar_count): + add, offset = ResourceRecord.from_bytes(packet, offset, parser) + additionals.append(add) return cls(header, questions, answers, authorities, additionals) class Header(object): """ The header section of a DNS message - + Contains a number of properties which are accessible as normal member variables. See section 4.1.1 of RFC 1035 for their meaning. """ - + def __init__(self, ident, flags, qd_count, an_count, ns_count, ar_count): """ Create a new Header object @@ -135,13 +132,14 @@ class Header(object): def to_bytes(self): """ Convert header to bytes """ - return struct.pack("!6H", - self.ident, - self._flags, - self.qd_count, - self.an_count, - self.ns_count, - self.ar_count) + return struct.pack( + "!6H", + self.ident, + self._flags, + self.qd_count, + self.an_count, + self.ns_count, + self.ar_count) @classmethod def from_bytes(cls, packet): @@ -149,21 +147,27 @@ class Header(object): if len(packet) < 12: raise ShortHeader return cls(*struct.unpack_from("!6H", packet)) - + @property def flags(self): + """The flags of the header""" return self._flags + @flags.setter def flags(self, value): + """Set the flags of the header""" if value >= (1 << 16): raise ValueError("value too big for flags") self._flags = value @property def qr(self): + """The QR flag""" return self._flags & (1 << 15) + @qr.setter def qr(self, value): + """Set the QR flag""" if value: self._flags |= (1 << 15) else: @@ -171,9 +175,12 @@ class Header(object): @property def opcode(self): + """The opcode of the header""" return (self._flags & (((1 << 4) - 1) << 11)) >> 11 + @opcode.setter def opcode(self, value): + """Set the opcode""" if value > 0b1111: raise ValueError("invalid opcode") self._flags &= ~(((1 << 4) - 1) << 11) @@ -181,9 +188,12 @@ class Header(object): @property def aa(self): + """The AA flag""" return self._flags & (1 << 10) + @aa.setter def aa(self, value): + """Set the AA flag""" if value: self._flags |= (1 << 10) else: @@ -191,9 +201,12 @@ class Header(object): @property def tc(self): + """The TC flag""" return self._flags & (1 << 9) + @tc.setter def tc(self, value): + """Set the TC flag""" if value: self._flags |= (1 << 9) else: @@ -201,9 +214,12 @@ class Header(object): @property def rd(self): + """The RD flag""" return self._flags & (1 << 8) + @rd.setter def rd(self, value): + """Set the RD flag""" if value: self._flags |= (1 << 8) else: @@ -211,9 +227,12 @@ class Header(object): @property def ra(self): + """The RA flag""" return self._flags & (1 << 7) + @ra.setter def ra(self, value): + """Set the RA flag""" if value: self._flags |= (1 << 7) else: @@ -221,17 +240,23 @@ class Header(object): @property def z(self): - return (self._flags & (((1 << 3) - 1) << 4) >> 4) + """The Z flag""" + return self._flags & (((1 << 3) - 1) << 4) >> 4 + @z.setter def z(self, value): + """Set the Z flag""" if value: raise ValueError("non-zero zero flag") @property def rcode(self): + """The return code""" return self._flags & ((1 << 4) - 1) + @rcode.setter def rcode(self, value): + """Set the return code""" if value > 0b1111: raise ValueError("invalid return code") self._flags &= ~((1 << 4) - 1) @@ -245,8 +270,8 @@ class Question(object): """ def __init__(self, qname, qtype, qclass): - """ Create a new entry in the question section - + """ Create a new entry in the question section + Args: qname (str): QNAME qtype (Type): QTYPE diff --git a/project2/proj2_s4498062/dns/rcodes.py b/project2/proj2_s4498062/dns/rcodes.py index a35482c..cff7a8f 100644 --- a/project2/proj2_s4498062/dns/rcodes.py +++ b/project2/proj2_s4498062/dns/rcodes.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 - """ DNS RCODE values This module contains an Enum of RCODE values. See section 4.1.4 of RFC 1035 for @@ -8,7 +6,7 @@ more info. class RCode(object): """ Enum of RCODE values - + Usage: >>> NoError 0 @@ -62,8 +60,10 @@ class RCode(object): @staticmethod def to_string(rcode): + """Convert a return code to a string""" return RCode.by_value[rcode] @staticmethod def from_string(string): + """Convert a string to a return code""" return RCode.by_string[string] diff --git a/project2/proj2_s4498062/dns/resolver.py b/project2/proj2_s4498062/dns/resolver.py index ca4be95..8d12c1d 100644 --- a/project2/proj2_s4498062/dns/resolver.py +++ b/project2/proj2_s4498062/dns/resolver.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 - """ DNS Resolver This module contains a class for resolving hostnames. You will have to implement @@ -9,22 +7,22 @@ DNS server, but with a different list of servers. import socket -from dns.cache import RecordCache from dns.classes import Class from dns.message import Message, Header, Question -from dns.rcodes import RCode from dns.types import Type class Resolver(object): """ DNS resolver """ - - def __init__(self, caching, ttl): + + def __init__(self, nameservers, timeout, caching, ttl): """ Initialize the resolver - + Args: caching (bool): caching is enabled if True ttl (int): ttl of cache entries (if > 0) """ + self.nameservers = nameservers + self.timeout = timeout self.caching = caching self.ttl = ttl @@ -42,20 +40,21 @@ class Resolver(object): (str, [str], [str]): (hostname, aliaslist, ipaddrlist) """ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.settimeout(timeout) + sock.settimeout(self.timeout) # Create and send query - question = dns.message.Question(hostname, Type.A, Class.IN) - header = dns.message.Header(9001, 0, 1, 0, 0, 0) + question = Question(hostname, Type.A, Class.IN) + header = Header(9001, 0, 1, 0, 0, 0) header.qr = 0 header.opcode = 0 header.rd = 1 - query = dns.message.Message(header, [question]) + query = Message(header, [question]) + #TODO should come from self.nameservers sock.sendto(query.to_bytes(), ("8.8.8.8", 53)) # Receive response data = sock.recv(512) - response = dns.message.Message.from_bytes(data) + response = Message.from_bytes(data) # Get data aliases = [] diff --git a/project2/proj2_s4498062/dns/resource.py b/project2/proj2_s4498062/dns/resource.py index 350c87d..572397f 100644 --- a/project2/proj2_s4498062/dns/resource.py +++ b/project2/proj2_s4498062/dns/resource.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 - """ A DNS resource record This class contains classes for DNS resource records and record data. This @@ -10,7 +8,6 @@ of your resolver and server. import socket import struct -from dns.classes import Class from dns.types import Type @@ -25,34 +22,33 @@ class ResourceRecord(object): class_ (Class): the class rdata (RecordData): the record data """ - self.name = name - self.type_ = type_ - self.class_ = class_ - self.ttl = ttl - self.rdata = rdata + self.name = name + self.type_ = type_ + self.class_ = class_ + self.ttl = ttl + self.rdata = rdata def to_bytes(self, offset, composer): """ Convert ResourceRecord to bytes """ name = composer.to_bytes(offset, [self.name]) offset += len(name) rdata = self.rdata.to_bytes(offset, composer) - return (name + - struct.pack("!HHIH", - self.type_, - self.class_, - self.ttl, - len(rdata)) + - rdata) + return (name + struct.pack( + "!HHIH", + self.type_, + self.class_, + self.ttl, + len(rdata)) + rdata) @classmethod def from_bytes(cls, packet, offset, parser): """ Convert ResourceRecord from bytes """ names, offset = parser.from_bytes(packet, offset, 1) name = names[0] - type_, class_, ttl, rdlength = struct.unpack_from("!HHIH", packet, offset) + type_, class_, ttl, rdlen = struct.unpack_from("!HHIH", packet, offset) offset += 10 - rdata = RecordData.from_bytes(type_, packet, offset, rdlength, parser) - offset += rdlength + rdata = RecordData.from_bytes(type_, packet, offset, rdlen, parser) + offset += rdlen return cls(name, type_, class_, ttl, rdata), offset @@ -115,6 +111,8 @@ class RecordData(object): class ARecordData(RecordData): + """Data of an A record""" + def to_bytes(self, offset, composer): """ Convert to bytes @@ -139,6 +137,8 @@ class ARecordData(RecordData): class CNAMERecordData(RecordData): + """Data of a CNAME record""" + def to_bytes(self, offset, composer): """ Convert to bytes @@ -164,6 +164,8 @@ class CNAMERecordData(RecordData): class NSRecordData(RecordData): + """Data of an NS record""" + def to_bytes(self, offset, composer): """ Convert to bytes @@ -189,6 +191,8 @@ class NSRecordData(RecordData): class AAAARecordData(RecordData): + """Data of an AAAA record""" + def to_bytes(self, offset, composer): """ Convert to bytes @@ -213,6 +217,8 @@ class AAAARecordData(RecordData): class GenericRecordData(RecordData): + """Data of a generic record""" + def to_bytes(self, offset, composer): """ Convert to bytes diff --git a/project2/proj2_s4498062/dns/server.py b/project2/proj2_s4498062/dns/server.py index 7234e36..f412311 100644 --- a/project2/proj2_s4498062/dns/server.py +++ b/project2/proj2_s4498062/dns/server.py @@ -1,12 +1,9 @@ -#!/usr/bin/env python2 - """ A recursive DNS server This module provides a recursive DNS server. You will have to implement this server using the algorithm described in section 4.3.2 of RFC 1034. """ -import socket from threading import Thread @@ -15,9 +12,9 @@ class RequestHandler(Thread): def __init__(self): """ Initialize the handler thread """ - super().__init__() + super(RequestHandler).__init__() self.daemon = True - + def run(self): """ Run the handler thread """ # TODO: Handle DNS request @@ -29,7 +26,7 @@ class Server(object): def __init__(self, port, caching, ttl): """ Initialize the server - + Args: port (int): port that server is listening on caching (bool): server uses resolver with caching if true @@ -38,6 +35,7 @@ class Server(object): self.caching = caching self.ttl = ttl self.port = port + self.done = False # TODO: create socket def serve(self): diff --git a/project2/proj2_s4498062/dns/types.py b/project2/proj2_s4498062/dns/types.py index f0d9ef3..3c2fb29 100644 --- a/project2/proj2_s4498062/dns/types.py +++ b/project2/proj2_s4498062/dns/types.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 - """ DNS TYPE and QTYPE values This module contains an Enum for TYPE and QTYPE values. This Enum also contains @@ -9,7 +7,7 @@ RFC 1035 for more information. class Type(object): """ DNS TYPE and QTYPE - + Usage: >>> Type.A 1 @@ -48,8 +46,10 @@ class Type(object): @staticmethod def to_string(type_): + """Convert a type to a string""" return Type.by_value[type_] @staticmethod def from_string(string): + """Convert a string to a type""" return Type.by_string[string] diff --git a/project2/proj2_s4498062/dns_tests.py b/project2/proj2_s4498062/dns_tests.py index be7da9b..b62180b 100644 --- a/project2/proj2_s4498062/dns_tests.py +++ b/project2/proj2_s4498062/dns_tests.py @@ -4,8 +4,8 @@ import sys import unittest -PORT = 5353 -SERVER = "localhost" +port = 5353 +server = "localhost" class TestResolver(unittest.TestCase): """Unit tests for the resolver""" @@ -30,8 +30,8 @@ def main(): parser.add_argument("-s", "--server", type=str, default="localhost") parser.add_argument("-p", "--port", type=int, default=5001) args, extra = parser.parse_known_args() - PORT = args.port - SERVER = args.server + port = args.port + server = args.server # Pass the extra arguments to unittest sys.argv[1:] = extra |