-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrun-DNSrank
339 lines (302 loc) · 12.6 KB
/
run-DNSrank
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#!/bin/bash
#______________________________________________#
# _____ _ _ _____ _ #
# | __ \| \ | |/ ____| | | #
# | | | | \| | (___ _ __ __ _ _ __ | | __ #
# | | | | . ` |\___ \| '__/ _` | '_ \| |/ / #
# | |__| | |\ |____) | | | (_| | | | | < #
# |_____/|_| \_|_____/|_| \__,_|_| |_|_|\_\ #
# #
# DNSrank version 1.3/23.Jan.2022 #
# License: GPL-3.0 #
# Github: https://github.com/Deepcuts/DNSrank #
#______________________________________________#
#------------------------------------------------------------------------------------------------------------------------
# Edit test parameters below #
#------------------------------------------------------------------------------------------------------------------------
# File containing DNS servers. One record per line. Example: 1.1.1.1#CloudFlare#53 ( IP#ShortName#Port )
# Only use IP and not fqdn for DNS servers. Non IP values will be skipped.
# hint: edit the actual file to add/modify DNS servers.
ServersFile=servers.txt
# File containing the list of domains. One domain per line. Example: 1,example1.com ( rank#domain.tld )
# Bundled domains source: https://statvoo.com/dl/top-1million-sites.csv.zip
# hint: edit the actual file to add/modify domain names.
DomainsFile=domains.txt
# How many domains to test from $DomainsFile?. Script comes with top 1 milion domains in format 1,example1.com where 1 is the rank. Testing all bundled domains is not advised.
# Recommended values: 100 (quick test, not very conclusive), 1000 (good balance, pretty conclusive) or 10000 (very good coverage, conclusive). Test with over 10000 domains at your own peril.
# Default 1000
DomainsTestCount=1000
# Sets the timeout for a DNS query in seconds. Setting this to a much larger value will greatly increase total testing time with no real benefit. Keep it around 2 seconds.
# Default 2
querytime=2
# How thorough to test icmp latency and packet loss for each server in seconds. Increase to 10 or more for better rtt average calculation, but each test will take longer.
# Default 4
pingtime=4
# Query response times in ms without decimals for best and worst ranking. Example 2 for best performance and 100 for worst performance.
# Default 2 and 100
bestqt=10
worstqt=100
# Enable checking for update. If enabled (true), the script will pull the latest version from github, overwriting any local modifications. If false, no update check or changes will be made.
# Warning: all local modifications made, including #ServersFile and $DomainsFile will be overwritten if set to true! Backup your modifications or set to false.
# Default true
check4update=true
#------------------------------------------------------------------------------------------------------------------------
# Edit below only if you know what you are doing and you want to modify the script #
#------------------------------------------------------------------------------------------------------------------------
# If $check4update is true, check for update and pull the latest version if new version found.
if [ $check4update = "true" ]; then
printf "Checking for update...\n"
[ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | \
sed 's/\// /g') | cut -f1) ] && needupdate=0 || needupdate=1
if [ $needupdate = 1 ]; then
# Notify that a new update has been found and that it will be applied.
printf "Update found. Applying...\n"
# Check for new version on github and pull quietly.
git reset --hard HEAD --quiet
git pull --quiet
# Make the script executable
chmod u+x run-DNSrank
printf "Restarting....\n"
# Restart script if new version downloaded.
./$(basename $0) && exit
fi
if [ $needupdate = 0 ]; then
# Notify that no new update has been found.
printf "No update found. \n"
fi
fi
if [ $check4update = "false" ]; then
:
fi
if [ $check4update != "true" ] && [ $check4update != "false" ]; then
# Hint the user to stop bashing his head against the keyboard.
printf "Set check4update variable to true or false to enable or disable checking for updates \n"
fi
# Set script git home
githome="https://github.com/Deepcuts/DNSrank"
# Set colors for various messages marking.
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
RED=$(tput setaf 1)
normal=$(tput sgr0)
# Checking if required files exist.
if [ ! -f "$DomainsFile" ]; then
printf "${RED}$DomainsFile file not found. Download it from $githome or create it yourself and add some domains in format 1,example1.com. Script halted! ${normal} \n"
exit 1
fi
if [ ! -f "$ServersFile" ]; then
printf "${RED}$ServersFile file not found. Download it from $githome or create it yourself and add some servers in format 1.1.1.1#CloudFlare#53. Script halted! ${normal} \n"
exit 1
fi
# Checking if required commands are available.
if ! [ -x "$(command -v bc)" ]; then
printf "${RED}Error: bc is not installed. Script halted! ${normal} \n"
exit 1
fi
if ! [ -x "$(command -v dig)" ]; then
printf "${RED}Error: dig is not installed. Script halted! ${normal} \n"
exit 1
fi
if ! [ -x "$(command -v traceroute)" ]; then
printf "${RED}Error: traceroute is not installed. Script halted! ${normal} \n"
exit 1
fi
if ! [ -x "$(command -v ping)" ]; then
printf "${RED}Error: ping is not installed. Script halted! ${normal} \n"
exit 1
fi
if ! [ -x "$(command -v curl)" ]; then
printf "${RED}Error: curl is not installed. Script halted! ${normal} \n"
exit 1
fi
if ! [ -x "$(command -v getent)" ]; then
printf "${RED}Error: getent is not installed. Script halted! ${normal} \n"
exit 1
fi
# Zeroing required variables just in case.
totalservers=0
totaldomains=0
badservers=0
testedservers=0
totalservers=0
d1=""
s1=""
ISP=""
ISPCI=""
ISPCO=""
# Build domains list to test, taking into consideration $DomainsTestCount and cutting the rank number and ,
Domains=$(cat $DomainsFile |head -n $DomainsTestCount| cut -d "," -f2-)
# Build servers list to test.
Servers=$(cat "$ServersFile")
# Counting final number of domains to test.
for d1 in $Domains; do
totaldomains=$((totaldomains + 1))
done
# Counting number of DNS servers to use.
for s1 in $Servers; do
totalservers=$((totalservers + 1))
done
# Check if at least one DNS server has been setup and quit if none found.
if [ $totalservers = 0 ]; then
echo ""
printf "${RED}No DNS servers defined. Edit $ServersFile file and add at least one DNS server in format ShortName#ServerIP#Port ${normal} \n"
exit 1
fi
# Check if at least one domain has been setup and quit if none found.
if [ $totaldomains = 0 ]; then
echo ""
printf "${RED}No domains defined. Edit $DomainsFile file and add add least one domain in format 1,example1.com ${normal}"
exit 1
fi
# Some grammar fixes.
if [ $totalservers -eq 1 ]; then
gservers="server"
ghas="has"
fi
if [ $totalservers -ge 2 ]; then
gservers="servers"
ghas="have"
fi
if [ $totaldomains -eq 1 ]; then
gdomains="domain"
fi
if [ $totaldomains -ge 2 ]; then
gdomains="domains"
fi
# Display some test info, parameters and legend.
printf "\n"
printf "\n%s" "Analyzing DNS performance using $totaldomains $gdomains and $totalservers DNS $gservers."
printf "\n%s" "Parameters: $querytime seconds query timeout and $pingtime seconds latency test/server."
printf "\n%s" "Legend: average query time ${GREEN}under $bestqt ms ${normal}(Very good) |${YELLOW} between $bestqt ms and $worstqt ms ${normal}(Acceptable) |${RED} above $worstqt ms or not responding ${normal}(Not Recommended)."
# Try to get current ISP via ipinfo.io/org. Test if domain is blocked or not resolving.
testipinfo=`getent hosts ipinfo.io | awk '{ print $1 }'`
if [ "$testipinfo" != "::" ]; then
ISP=`curl -s ipinfo.io/org`
if [ $? -eq 0 ]; then
:
else
ISP="Unknown"
fi
ISPCI=`curl -s ipinfo.io/city`
if [ $? -eq 0 ]; then
:
else
ISPCI="Unknown"
fi
ISPCO=`curl -s ipinfo.io/country`
if [ $? -eq 0 ]; then
:
else
ISPCO="Unknown"
fi
else
ISP="request blocked or info unavailable"
ISPCI=""
ISPCO=""
fi
printf "\n%s\n" "Testing from: $ISP | $ISPCI $ISPCO"
# Main loop start.
for s1 in $Servers; do
# Get DNS server IP.
sip=${s1%%#*}
# Get DNS server ShortName.
sname=${s1#*#}
# Get DNS server port.
sport=${s1##*#}
# Print each DNS server ShortName.
printf "\n%22s%s:" $sname
# Test each DNS server if value is an IP and skip it if it is not.
if [[ $sip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
:
else
printf " ${RED}Server is not an IP. Skipping!${normal}"
badservers=$((badservers + 1))
continue
fi
# Test each DNS server and skip it if packet loss is 100%.
pktloss=`ping -W 2 -i 1 -n -c $pingtime $sip | grep -oP '\d+(?=% packet loss)'`
if [ "$pktloss" = "100" ]; then
printf " ${RED}Server not responding to icmp requests. Skipping!${normal}"
badservers=$((badservers + 1))
continue
fi
# Test each DNS server and skip it if unable to query some hopefully always online domains.
testdns=`dig -p $sport +tries=1 +retry=1 +time=1 @$sip +short google.com apple.com microsoft.com`
if [ $? -eq 0 ]; then
:
else
printf " ${RED}Server not responding to DNS queries. Skipping!${normal}"
badservers=$((badservers + 1))
continue
fi
# Test each DNS server and skip it if recursion is not available.
testdns1=`dig -p $sport +tries=1 +retry=1 +time=1 @$sip google.com apple.com microsoft.com | grep "WARNING: recursion requested but not available" `
if [ $? -eq 0 ]; then
printf " ${RED}Server reporting that recursion is not available. Skipping!${normal}"
badservers=$((badservers + 1))
continue
else
:
fi
# Find max hops to each DNS server with traceroute.
troute=`traceroute -n -I "$sip" 2>/dev/null | tail -1 | awk '{print $1}'`
# Find average rtt to each DNS server with ping.
rttavg=`ping -W 2 -i 1 -n -c $pingtime $sip | tail -1 | awk '{print $4}' | cut -d '/' -f 2`
dnsversion=`dig version.bind txt chaos @$sip | grep "version.bind" | tail -n1 | cut -d T -f 3- | xargs`
[ -z "$dnsversion" ] && dnsversion=Unknown
ftime=0
# Loop all domains.
for d1 in $Domains; do
# Query each server and look for Query time value in reponse.
ttime=`dig -p $sport +tries=1 +retry=1 +time=$querytime +stats @$sip $d1 | grep "Query time:" | cut -d : -f 2- | cut -d " " -f 2`
if [ -z "$ttime" ]; then
ttime=1000
elif [ "x$ttime" = "x0" ]; then
ttime=1
fi
ftime=$((ftime + ttime))
done
# Do some math for each DNS server final query average time.
avg=`bc -lq <<< "scale=2; $ftime/$totaldomains"`
# Print statistics for each DNS server
# Mark servers with a query time lower than $bestqt with a different color.
if (( $(echo "$avg < $bestqt" |bc -l) )); then
printf "%8s%s" ${GREEN} $avg " ms (average) | Distance to server: $troute hops | icmp rtt: $rttavg ms (average) | packet loss: $pktloss% | version: $dnsversion ${normal}"
continue
fi
# Mark servers with a query time higher than $worstqt with a different color.
if (( $(echo "$avg > $worstqt" |bc -l) )); then
printf "%6s%s" ${RED} $avg " ms (average) | Distance to server: $troute hops | icmp rtt: $rttavg ms (average) | packet loss: $pktloss% | version: $dnsversion ${normal}"
continue
fi
# Mark servers with a query time between $bestqt and $worstqt with a different color.
if (( $(echo "$avg > $bestqt" |bc -l) && $(echo "$avg < $worstqt" |bc -l ))); then
printf "%7s%s" ${YELLOW} $avg " ms (average) | Distance to server: $troute hops | icmp rtt: $rttavg ms (average) | packet loss: $pktloss% | version: $dnsversion ${normal}"
fi
done
# Main loop done.
echo ""
if [ $badservers -ge 1 ]; then
testedservers=$((totalservers - badservers))
# Some grammar fixes.
if [ $testedservers -eq 1 ]; then
g1servers="server"
g1has="has"
fi
if [ $testedservers -ge 2 ]; then
g1servers="servers"
g1has="have"
fi
# Notify that not even one server was tested.
if [ $testedservers -eq 0 ]; then
printf "\n%s\n" "Not even one server responded to DNS queries. Check your network connection or the configured DNS servers."
exit 1
fi
# Notiy that some servers were not reachable while others were.
printf "\n%s\n" "$badservers out of $totalservers $gservers failed to respond to DNS queries. $testedservers $g1servers responded to queries and $g1has been tested."
else
# Notify that all configured servers were reachable and tested.
printf "\n%s\n" "$totalservers $gservers responded to queries and $ghas been tested."
fi
exit 0;