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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
#!/usr/bin/env python
import binascii
import socket
import random
import os
DEFAULT_SERVER = '1.1.1.1'
DEFAULT_PORT = 53
def send(message, server, port):
"""
Sends UDP packet to server and waits for response.
Args:
message: Encoded data, which will be sent.
server: DNS server address. both IPv4 and IPv6 are supported.
port: DNS server port.
Returns:
A string containing raw response.
"""
message = message.strip()
addr = (server, port)
if '.' in server:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
else:
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
try:
s.sendto(binascii.unhexlify(message), addr)
data, address = s.recvfrom(4096)
finally:
s.close()
return binascii.hexlify(data).decode()
def buildMessage(domain):
"""
Creates a DNS request according to RFC2929. Attributes other than domain name are hard-coded.
Args:
domain: The domain name to be checked.
Returns:
A string containing raw DNS request.
"""
message = '{:04x}'.format(random.randint(0, 65535)) #Generate an random request ID
message += '01000001000000000000'
#Encode parts of the given domain name into our request
addr = domain.split('.')
for i in addr:
length = '{:02x}'.format(len(i))
addr = binascii.hexlify(i.encode())
message += length
message += addr.decode()
message += '0000060001'
return message
def validateServer(ip, port):
"""
Checks if the given IP-port combination is valid.
Args:
ip: IPv4 or IPv6 address.
port: Port number.
Returns:
A bool value. True for valid and False for invalid.
"""
if port <= 0 or port > 65535:
return False
try:
if '.' in ip:
socket.inet_pton(socket.AF_INET, ip)
else:
socket.inet_pton(socket.AF_INET6, ip)
except:
return False
return True
def check(domain, server, port):
"""
Sends the request, reads the raw response and checks the ANCOUNT attribute according to RFC2929.
Args:
domain: Domain name to be checked.
server: DNS server to check against.
port: DNS server port.
Returns:
A bool value representing if the domain exists.
"""
message = buildMessage(domain)
response = send(message, server, port)
rcode = '{:b}'.format(int(response[4:8], 16)).zfill(16)[12:16]
return False if rcode == '0011' else True
def main():
server = []
port = []
dns = input('DNS服务器(回车默认):')
if len(dns) == 0:
server.append(DEFAULT_SERVER)
port.append(DEFAULT_PORT)
else:
dns = dns.split(',')
for i, item in enumerate(dns):
item = item.strip()
if '[' in item:
s = item.split(']')[0][1:]
p = item.split(']')[1][1:]
else:
s = item.split(':')[0]
p = item.split(':')[1]
p = int(p)
if not validateServer(s, p):
print('DNS服务器无效')
return
server.append(s)
port.append(p)
tld = input('域名后缀(多个后缀用,分隔):')
tld = tld.split(',')
for i, item in enumerate(tld):
tld[i] = item.strip()
dictFile = input('字典文件路径:')
if not os.access(dictFile, os.R_OK):
print('无法读取字典文件')
return
resultFile = input('扫描结果保存路径(不保存回车):')
if len(resultFile) > 0:
result = open(resultFile, 'a')
verbose = False
v = input('显示不可用域名[y/n]:')
if v.lower() == 'y':
verbose = True
input('回车开始扫描')
for line in open(dictFile):
for suffix in tld:
domain = line.strip() + '.' + suffix
i = random.choice(range(len(server)))
if not check(domain, server[i], port[i]):
print(domain + ' 可用')
if len(resultFile) > 0:
result.write(domain + ' 可用 \n')
elif verbose:
print(domain + ' 不可用')
if len(resultFile) > 0:
result.write(domain + ' 不可用 \n')
print('扫描完毕')
if len(resultFile) > 0:
print('扫描结果已保存到' + resultFile)
if __name__ == '__main__':
main()
|