-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathletsencrypt_dns01_server.py
executable file
·138 lines (103 loc) · 3.74 KB
/
letsencrypt_dns01_server.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
#!/usr/bin/env python
import datetime
import sys
import time
import threading
import traceback
import SocketServer
import dnslib
from dnslib import *
import json
class DomainName(str):
def __getattr__(self, item):
return DomainName(item + '.' + self)
# Can change bind address of server here
BIND_HOST = '0.0.0.0'
BIND_PORT = 53
TTL = 30
bp = ''
if sys.path[0]:
bp = sys.path[0] + os.sep
config_name= bp + 'config.json'
# records and associated filenames resolved by this server
my_records = json.load(open(config_name))
def dns_response(data):
try:
request = DNSRecord.parse(data)
except:
traceback.print_exc(file=sys.stderr)
return None
#print request
reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q)
qname = request.q.qname
qn = str(qname).lower()
qtype = request.q.qtype
qt = QTYPE[qtype]
if qn in my_records.keys():
r = [my_records[a] for a in my_records.keys() if a == qn][0]
if r:
try:
if str(r[0]).startswith('file://'):
rdata = getattr(dnslib.dns, r[-1])(open(bp + r[0].lstrip('file://')).read().rstrip())
else:
rdata = getattr(dnslib.dns, r[-1])(*r[:-1])
reply.add_answer(RR(rname=qname, rtype=getattr(QTYPE, r[-1]), rclass=1, ttl=TTL, rdata=rdata))
#print "---- Reply:\n", reply
except Exception:
traceback.print_exc(file=sys.stderr)
return None
return reply.pack()
class BaseRequestHandler(SocketServer.BaseRequestHandler):
def get_data(self):
raise NotImplementedError
def send_data(self, data):
raise NotImplementedError
def handle(self):
now = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')
#print "\n\n%s request %s (%s %s):" % (self.__class__.__name__[:3], now, self.client_address[0], self.client_address[1])
try:
data = self.get_data()
#print len(data), data.encode('hex') # repr(data).replace('\\x', '')[1:-1]
resp = dns_response(data)
if resp:
self.send_data(resp)
except Exception:
traceback.print_exc(file=sys.stderr)
class TCPRequestHandler(BaseRequestHandler):
def get_data(self):
data = self.request.recv(8192).strip()
sz = int(data[:2].encode('hex'), 16)
if sz < len(data) - 2:
raise Exception("Wrong size of TCP packet")
elif sz > len(data) - 2:
raise Exception("Too big TCP packet")
return data[2:]
def send_data(self, data):
sz = hex(len(data))[2:].zfill(4).decode('hex')
return self.request.sendall(sz + data)
class UDPRequestHandler(BaseRequestHandler):
def get_data(self):
return self.request[0].strip()
def send_data(self, data):
return self.request[1].sendto(data, self.client_address)
if __name__ == '__main__':
print "Starting nameserver..."
servers = [
SocketServer.ThreadingUDPServer((BIND_HOST, BIND_PORT), UDPRequestHandler),
SocketServer.ThreadingTCPServer((BIND_HOST, BIND_PORT), TCPRequestHandler),
]
for s in servers:
thread = threading.Thread(target=s.serve_forever) # that thread will start one more thread for each request
thread.daemon = True # exit the server thread when the main thread terminates
thread.start()
print "%s server loop running in thread: %s" % (s.RequestHandlerClass.__name__[:3], thread.name)
try:
while 1:
time.sleep(1)
sys.stderr.flush()
sys.stdout.flush()
except KeyboardInterrupt:
pass
finally:
for s in servers:
s.shutdown()