summaryrefslogtreecommitdiff
path: root/project2/proj2_s4498062/dns/resolver.py
diff options
context:
space:
mode:
authorCamil Staps2016-05-02 22:51:37 +0200
committerCamil Staps2016-05-02 22:51:37 +0200
commit28e067fc983aa8241c782b04406abd9c538a0986 (patch)
treed16857831f340829c7be65a73e89a508101061d0 /project2/proj2_s4498062/dns/resolver.py
parentpylint project 2 (diff)
Project 2: simple DNS resolver
Diffstat (limited to 'project2/proj2_s4498062/dns/resolver.py')
-rw-r--r--project2/proj2_s4498062/dns/resolver.py94
1 files changed, 75 insertions, 19 deletions
diff --git a/project2/proj2_s4498062/dns/resolver.py b/project2/proj2_s4498062/dns/resolver.py
index 8d12c1d..a046d5d 100644
--- a/project2/proj2_s4498062/dns/resolver.py
+++ b/project2/proj2_s4498062/dns/resolver.py
@@ -5,15 +5,33 @@ things in this module. This resolver will be both used by the DNS client and the
DNS server, but with a different list of servers.
"""
+import re
import socket
from dns.classes import Class
from dns.message import Message, Header, Question
from dns.types import Type
+import dns.regexes as rgx
class Resolver(object):
""" DNS resolver """
+ ROOT_SERVERS = [
+ '198.41.0.4',
+ '192.228.79.201',
+ '192.33.4.12',
+ '199.7.91.13',
+ '192.203.230.10',
+ '192.5.5.241',
+ '192.112.36.4',
+ '198.97.190.53',
+ '192.36.148.17',
+ '192.58.128.30',
+ '193.0.14.129',
+ '199.7.83.42',
+ '202.12.27.33'
+ ]
+
def __init__(self, nameservers, timeout, caching, ttl):
""" Initialize the resolver
@@ -21,11 +39,61 @@ class Resolver(object):
caching (bool): caching is enabled if True
ttl (int): ttl of cache entries (if > 0)
"""
- self.nameservers = nameservers
+ self.nameservers = nameservers + self.ROOT_SERVERS
self.timeout = timeout
self.caching = caching
self.ttl = ttl
+ def do_query(self, query, using):
+ """Send a query to a list of name servers"""
+ for hint in using:
+ if re.match(rgx.IP, hint) == None:
+ continue
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.settimeout(self.timeout)
+ try:
+ sock.sendto(query.to_bytes(), (hint, 53))
+ data = sock.recv(512)
+ response = Message.from_bytes(data)
+ yield response
+ except socket.timeout:
+ pass
+
+ def get_hints(self, domain, parent='', using=None, in_recursion=False):
+ """Get a list of nameservers for a domain"""
+ if using is None:
+ using = []
+
+ if not in_recursion:
+ using += self.nameservers
+
+ domains = re.match(rgx.DOMAIN, domain)
+ if domains == None:
+ return None
+ sub, dom = domains.groups()
+ if parent != '':
+ dom += '.' + parent
+
+ header = Header(0, 0, 1, 0, 0, 0)
+ header.qr = 0
+ header.opcode = 0
+ header.rd = 0
+ query = Message(header, [Question(dom, Type.NS, Class.IN)])
+
+ for response in self.do_query(query, using):
+ new_hints = [ip for _, [ip] in list(response.get_hints())]
+
+ if new_hints != []:
+ if sub is '':
+ return new_hints + using
+
+ result = self.get_hints(
+ sub, dom, new_hints + using, in_recursion=True)
+ if result != None:
+ return result
+
+ return []
+
def gethostbyname(self, hostname):
""" Translate a host name to IPv4 address.
@@ -49,21 +117,9 @@ class Resolver(object):
header.opcode = 0
header.rd = 1
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 = Message.from_bytes(data)
-
- # Get data
- aliases = []
- for additional in response.additionals:
- if additional.type_ == Type.CNAME:
- aliases.append(additional.rdata.data)
- addresses = []
- for answer in response.answers:
- if answer.type_ == Type.A:
- addresses.append(answer.rdata.data)
-
- return hostname, aliases, addresses
+
+ for response in self.do_query(query, self.get_hints(hostname)):
+ aliases = response.get_aliases()
+ addresses = response.get_addresses()
+
+ return hostname, aliases, addresses