Last active
October 10, 2022 04:15
-
-
Save gbot/53c9d5b4d79f75790443db5f0b665c91 to your computer and use it in GitHub Desktop.
Use 'nslookup' to query one or more domains, using a pre-defined list of nameservers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# what's this all about then? | |
description="Use 'nslookup' to query one or more domains, using a pre-defined list of nameservers" | |
# set nameservers as associative array | |
declare -A nameservers | |
nameservers['AdGuard DNS']='94.140.14.14' | |
nameservers['Alternate DNS']='76.76.19.19' | |
nameservers['CloudFlare']='1.1.1.1' | |
nameservers['Control D']='76.76.2.0' | |
nameservers['Digital Ocean SG']='139.59.219.245' | |
nameservers['Google']='8.8.8.8' | |
nameservers['ICONZ']='210.48.77.68' | |
nameservers['OpenDNS']='208.67.222.222' | |
nameservers['Orcon NZ']='121.98.0.1' | |
nameservers['Quad9']='9.9.9.9' | |
nameservers['SiteHost NZ']='223.165.64.97' | |
nameservers['Telstra AU']='139.130.4.4' | |
# nameservers['Voyager NZ']='103.21.194.19' | |
nameservers['Yandex Basic DNS']='77.88.8.8' | |
nameservers['Yandex Safe DNS']='77.88.8.88' | |
# misc. vars / settings / default | |
lookup_type="A" | |
this_script=$(basename "${BASH_SOURCE[0]}") | |
# colors, cos we like colours! | |
clr_default="\e[0m" | |
clr_white="\e[1m" | |
clr_dim="\e[2m" | |
clr_inverse="\e[7m" | |
clr_red="\e[31m" | |
clr_green="\e[32m" | |
clr_yellow="\e[33m" | |
clr_cyan="\e[36m" | |
# help text | |
help() { | |
echo "$description" | |
echo -e "${clr_yellow}Either pass in a list of domains: \n\t${clr_default}${this_script} domain.com\n\t${this_script} 'domain.com domain2.com domain3.com'\n\t${this_script} -d domain.com \n\t${this_script} --domains='domain.com domain2.com'\e[0m" | |
echo -e "${clr_yellow}Or export a ENV variable 'domains': \n\t${clr_default}export domains=\"domain.com domain2.com\"\e[0m" | |
echo -e "${clr_yellow}OPTIONS:${clr_default}" | |
echo -e "\t -d | --domains \tDomain(s) to query" | |
echo -e "\t -t | --type \t\tSet query type [ A = default | AAAA | NS | MX ]" | |
echo -e "\t -e | --expected \tHighlight result RED if doesn't match 'expected'" | |
echo -e "\t -h | --help \t\tDisplay this help" | |
echo -e "${clr_yellow}EXAMPLES:${clr_default}" | |
echo -e "\t${this_script} -t NS domain.com" | |
echo -e "\t${this_script} -d domain.com -e 123.123.123.123" | |
echo -e "\t${this_script} --domains='domain.com domain2.com' --type=NS" | |
echo -e "${clr_yellow}NOTES:${clr_default} \n\tWhen passing domains without a preceding option (-d | --domains), it must be the last argument." | |
echo | |
exit | |
} | |
# write error to STDERR and exit | |
die() { | |
echo -e "${clr_red}ERROR:${clr_default} $1 ${clr_dim}${2}${clr_default}" >&2; exit 2; | |
} | |
# getopts required arg fallback | |
option_needs_arg() { | |
if [ -z "$OPTARG" ] ; then | |
die "Missing argument for --$OPT" "[ERR1:long-option-missing-arg]" | |
fi | |
} | |
while getopts :d:ht:e:-: OPT; do | |
# support long options: https://stackoverflow.com/a/28466267/519360 | |
if [ "$OPT" = "-" ]; then # long option: reformulate OPT and OPTARG | |
OPT="${OPTARG%%=*}" # extract long option name | |
OPTARG="${OPTARG#$OPT}" # extract long option argument (may be empty) | |
OPTARG="${OPTARG#=}" # if long option argument, remove assigning "=" | |
fi | |
case "$OPT" in | |
h | help ) | |
help;; | |
e | expected ) | |
option_needs_arg | |
expected_result="$OPTARG";; | |
t | type ) | |
option_needs_arg | |
lookup_type="${OPTARG^^}";; # convert to uppercase "^^" | |
d | domains ) | |
option_needs_arg | |
domains="$OPTARG";; | |
: ) | |
die "Missing argument for -$OPTARG" "[ERR2:missing-arg]";; | |
??* ) | |
die "Unrecognised option --$OPT" "[ERR3:bad-long-option]";; | |
? ) | |
die "Unrecognised option -$OPTARG" "[ERR4:bad-short-option]";; | |
esac | |
done | |
shift $((OPTIND-1)) # remove parsed options and args from $@ list | |
# if there is a remaining argument, consider it as a list of domains to query | |
if [[ $1 != '' ]]; then | |
domains="${1}" | |
elif [[ $domains == '' ]]; then | |
echo -e "\e[31mNo domains to query!\e[0m" | |
help | |
fi | |
# check 'lookup_type' for accepted values | |
case "$lookup_type" in | |
NS | A | AAAA | MX ) ;; | |
* ) die "Unsupported lookup type";; | |
esac | |
do_nslookup_loop() { | |
for this_domain in $domains; do | |
echo -e "${clr_cyan}+ $this_domain ...${clr_default}" | |
echo -e " ${clr_yellow}Nameserver:\t\t\t\t\tResult:${clr_default}" | |
for key in "${!nameservers[@]}"; do | |
# run nslookup | |
local nslookup_result=$( nslookup -type="${lookup_type}" $this_domain ${nameservers[$key]} ) | |
# check for failure | |
local failed="$( echo "$nslookup_result" | egrep "NXDOMAIN|No answer" )" | |
if [[ $failed != '' ]]; then | |
local result_output="NOT FOUND!" | |
else | |
# check if this is a canonical lookup | |
local canonical="$( echo "$nslookup_result" | grep "canonical name" | cut -f2 )" | |
# format result_output according to lookup type, i.e. NS, A | |
if [[ $lookup_type == "NS" ]]; then | |
local result_output=$( echo "${nslookup_result}" | grep "nameserver =" | cut -f2 -d'=' | sed 's/^ //' | sed 's/.$//' | sort ) | |
elif [[ $lookup_type == "MX" ]]; then | |
local result_output="$( echo "$nslookup_result" | tail -4 | grep "mail exchanger =" | cut -f2 -d'=' | cut -f3 -d' ' | sed 's/.$//' | sort )" | |
else # default for 'A' or 'AAAA' lookup | |
local result_output="$( echo "$nslookup_result" | tail -3 | grep "Address:" | cut -f2 -d' ' )" | |
fi | |
fi | |
# output | |
echo -e -n "${clr_white} ${key} ${clr_dim}[${nameservers[$key]}]${clr_default}" | |
# hacky method faking column layout (pad spaces based on length of col 1 ) | |
loops="$(( 42 - (( ${#key} + ${#nameservers[$key]} )) ))" | |
for i in $( seq 0 $loops ); do echo -n " "; done | |
if [[ $result_output == *"$expected_result"* ]] || [[ $expected_result == '' ]] && [[ $failed == '' ]]; then | |
echo -en "${clr_green}" | |
else | |
echo -en "${clr_red}" | |
fi | |
echo -en ${result_output}${clr_default} | |
if [[ $canonical != '' ]] && [[ $failed == '' ]] ; then | |
canonical="CNAME: $( echo $canonical | cut -f2 -d '=' | sed 's/^ //' )" | |
echo -en " ${clr_dim}${canonical}${clr_default}" | |
fi | |
echo # newline | |
done | |
done | |
} | |
# run the nslookup loop | |
do_nslookup_loop | |
# tidy up | |
unset domains | |
unset nameservers | |
exit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Added support for A, AAAA, NS and MX query types