Skip to content

Instantly share code, notes, and snippets.

@tayyebi
Created July 2, 2025 12:35
Show Gist options
  • Save tayyebi/57a4d69081a0fca9e4483772da12e28c to your computer and use it in GitHub Desktop.
Save tayyebi/57a4d69081a0fca9e4483772da12e28c to your computer and use it in GitHub Desktop.
Checks whether your website and mail server resolutions works fine around the globe

Download DNS list from https://public-dns.info/, which will be a file like below:

ip_address,name,as_number,as_org,country_code,city,version,error,dnssec,reliability,checked_at,created_at
8.8.8.8,dns.google.,15169,GOOGLE,US,,,,true,1.00,2022-04-17T08:03:50Z,2020-07-16T14:19:04Z

then, run the command below to run tests

./test_dns.sh -f us.csv -d gordarg.com -n 5 -r MX

#!/usr/bin/env bash
set -uo pipefail
usage() {
cat <<EOF
Usage: $0 -f servers.csv -d domain [-r record] [-n tries] [-p parallelism]
-f CSV file (with header, including ip_address, as_org, city, country_code)
-d Domain to query
-r DNS record type to query (A, NS, MX, TXT, etc.; default: MX)
-n Number of attempts per server (default: 3)
-p Max parallel jobs (default: 10)
EOF
exit 1
}
# defaults
tries=3
parallelism=10
record="MX"
# parse options
while getopts ":f:d:r:n:p:" opt; do
case $opt in
f) file="$OPTARG" ;;
d) domain="$OPTARG" ;;
r) record="${OPTARG^^}" ;; # uppercase record type
n) tries="$OPTARG" ;;
p) parallelism="$OPTARG" ;;
*) usage ;;
esac
done
[[ -z "${file:-}" || -z "${domain:-}" ]] && usage
# prepare workspace
mapfile -t lines < <(tail -n +2 "$file" | sed 's/\r$//')
workdir=$(mktemp -d)
lockfile="$workdir/.lock"
touch "$lockfile"
trap 'rm -rf "$workdir"' EXIT
# header
printf "\nQuerying %-4s records for %-25s\n\n" "$record" "$domain"
printf "%-15s | %-20s | %-15s | %-10s | %-2s | %8s | %9s | %11s | %15s\n" \
"IP Address" "Org" "City" "ASN" "CC" "Attempts" "Successes" "Reliability" "Avg Delay(ms)"
printf -- "-----------------+----------------------+-----------------+------------+----+----------+-----------+-------------+----------------\n"
# per-server worker
process_server(){
local line=$1
IFS=',' read -r ip _ asn org cc city _ _ _ _ <<<"$line"
ip="${ip//[[:space:]]/}" || return
[[ -z "$ip" ]] && return
local success=0 total_delay=0
for ((i=1; i<=tries; i++)); do
if out=$(dig +time=5 +tries=1 +stats "$record" "$domain" @"$ip" 2>&1); then
if grep -qE "^[^;].+${record}[[:space:]]" <<<"$out"; then
(( success++ ))
delay=$(awk '/^;; Query time:/ {print $4}' <<<"$out")
total_delay=$(( total_delay + delay ))
fi
fi
done
local avg_delay=0
(( success > 0 )) && avg_delay=$(( total_delay / success ))
local reliability
reliability=$(awk "BEGIN{printf \"%.1f\", ($success/$tries)*100}")
# flag any server that worked
if (( success > 0 )); then
touch "$workdir/${ip//./-}.ok"
fi
# save raw for summary
printf "%s|%s|%s|%s|%s|%d|%d|%s|%d\n" \
"$ip" "${org:-—}" "${city:-—}" "${asn:-—}" "${cc:-—}" \
"$tries" "$success" "$reliability" "$avg_delay" \
> "$workdir/${ip//./-}.out"
# real-time row (locked)
local disp_avg="—"
(( success > 0 )) && disp_avg="$avg_delay"
flock -x "$lockfile" -c \
"printf \"%-15s | %-20s | %-15s | %-10s | %-2s | %8d | %9d | %10s%% | %15s\n\" \
\"$ip\" \"${org:-—}\" \"${city:-—}\" \"${asn:-—}\" \"${cc:-—}\" \
\"$tries\" \"$success\" \"$reliability\" \"$disp_avg\""
}
# semaphore
wait_for_slot(){
while (( $(jobs -rp | wc -l) >= parallelism )); do
sleep 0.05
done
}
# dispatch
for line in "${lines[@]}"; do
wait_for_slot
process_server "$line" &
done
wait
# final aggregation
total_servers=0
total_successes=0
total_delay_sum=0
for f in "$workdir"/*.out; do
IFS='|' read -r ip org city asn cc att succ reli avg <<<"$(<"$f")"
(( total_servers++ ))
total_successes=$(( total_successes + succ ))
total_delay_sum=$(( total_delay_sum + avg ))
done
# count servers that worked
total_ok=$(ls "$workdir"/*.ok 2>/dev/null | wc -l)
# summary
echo -e "\n📊 Overall Summary:"
echo "---------------------------"
echo "Record Type : $record"
echo "Domain : $domain"
echo "Total DNS Servers Tested : $total_servers"
echo "Total Successful Queries : $total_successes"
echo "Servers that worked : $total_ok / $total_servers"
if (( total_servers > 0 )); then
avg_reliability=$(awk "BEGIN{printf \"%.1f\", ($total_successes/($total_servers*tries))*100}")
avg_response_delay=$(( total_delay_sum / total_servers ))
echo "Average Reliability : $avg_reliability%"
echo "Average Response Delay : ${avg_response_delay} ms"
else
echo "Average Reliability : —"
echo "Average Response Delay : —"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment