#!/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