check_nmap.sh/check_nmap.sh

177 lines
3.2 KiB
Bash
Executable File

#!/bin/bash
function echoerr { echo "$@" 1>&2; }
### Parse attributes ###
INPUT=""
DEBUG=false
PORT_RANGE="1-65535"
NMAP_ARGS=""
KNOWN_PORTS=()
IPv=""
while [[ $# -gt 0 ]]; do
case $1 in
-h|--host) HOST="$2"; shift;;
-p|--portrange) PORT_RANGE="$2"; shift;;
-k|--known) KNOWN_PORTS+=($2); shift;;
-d|--debug) DEBUG=true;;
-4|--ipv4) IPv="";;
-6|--ipv6) IPv="-6";;
-i|--input)
INPUT="$2"
if [ ! -f "$INPUT" ]; then
echoerr "The specified input file '$INPUT' does not exist"
exit 3
fi
shift;;
--) shift; NMAP_ARGS="$@"; shift $#;;
-?|--help)
echo "Check nmap portscan. Arguments:"
echo "--host HOSTNAME/IP: Host that shall be scanned by nmap"
echo "--portrange RANGE: Ports that shall be scanned (nmap format)"
echo "--known PORTNUMBER: Port number that is expected to be open"
echo "--ipv6: Use IPv6 for the scan (IPv4 if not specified)"
exit 0
;;
*)
echoerr "Unknown argument: $1"
exit 3
;;
esac
shift
done
if [ -z "$HOST" -a -z "$INPUT" ]; then
echoerr "Missing host argument (-h)"
exit 3
fi
if ! command -v nmap &> /dev/null; then
echoerr "Missing nmap executable"
exit 3
fi
function log {
if $DEBUG; then
echo " > $@"
fi
}
function logLine {
if $DEBUG; then
echo " : $@"
fi
}
NL=$'\n'
log "INPUT: $INPUT"
log "PORT_RANGE: $PORT_RANGE"
log "KNOWN_PORTS: ${KNOWN_PORTS[@]}"
function runNmap {
local $portrange
if [ -n "$PORT_RANGE" ]; then
portrange="-p$PORT_RANGE"
else
portrange=""
fi
local $input
if [ -n "$INPUT" ]; then
while read -r line; do
parseLine "$line"
done < $INPUT
else
local $cmd
cmd="nmap $portrange $IPv $NMAP_ARGS -- $HOST"
log "$cmd"
while read -r line; do
parseLine "$line"
done <<< $($cmd)
result=$?
log "nmap exited with $result"
if [ $result -ne 0 ]; then
echoerr "CRITICAL - nmap exited with $result"
exit 2
fi
fi
}
NOW_PORTS=false
PORT_STATES=()
PORT_NAMES=()
function parseLine {
local line="$1"
if ! $NOW_PORTS; then
if [[ "$line" == PORT*STATE*SERVICE ]]; then
NOW_PORTS=true
fi
else
if [ -z "$line" ]; then
NOW_PORTS=false
else
local split
read -ra split <<< "$line"
local number=${split[0]/\/*}
local state=${split[1]}
local name=${split[2]}
PORT_STATES[$number]=$state
PORT_NAMES[$number]=$name
fi
fi
}
ERROR=false
UNEXP_OPEN_PORTS=()
function comparePorts {
log ${KNOWN_PORTS[@]}
KNOWN_PORTS=($(for each in ${KNOWN_PORTS[@]}; do echo $each; done | sort))
log ${KNOWN_PORTS[@]}
for port in "${!PORT_STATES[@]}"; do
if [[ "${PORT_STATES[$port]}" != open* ]]; then
continue;
fi
skip=false
for j in "${KNOWN_PORTS[@]}"; do
if [ $j -eq $port ]; then
skip=true
break
fi
done
if ! $skip; then
log Unexpected open port: $port
UNEXP_OPEN_PORTS+=($port)
fi
done
if [ ${#UNEXP_OPEN_PORTS[@]} -gt 0 ]; then
ERROR=true
fi
}
function print {
if $ERROR; then
echo -n "CRITICAL - These ports should not be open: ${UNEXP_OPEN_PORTS[@]}"
else
echo -n "OK"
fi
echo -n " | "
for port in "${!PORT_STATES[@]}"; do
echo -n "'${PORT_NAMES[$port]} ($port): ${PORT_STATES[$port]}'=0 "
done
}
runNmap
comparePorts
print
if $ERROR; then
exit 2
else
exit 0
fi