#!/bin/bash ################################ # check iptables for open port # # # # Created by Bogdan Kukharskiy # # Namecheap # ################################ # This script is for testing IPTABLES if the specified port is open (with the possibility to exclude users) # # Usage: "check_openport.sh [-x eXclude users(can be as a list separated by ',')] -p Port to check" # # Returns the Nagios native status codes: # Nagios Status # 0 = OK (Specified port is NOT open or opened only for users from excluded list) # 1 = WARNING NO Warning states # 2 = CRITICAL (Specified port is OPENED, additionally shows users list OR specified port is not closed globally) # 3 = UNKNOWN (Wrong usage) # # Speed optimized version # Declaring arrays DEFAULT_EXCLUDE_ARRAY=('root' 'cpanel' 'mailman' 'mailnull') EXCLUDE_ARRAY=() PORTS_ARRAY=() OPEN_PORTS=() UNPRIV_PORTS=() ## USAGE MESSAGE usage() { cat << EOF usage: $0 options This script is for testing IPTABLES if the specified port(s) is(are) open (with the possibility to exclude users). Default excluded users: ${DEFAULT_EXCLUDE_ARRAY[@]} OPTIONS: -h Show this message -x eXclude users (optional, string (can be as a list separated by ',') -p Ports to check, integer number (can be as a list separated by ','), mandatory parameter EOF } # Generate a mapping of UID to username declare -A UID_TO_USERNAME while IFS=: read -r uid username; do UID_TO_USERNAME["$uid"]="$username" done < <(getent passwd) function check_open_ports() { # let's check if the requested port is opened for someone (in ACCEPT dest) IS_ACCEPT=0 for ARRSTR in "${ACCSTR_ARRAY[@]}"; do #PORTSTR=$(echo "$ARRSTR" | awk '{split($0,array,"--dports|--dport")} END{print array[2]}' | awk '{print$1}') IFS=' ' read -ra array <<< "${ARRSTR}" unset IFS array_index=0 PORTSTR="" OWNER="" for a in "${array[@]}"; do if [[ ${a} =~ "--dport" ]]; then PORTSTR=${array[array_index+1]} fi if [[ ${a} =~ "id-owner" ]]; then OWNER=${array[array_index+1]} fi array_index=$((array_index+1)) done if [[ ${#OWNER} -ne 0 ]]; then #owner of the rule is not empty if [[ $OWNER =~ ^[0-9]+$ ]]; then #if iptables returned number uid # OWNER=$(id -u -n $OWNER 2>/dev/null) OWNER="${UID_TO_USERNAME[$OWNER]}" fi if [[ ${PORTSTR} == *":"* ]]; then #result contains ":" what means we have to check the range of ports RANGESTART=$(echo "${PORTSTR}" | cut -d":" -f1) RANGEEND=$(echo "${PORTSTR}" | cut -d":" -f2) if ((PORT >= RANGESTART && PORT <= RANGEEND)); then if ! [[ "${EXCLUDE_ARRAY[@]}" =~ ${OWNER} ]]; then #checking that user is NOT in excluded array ALLOWED_ARRAY+=("${OWNER}") #adding to array IS_ACCEPT=1 fi fi; elif [[ ${PORTSTR} =~ ${RX} ]]; then if ! [[ "${EXCLUDE_ARRAY[@]}" =~ ${OWNER} ]]; then #checking that user is NOT in excluded array ALLOWED_ARRAY+=("${OWNER}") #adding to array IS_ACCEPT=1 fi fi fi done if [[ ${IS_ACCEPT} -eq 1 ]]; then return 5 fi # let's check if the requested port is closed totally (in REJECTED dest) for REJECTSTR in "${REJECTSTR_ARRAY[@]}"; do #PORTSTR=$(echo "$REJECTSTR" | awk '{split($0,array,"--dports|--dport")} END{print array[2]}' | awk '{print$1}') IFS=' ' read -ra rarray <<< "${REJECTSTR}" unset IFS array_index=0 PORTSTR="" for a in "${rarray[@]}"; do if [[ ${a} =~ "--dport" ]]; then PORTSTR=${rarray[array_index+1]} break else array_index=$((array_index+1)) fi done if [[ ${PORTSTR} == *":"* ]]; then #result contains ":" what means we have to check the range of ports RANGESTART=$(echo "${REJECTSTR}" | cut -d":" -f1) RANGEEND=$(echo "${REJECTSTR}" | cut -d":" -f2) if ((PORT >= RANGESTART && PORT <= RANGEEND)); then #OK, the port is blocked globally (at least in the REJECTed range ${REJECTSTR}) return 0 fi; elif [[ ${PORTSTR} =~ ${RX} ]]; then #OK, the port is blocked globally (at least in the REJECTed array ${RESULTSTR}) return 0 fi done return 1 } ## FETCH ARGUMENTS while getopts ":hx:p:" OPTION; do case "${OPTION}" in h) usage exit 3 ;; x) IFS=, read -r -a EXCLUDE_ARRAY <<< "$OPTARG" unset IFS ;; p) IFS=, read -r -a PORTS_ARRAY <<< "$OPTARG" unset IFS ;; ?) usage exit 3 ;; *) echo "No reasonable options found!" exit 3 ;; esac done ## CHECK ARGUMENTS if ! [[ ${#PORTS_ARRAY[@]} -eq 0 ]]; then for PORT in "${PORTS_ARRAY[@]}"; do if [ -z "${PORT}" ] || ! [[ ${PORT} =~ ^[0-9]+$ ]] ; then usage exit 3 fi done else usage exit 3 fi ## MAIN ROUTINE EXCLUDE_ARRAY=("${DEFAULT_EXCLUDE_ARRAY[@]}" "${EXCLUDE_ARRAY[@]}") #combine default exclude array with readed IPTABLES_OUTPUT=$(iptables -S) RESULTSTR=$(echo "${IPTABLES_OUTPUT}" |grep -i "\-j REJECT") if [ -z "${RESULTSTR}" ]; then echo "No REJECTs were found in IPTABLES" exit 2 fi RESULTSTR=$(echo "${IPTABLES_OUTPUT}" |grep -i "\-j ACCEPT") if [ -z "${RESULTSTR}" ]; then echo "No ACCEPTs were found in IPTABLES" exit 2 fi REJECTSTR_ARRAY=() ACCSTR_ARRAY=() # Loop through the iptables output and filter relevant rules while read -r line; do if [[ $line == *"-j REJECT"* && $line == *"dport"* ]]; then REJECTSTR_ARRAY+=("$line") elif [[ $line == *"-j ACCEPT"* && $line == *"dport"* ]]; then ACCSTR_ARRAY+=("$line") fi done <<< "${IPTABLES_OUTPUT}" if [[ ${#REJECTSTR_ARRAY[@]} -eq 0 ]]; then echo "No destination ports in REJECTs were found in IPTABLES" exit 2 elif [[ ${#ACCSTR_ARRAY[@]} -eq 0 ]]; then echo "No destination ports in ACCEPTs were found in IPTABLES" exit 2 fi UNPRIV_DATA="CRITICAL! Unprivileged users with opened: " for PORT in "${PORTS_ARRAY[@]}"; do ALLOWED_ARRAY=() RX="^${PORT}$|^${PORT},|,${PORT}$|,${PORT}," check_open_ports "${PORT}" RESULT=$? if [[ "${RESULT}" -eq 1 ]]; then OPEN_PORTS+=("${PORT}") elif [[ "${RESULT}" -eq 5 ]]; then UNPRIV_PORTS+=("${PORT}") USERS=$(echo "${ALLOWED_ARRAY[@]}" | tr ' ' ,) UNPRIV_DATA+="port: ${PORT} - ${USERS}. " unset ALLOWED_ARRAY fi done if ! [[ "${#UNPRIV_PORTS[@]}" -eq 0 ]]; then echo "${UNPRIV_DATA}" exit 2 elif ! [[ ${#OPEN_PORTS[@]} -eq 0 ]]; then #some ports are not blocked globally (not in any of REJECTs) echo "CRITICAL! Ports ${OPEN_PORTS[*]} are NOT blocked globally (not in any of REJECTs)" exit 2 else #there are no common users who have specified port opened and port is blocked globally echo "OK! Ports ${PORTS_ARRAY[*]} are closed globally and opened only for privileged users:" echo "${EXCLUDE_ARRAY[@]}" exit 0 fi