Last active
July 6, 2023 07:53
-
-
Save silverweed/36d539ac68b13c6a50d5f449d64d4754 to your computer and use it in GitHub Desktop.
Checks if LAN hosts are up in parallel
This file contains 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 | |
# parallel port check via nc. Takes ~1 s per scanned service, but | |
# should almost not depend on the number of hosts. | |
# by silverweed | |
# FIXME: echo-ing lines from check_host may result in more lines | |
#+ bloated together. | |
# file containing the IPs to scan | |
HOSTLIST="$HOME/.hostlist.txt" | |
NC="/bin/nc" | |
# map of default services -> ports to scan | |
declare -A TO_CHECK | |
TO_CHECK[ssh]=22 | |
TO_CHECK[http]=80 | |
# preliminary checks | |
[[ -r $HOSTLIST ]] || { | |
echo "$HOSTLIST not readable: exiting." >&2 | |
exit 1 | |
} | |
[[ -x $NC ]] || { | |
echo "$NC not executable: exiting." >&2 | |
exit 2 | |
} | |
# given a host IP, checks all services in TO_CHECK and returns an associative | |
# array IS_UP with the results (0 = up, 1 = not up) | |
check_host() { | |
[[ -n $1 ]] || { | |
echo "Warning: invalid argument for check_host(): $1" >&2 | |
return 1 | |
} | |
ping -c 1 -w 1 $1 &> /dev/null || { | |
[[ $1 =~ ^([0-9]{1,3}\.){3}([0-9]{1,3})$ ]] || { | |
echo -en "\033[1;31m" | |
printf "%-16s " "$1:" | |
echo -e "down\033[0;0m" | |
} | |
return | |
} | |
declare -A IS_UP | |
for SERVICE in ${!TO_CHECK[@]}; do | |
$NC -w 1 $1 ${TO_CHECK[$SERVICE]} &> /dev/null | |
IS_UP[$SERVICE]=$? | |
done | |
echo -en "\033[1;32m" | |
printf "%-16s " "$1:" | |
for SERVICE in ${!IS_UP[@]}; do | |
if [[ ${IS_UP[$SERVICE]} == 0 ]]; then | |
echo -en "\033[1;32m" | |
else | |
echo -en "\033[1;31m" | |
fi | |
echo -en "$SERVICE \033[0;0m" | |
done | |
echo "" | |
} | |
add_service() { | |
SRV=$(awk -v FS=':' '{ print $1 }' <(echo $1)) | |
PORT=$(awk -v FS=':' '{ print $2 }' <(echo $1)) | |
if [[ $PORT ]]; then | |
TO_CHECK["${SRV:-?}"]=$PORT | |
else | |
# try to resolve port number from service name | |
TO_CHECK["$SRV"]=$(awk "/^\s*[^#]/ && /$SRV/ { print \$2; exit }" /etc/services | cut -f1 -d'/') | |
if [[ ${TO_CHECK["$SRV"]} ]]; then | |
echo "[INFO] Scanning service $SRV on port ${TO_CHECK[$SRV]}." >&2 | |
else | |
echo -n "[ERR] Failed to resolve port for service $SRV. " | |
echo "Please specify it with '-s $SRV:<port>'." >&2 | |
fi | |
fi | |
} | |
SORT='sort -g' | |
while [[ $# -gt 0 ]]; do | |
case $1 in | |
-s) | |
unset TO_CHECK | |
declare -A TO_CHECK | |
shift | |
while [[ $# -gt 0 && ! $1 =~ -.* ]]; do | |
add_service "$1" | |
shift | |
done | |
;; | |
-n) | |
DONTRESOLVE=true | |
SORT="sort -g -k4 -t'.'" | |
shift | |
;; | |
*) | |
echo "Usage: $0 [-n] [-s <service1[:port]> [service2[:port] ...] ]" >&2 | |
exit 0 | |
;; | |
esac | |
done | |
declare -a PIDS | |
i=0 | |
echo "Checking $(wc -l $HOSTLIST | awk '{print $1}') hosts..." >&2 | |
STARTTIME=$(date +%s) | |
for HOST in $(< $HOSTLIST); do | |
if [[ $DONTRESOLVE != true ]]; then | |
RESOLVE=$(grep $HOST /etc/hosts | awk '{print $2}') | |
[[ -n $RESOLVE ]] && HOST=$RESOLVE | |
fi | |
# parallel scan | |
check_host $HOST & PIDS[$i]=$! | |
let i++ | |
done | eval "$SORT" | |
for ((j = 0; j < i; j++)); do | |
wait ${PIDS[$j]} | |
done | |
echo "Elapsed time: $(($(date +%s) - STARTTIME)) s" >&2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment