Current File : //proc/thread-self/root/lib64/nagios/plugins/nccustom/check_openport.sh |
#!/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