summaryrefslogtreecommitdiff
path: root/project2/proj2_s4498062
diff options
context:
space:
mode:
Diffstat (limited to 'project2/proj2_s4498062')
-rw-r--r--project2/proj2_s4498062/dns/__init__.py1
-rw-r--r--project2/proj2_s4498062/dns/cache.py18
-rw-r--r--project2/proj2_s4498062/dns/classes.py6
-rw-r--r--project2/proj2_s4498062/dns/domainname.py29
-rw-r--r--project2/proj2_s4498062/dns/message.py81
-rw-r--r--project2/proj2_s4498062/dns/rcodes.py6
-rw-r--r--project2/proj2_s4498062/dns/resolver.py23
-rw-r--r--project2/proj2_s4498062/dns/resource.py42
-rw-r--r--project2/proj2_s4498062/dns/server.py10
-rw-r--r--project2/proj2_s4498062/dns/types.py6
-rw-r--r--project2/proj2_s4498062/dns_tests.py8
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