-
Notifications
You must be signed in to change notification settings - Fork 36
/
DNSServer.py
156 lines (133 loc) · 5.84 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import dns.message
import dns.rdatatype
import dns.rdataclass
import dns.rdtypes
import dns.rdtypes.ANY
from dns.rdtypes.ANY.MX import MX
from dns.rdtypes.ANY.SOA import SOA
import dns.rdata
import socket
import threading
import signal
import os
import sys
import hashlib
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import ast
def generate_aes_key(password, salt):
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
iterations=100000,
salt=salt,
length=32
)
key = kdf.derive(password.encode('utf-8'))
key = base64.urlsafe_b64encode(key)
return key
# Lookup details on fernet in the cryptography.io documentation
def encrypt_with_aes(input_string, password, salt):
key = generate_aes_key(????)
f = Fernet(???)
encrypted_data = f.????(????.encode('utf-8')) #call the Fernet encrypt method
return encrypted_data
def decrypt_with_aes(encrypted_data, password, salt):
key = generate_aes_key(????)
f = Fernet(????)
decrypted_data = f.????(????) #call the Fernet decrypt method
return decrypted_data.decode('utf-8')
salt = ???? # Remember it should be a byte-object
password = ?????
input_string = ?????
encrypted_value = encrypt_with_aes(input_string, password, salt) # exfil function
decrypted_value = decrypt_with_aes(encrypted_value, password, salt) # exfil function
# For future use
def generate_sha256_hash(input_string):
sha256_hash = hashlib.sha256()
sha256_hash.update(input_string.encode('utf-8'))
return sha256_hash.hexdigest()
# A dictionary containing DNS records mapping hostnames to different types of DNS data.
dns_records = {
'example.com.': {
dns.rdatatype.A: '192.168.1.101',
dns.rdatatype.AAAA: '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
dns.rdatatype.MX: [(10, 'mail.example.com.')], # List of (preference, mail server) tuples
dns.rdatatype.CNAME: 'www.example.com.',
dns.rdatatype.NS: 'ns.example.com.',
dns.rdatatype.TXT: ('This is a TXT record',),
dns.rdatatype.SOA: (
'ns1.example.com.', #mname
'admin.example.com.', #rname
2023081401, #serial
3600, #refresh
1800, #retry
604800, #expire
86400, #minimum
),
},
# Add more records as needed (see assignment instructions!
}
def run_dns_server():
# Create a UDP socket and bind it to the local IP address (what unique IP address is used here, similar to webserver lab) and port (the standard port for DNS)
server_socket = socket.socket(socket.AF_INET, ????) # Research this
server_socket.bind((?????, ????))
while True:
try:
# Wait for incoming DNS requests
data, addr = server_socket.recvfrom(1024)
# Parse the request using the `dns.message.from_wire` method
request = ?????
# Create a response message using the `dns.message.make_response` method
response = ??????
# Get the question from the request
question = request.question[???]
qname = question.name.to_text()
qtype = question.rdtype
# Check if there is a record in the `dns_records` dictionary that matches the question
if qname in dns_records and qtype in dns_records[qname]:
# Retrieve the data for the record and create an appropriate `rdata` object for it
answer_data = dns_records[qname][qtype]
rdata_list = []
if qtype == dns.rdatatype.??:
for pref, server in answer_data:
rdata_list.append(MX(dns.rdataclass.IN, dns.rdatatype.MX, pref, server))
elif qtype == dns.rdatatype.??:
??, ??, ??, ??, ??, ??, ?? = answer_data # What is the record format? See dns_records dictionary. Assume we handle @, Class, TTL elsewhere. Do some research on SOA Records
rdata = SOA(dns.rdataclass.IN, dns.rdatatype.SOA, ??, ??, ??, ??, ??, ??, ??) # follow format from previous line
rdata_list.append(rdata)
else:
if isinstance(answer_data, str):
rdata_list = [dns.rdata.from_text(dns.rdataclass.IN, qtype, answer_data)]
else:
rdata_list = [dns.rdata.from_text(dns.rdataclass.IN, qtype, data) for data in answer_data]
for rdata in rdata_list:
response.answer.append(dns.rrset.RRset(question.name, dns.rdataclass.IN, qtype))
response.answer[-1].add(rdata)
# Set the response flags
response.flags |= 1 << 10
# Send the response back to the client using the `server_socket.sendto` method and put the response to_wire(), return to the addr you received from
print("Responding to request:", qname)
server_socket.???????
except KeyboardInterrupt:
print('\nExiting...')
server_socket.close()
sys.exit(0)
def run_dns_server_user():
print("Input 'q' and hit 'enter' to quit")
print("DNS server is running...")
def user_input():
while True:
cmd = input()
if cmd.lower() == 'q':
print('Quitting...')
os.kill(os.getpid(), signal.SIGINT)
input_thread = threading.Thread(target=user_input)
input_thread.daemon = True
input_thread.start()
run_dns_server()
if __name__ == '__main__':
run_dns_server_user()
#print("Encrypted Value:", encrypted_value)
#print("Decrypted Value:", decrypted_value)