-
Notifications
You must be signed in to change notification settings - Fork 0
/
dnsserver.py
executable file
·118 lines (87 loc) · 3.57 KB
/
dnsserver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/usr/bin/env python3
''' Python DNS server '''
import configparser
import random
import socket
import dns
HOST = ''
INPORT = 53
OUTPORT = 8877
class DNSserver:
def __init__(self, config):
self.forward_servers = config["DEFAULT"]["dns_servers"].split(";")
# A resource dictionary that maps a name to a list of IP addresses
self.resources = {}
for resource in [r for r in config.keys() if r != "DEFAULT"]:
self.resources[resource] = config[resource]["url"].split()
# Listening socket
self.sock_in = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock_in.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock_in.bind((HOST, INPORT))
# Output socket, for recursive queries
self.sock_out = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock_out.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock_out.bind((HOST, OUTPORT))
def start(self):
print("Starting domain name service.")
print("hostname:", HOST + ',', "port", INPORT)
while True:
data, addr = self.sock_in.recvfrom(1024)
print("Query recieved from", addr)
query = dns.DNSmessage(data)
print(query)
if self.__name_exists(query.questions):
# An answer can be made from local data
name = query.questions[0].qname
if not name.startswith("www."):
name = "www." + name
# Add the answer and convert the query into a response
query.flags["qr"] = True
query.add_answer(name, self.resources[name][0])
print("\nSending response for", name)
print(query, '\n')
# Send response to client
self.sock_in.sendto(bytes(query), addr)
else:
if query.flags["rd"]:
# Query will be forwarded to another DNS server
print("\nRedirecting to default DNS server (Recursion desired):",
self.forward_servers[0])
self.__redirect_query(addr, query)
else:
# If an answer cannot be made with a recursive query, return a list of other DNS servers
print(
"\nReturning a list of other DNS servers (Recursion not desired).")
def __redirect_query(self, addr, query):
# Redirect through output socket
self.sock_out.sendto(bytes(query), (self.forward_servers[0], 53))
# Receive data and parse as a DNS response
data, address = self.sock_out.recvfrom(1024)
print(data)
response = dns.DNSmessage(data)
print("\nResponse received from", address)
print(response)
# Send response to original client
self.sock_in.sendto(data, addr)
def __name_exists(self, questions):
for q in questions:
qname = q.qname
if qname.startswith("www."):
other_name = qname[4:]
else:
other_name = 'www.' + qname
if qname in self.resources or other_name in self.resources:
return True
return False
@staticmethod
def __change_id(id, data):
return dns.int_to_bytes(id) + data[2:]
if __name__ == '__main__':
# Configuration load
conf = configparser.ConfigParser()
conf.read("dns.config")
ds = DNSserver(conf)
try:
ds.start()
except KeyboardInterrupt:
print("\rStopping server.")