LDP/LDP/guide/docbook/abs-guide/whx.sh

281 lines
8.9 KiB
Bash

#!/bin/bash
# whx.sh: "whois" spammer lookup
# Author: Walter Dnes
# Slight revisions (first section) by ABS Guide author.
# Used in ABS Guide with permission.
# Needs version 3.x or greater of Bash to run (because of =~ operator).
# Commented by script author and ABS Guide author.
E_BADARGS=85 # Missing command-line arg.
E_NOHOST=86 # Host not found.
E_TIMEOUT=87 # Host lookup timed out.
E_UNDEF=88 # Some other (undefined) error.
HOSTWAIT=10 # Specify up to 10 seconds for host query reply.
# The actual wait may be a bit longer.
OUTFILE=whois.txt # Output file.
PORT=4321
if [ -z "$1" ] # Check for (required) command-line arg.
then
echo "Usage: $0 domain name or IP address"
exit $E_BADARGS
fi
if [[ "$1" =~ [a-zA-Z][a-zA-Z]$ ]] # Ends in two alpha chars?
then # It's a domain name &&
#+ must do host lookup.
IPADDR=$(host -W $HOSTWAIT $1 | awk '{print $4}')
# Doing host lookup
#+ to get IP address.
# Extract final field.
else
IPADDR="$1" # Command-line arg was IP address.
fi
echo; echo "IP Address is: "$IPADDR""; echo
if [ -e "$OUTFILE" ]
then
rm -f "$OUTFILE"
echo "Stale output file \"$OUTFILE\" removed."; echo
fi
# Sanity checks.
# (This section needs more work.)
# ===============================
if [ -z "$IPADDR" ]
# No response.
then
echo "Host not found!"
exit $E_NOHOST # Bail out.
fi
if [[ "$IPADDR" =~ ^[;;] ]]
# ;; Connection timed out; no servers could be reached.
then
echo "Host lookup timed out!"
exit $E_TIMEOUT # Bail out.
fi
if [[ "$IPADDR" =~ [(NXDOMAIN)]$ ]]
# Host xxxxxxxxx.xxx not found: 3(NXDOMAIN)
then
echo "Host not found!"
exit $E_NOHOST # Bail out.
fi
if [[ "$IPADDR" =~ [(SERVFAIL)]$ ]]
# Host xxxxxxxxx.xxx not found: 2(SERVFAIL)
then
echo "Host not found!"
exit $E_NOHOST # Bail out.
fi
# ======================== Main body of script ========================
AFRINICquery() {
# Define the function that queries AFRINIC. Echo a notification to the
#+ screen, and then run the actual query, redirecting output to $OUTFILE.
echo "Searching for $IPADDR in whois.afrinic.net"
whois -h whois.afrinic.net "$IPADDR" > $OUTFILE
# Check for presence of reference to an rwhois.
# Warn about non-functional rwhois.infosat.net server
#+ and attempt rwhois query.
if grep -e "^remarks: .*rwhois\.[^ ]\+" "$OUTFILE"
then
echo " " >> $OUTFILE
echo "***" >> $OUTFILE
echo "***" >> $OUTFILE
echo "Warning: rwhois.infosat.net was not working \
as of 2005/02/02" >> $OUTFILE
echo " when this script was written." >> $OUTFILE
echo "***" >> $OUTFILE
echo "***" >> $OUTFILE
echo " " >> $OUTFILE
RWHOIS=`grep "^remarks: .*rwhois\.[^ ]\+" "$OUTFILE" | tail -n 1 |\
sed "s/\(^.*\)\(rwhois\..*\)\(:4.*\)/\2/"`
whois -h ${RWHOIS}:${PORT} "$IPADDR" >> $OUTFILE
fi
}
APNICquery() {
echo "Searching for $IPADDR in whois.apnic.net"
whois -h whois.apnic.net "$IPADDR" > $OUTFILE
# Just about every country has its own internet registrar.
# I don't normally bother consulting them, because the regional registry
#+ usually supplies sufficient information.
# There are a few exceptions, where the regional registry simply
#+ refers to the national registry for direct data.
# These are Japan and South Korea in APNIC, and Brasil in LACNIC.
# The following if statement checks $OUTFILE (whois.txt) for the presence
#+ of "KR" (South Korea) or "JP" (Japan) in the country field.
# If either is found, the query is re-run against the appropriate
#+ national registry.
if grep -E "^country:[ ]+KR$" "$OUTFILE"
then
echo "Searching for $IPADDR in whois.krnic.net"
whois -h whois.krnic.net "$IPADDR" >> $OUTFILE
elif grep -E "^country:[ ]+JP$" "$OUTFILE"
then
echo "Searching for $IPADDR in whois.nic.ad.jp"
whois -h whois.nic.ad.jp "$IPADDR"/e >> $OUTFILE
fi
}
ARINquery() {
echo "Searching for $IPADDR in whois.arin.net"
whois -h whois.arin.net "$IPADDR" > $OUTFILE
# Several large internet providers listed by ARIN have their own
#+ internal whois service, referred to as "rwhois".
# A large block of IP addresses is listed with the provider
#+ under the ARIN registry.
# To get the IP addresses of 2nd-level ISPs or other large customers,
#+ one has to refer to the rwhois server on port 4321.
# I originally started with a bunch of "if" statements checking for
#+ the larger providers.
# This approach is unwieldy, and there's always another rwhois server
#+ that I didn't know about.
# A more elegant approach is to check $OUTFILE for a reference
#+ to a whois server, parse that server name out of the comment section,
#+ and re-run the query against the appropriate rwhois server.
# The parsing looks a bit ugly, with a long continued line inside
#+ backticks.
# But it only has to be done once, and will work as new servers are added.
#@ ABS Guide author comment: it isn't all that ugly, and is, in fact,
#@+ an instructive use of Regular Expressions.
if grep -E "^Comment: .*rwhois.[^ ]+" "$OUTFILE"
then
RWHOIS=`grep -e "^Comment:.*rwhois\.[^ ]\+" "$OUTFILE" | tail -n 1 |\
sed "s/^\(.*\)\(rwhois\.[^ ]\+\)\(.*$\)/\2/"`
echo "Searching for $IPADDR in ${RWHOIS}"
whois -h ${RWHOIS}:${PORT} "$IPADDR" >> $OUTFILE
fi
}
LACNICquery() {
echo "Searching for $IPADDR in whois.lacnic.net"
whois -h whois.lacnic.net "$IPADDR" > $OUTFILE
# The following if statement checks $OUTFILE (whois.txt) for
#+ the presence of "BR" (Brasil) in the country field.
# If it is found, the query is re-run against whois.registro.br.
if grep -E "^country:[ ]+BR$" "$OUTFILE"
then
echo "Searching for $IPADDR in whois.registro.br"
whois -h whois.registro.br "$IPADDR" >> $OUTFILE
fi
}
RIPEquery() {
echo "Searching for $IPADDR in whois.ripe.net"
whois -h whois.ripe.net "$IPADDR" > $OUTFILE
}
# Initialize a few variables.
# * slash8 is the most significant octet
# * slash16 consists of the two most significant octets
# * octet2 is the second most significant octet
slash8=`echo $IPADDR | cut -d. -f 1`
if [ -z "$slash8" ] # Yet another sanity check.
then
echo "Undefined error!"
exit $E_UNDEF
fi
slash16=`echo $IPADDR | cut -d. -f 1-2`
# ^ Period specified as 'cut" delimiter.
if [ -z "$slash16" ]
then
echo "Undefined error!"
exit $E_UNDEF
fi
octet2=`echo $slash16 | cut -d. -f 2`
if [ -z "$octet2" ]
then
echo "Undefined error!"
exit $E_UNDEF
fi
# Check for various odds and ends of reserved space.
# There is no point in querying for those addresses.
if [ $slash8 == 0 ]; then
echo $IPADDR is '"This Network"' space\; Not querying
elif [ $slash8 == 10 ]; then
echo $IPADDR is RFC1918 space\; Not querying
elif [ $slash8 == 14 ]; then
echo $IPADDR is '"Public Data Network"' space\; Not querying
elif [ $slash8 == 127 ]; then
echo $IPADDR is loopback space\; Not querying
elif [ $slash16 == 169.254 ]; then
echo $IPADDR is link-local space\; Not querying
elif [ $slash8 == 172 ] && [ $octet2 -ge 16 ] && [ $octet2 -le 31 ];then
echo $IPADDR is RFC1918 space\; Not querying
elif [ $slash16 == 192.168 ]; then
echo $IPADDR is RFC1918 space\; Not querying
elif [ $slash8 -ge 224 ]; then
echo $IPADDR is either Multicast or reserved space\; Not querying
elif [ $slash8 -ge 200 ] && [ $slash8 -le 201 ]; then LACNICquery "$IPADDR"
elif [ $slash8 -ge 202 ] && [ $slash8 -le 203 ]; then APNICquery "$IPADDR"
elif [ $slash8 -ge 210 ] && [ $slash8 -le 211 ]; then APNICquery "$IPADDR"
elif [ $slash8 -ge 218 ] && [ $slash8 -le 223 ]; then APNICquery "$IPADDR"
# If we got this far without making a decision, query ARIN.
# If a reference is found in $OUTFILE to APNIC, AFRINIC, LACNIC, or RIPE,
#+ query the appropriate whois server.
else
ARINquery "$IPADDR"
if grep "whois.afrinic.net" "$OUTFILE"; then
AFRINICquery "$IPADDR"
elif grep -E "^OrgID:[ ]+RIPE$" "$OUTFILE"; then
RIPEquery "$IPADDR"
elif grep -E "^OrgID:[ ]+APNIC$" "$OUTFILE"; then
APNICquery "$IPADDR"
elif grep -E "^OrgID:[ ]+LACNIC$" "$OUTFILE"; then
LACNICquery "$IPADDR"
fi
fi
#@ ---------------------------------------------------------------
# Try also:
# wget http://logi.cc/nw/whois.php3?ACTION=doQuery&DOMAIN=$IPADDR
#@ ---------------------------------------------------------------
# We've now finished the querying.
# Echo a copy of the final result to the screen.
cat $OUTFILE
# Or "less $OUTFILE" . . .
exit 0
#@ ABS Guide author comments:
#@ Nothing fancy here, but still a very useful tool for hunting spammers.
#@ Sure, the script can be cleaned up some, and it's still a bit buggy,
#@+ (exercise for reader), but all the same, it's a nice piece of coding
#@+ by Walter Dnes.
#@ Thank you!