-
Notifications
You must be signed in to change notification settings - Fork 39
/
DomainScanningTool.py
175 lines (142 loc) · 4.87 KB
/
DomainScanningTool.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env python
import binascii
import socket
import random
import os
DEFAULT_SERVER = '1.1.1.1'
DEFAULT_PORT = 53
AUTHOR = 'dynos01'
EMAIL = '[email protected]'
VERSION = '1.0.3'
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():
print('Domain scanning tool version %s' % VERSION)
print('Author: %s <%s>' % (AUTHOR, EMAIL))
server = []
port = []
dns = input('Please input a list of DNS servers (IPv4 or IPv6), which will be used to check against: ')
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('Invalid DNS server.')
return
server.append(s)
port.append(p)
tld = input('Please input the suffixes to be scanned. If you want to scan multiple suffixes at once, please use commas to separate the list. \n')
tld = tld.split(',')
for i, item in enumerate(tld):
tld[i] = item.strip()
dictFile = input('Please input the path for dictionary file. \n')
if not os.access(dictFile, os.R_OK):
print('Unable to read dictionary file. ')
return
resultFile = input('If you want to save the results to a file, input its path. Otherwise, press ENTER. \n')
if len(resultFile) > 0:
result = open(resultFile, 'a')
verbose = False
v = input('Do you want to show unavailable domains? [y/N]: ')
if v.lower() == 'y':
verbose = True
input('All data collected. Press ENTER to start scanning. ')
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 + ' is available. ')
if len(resultFile) > 0:
result.write(domain + ' is available. \n')
elif verbose:
print(domain + ' is not available. ')
if len(resultFile) > 0:
result.write(domain + ' is not available. \n')
print('Scanning finished. ')
if len(resultFile) > 0:
print('Results have been saved to ' + resultFile + '.')
if __name__ == '__main__':
main()