-
Notifications
You must be signed in to change notification settings - Fork 49
/
dnstricker.py
134 lines (112 loc) · 4.14 KB
/
dnstricker.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
#!/usr/bin/env python
# coding: utf-8
# Build By LandGrey
import time
import struct
try:
import SocketServer
except:
import socketserver as SocketServer
def current_time():
return time.strftime('[%Y.%m.%d %H:%M:%S]', time.localtime())
class SinDNSQuery:
def __init__(self, data):
i = 1
self.name = ''
while True:
try:
d = ord(data[i])
except:
d = data[i]
if d == 0:
break
if d < 32:
self.name += '.'
else:
self.name += chr(d)
i += 1
self.querybytes = data[0:i + 1]
self.type, self.classify = struct.unpack('>HH', data[i + 1:i + 5])
self.len = i + 5
def getbytes(self):
return self.querybytes + struct.pack('>HH', self.type, self.classify)
class SinDNSAnswer:
def __init__(self, ip):
self.type = 1
self.classify = 1
self.name = 49164
self.datalength = 4
self.timetolive = 190
self.ip = ip
def getbytes(self):
res = struct.pack('>HHHLH', self.name, self.type, self.classify, self.timetolive, self.datalength)
s = self.ip.split('.')
res += struct.pack('BBBB', int(s[0]), int(s[1]), int(s[2]), int(s[3]))
return res
class SinDNSFrame:
def __init__(self, data):
(self.id, self.flags, self.quests, self.answers, self.author, self.addition) = struct.unpack('>HHHHHH', data[0:12])
self.query = SinDNSQuery(data[12:])
def getname(self):
return self.query.name
def setip(self, ip):
self.answer = SinDNSAnswer(ip)
self.answers = 1
self.flags = 33152
def getbytes(self):
res = struct.pack('>HHHHHH', self.id, self.flags, self.quests, self.answers, self.author, self.addition)
res = res + self.query.getbytes()
if self.answers != 0:
res += self.answer.getbytes()
return res
class DnsRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
global ip_address
data = self.request[0].strip()
dns = SinDNSFrame(data)
conn = self.request[1]
query_name = dns.getname()
# A record
if dns.query.type == 1:
response = ip_address if query_name.endswith(dns_domain) else None
if response:
dns.setip(response)
log_format = {'client_ip': self.client_address[0], 'client_port': self.client_address[1],
'query': query_name, 'record-type': 'A', 'response': response}
conn.sendto(dns.getbytes(), self.client_address)
print('{} {}'.format(current_time(), log_format))
else:
dns.setip(default_ip)
conn.sendto(dns.getbytes(), self.client_address)
# AAAA record
elif dns.query.type == 28:
response = ip_address if query_name.endswith(dns_domain) else None
if response:
dns.setip(response)
conn.sendto(dns.getbytes(), self.client_address)
log_format = {'client_ip': self.client_address[0], 'client_port': self.client_address[1],
'query': query_name, 'record-type': 'AAAA', 'response': response}
print('{} {}'.format(current_time(), log_format))
else:
dns.setip(default_ip)
conn.sendto(dns.getbytes(), self.client_address)
else:
dns.setip(default_ip)
conn.sendto(dns.getbytes(), self.client_address)
class SimpleDnsServer:
def __init__(self, port=53):
self.port = port
def start(self):
host, port = "0.0.0.0", self.port
dns_udp_server = SocketServer.UDPServer((host, port), DnsRequestHandler)
dns_udp_server.serve_forever()
if __name__ == "__main__":
dns_domain = 'test.com'
ip_address = '2.2.2.2'
default_ip = '192.168.1.1'
dns_server = SimpleDnsServer()
print("{} Dnslog server start".format(current_time()))
try:
dns_server.start()
except KeyboardInterrupt:
print('{} User quit.'.format(current_time()))