I would like to seek your advice on this peculiar problem I had with this script that I wrote.
It has Single Mode where it checks for 1 server or Multi Mode where you can point it to a text file containing multiple lines of hostname and ip address per lines.
For each set of hostname and ip address,
- It will pings the ip address, (ping -c 4 )
- run nmap {sudo nmap -Pn -p )
- check if nagios agent is installed using the check_nrpe plugin.
The original version runs perfectly good. However, for a particular server, it evaluates both conditions for IF and ELSE as true for the function where nmap is run.
Below I provide the script and also the output of bash -x, with the p address redacted. I have bolded the output that baffles me.
#!/usr/bin/env bash
Usage () {
echo -e "Usage Info"
}
while getopts ":H:S:T:f:p:PMN" opt;
do
case $opt in
H) # Host IP Address. Use this option if checking only single host.
HostAddr=$OPTARG
RunMode=1
;;
S) # Host Name. Use this option if checking only single host.
HostName=$OPTARG
;;
f) # absolute path to the text file containing list of IP Addresses. Use this option if checking multiple hosts.
HostFile=$OPTARG
RunMode=2
;;
P) # Ping the hostnames.
PingOn=1
;;
M) # Check using NMAP if specified port is open.
CheckPort=1
;;
p) # Specify port to be used by NMAP.
NPort=$OPTARG
;;
N) # Check if NRPE agent is installed and configured.
CheckNRPEOn=1
;;
?) # Error in option. Shows Usage guide.
Usage
;;
esac
done
cmd_Ping () {
PingResult=$(ping -c 4 "$HostIP" | grep 'transmitted' | awk -F ' ' '{ print $4 }')
if [[ "$PingResult" -eq 4 ]]; then
PingStatus='OK'
else
PingStatus='FAILED'
fi
PingOut=$(echo -e "Ping: $PingStatus")
}
cmd_NMAP () {
PortStatus=$(sudo nmap -Pn -p "$NPort" "$HostIP" | grep "$NPort" | awk -F ' ' '{ print $2 }')
if [[ "$PortStatus" = 'open' ]]; then
PortOut=$(echo -e "Port $NPort: OPEN")
elif [[ "$PortStatus" = 'filtered' ]]; then
PortOut=$(echo -e "Port $NPort: FILTERED")
elif [[ "$PortStatus" = 'closed' ]]; then
PortOut=$(echo -e "Port $NPort: CLOSED")
else
PortOut=$(echo -e "Port $NPort: ERROR")
fi
}
cmd_TNET () {
PortStatus=$(echo -e '\x1dclose\x0d' | timeout 5 sudo telnet "$HostIP" "$NPort" | grep Connected | awk -F' ' '{ print $1}')
if [[ "$PortStatus" = 'Connected' ]]; then
PortOut=$(echo -e "Port $NPort: OPEN")
else
PortOut=$(echo -e "Port $NPort: FAILED")
fi
}
cmd_NRPE () {
NRPEtmp=$(sudo /usr/local/nagios/libexec/check_nrpe -H "$HostIP")
NRPEnix=$(echo "$NRPEtmp" | awk -F ' ' '{ print $1 }')
NRPEwin=$(echo "$NRPEtmp" | cut -d ' ' -f4-)
if [[ "$NRPEnix" = 'NRPE' ]] || [[ "$NRPEwin" = 'seem to be doing fine...' ]]; then
NRPEOut=$(echo -e "NRPE: Configured")
else
NRPEOut=$(echo -e "NPRE: Not Configured")
fi
}
mode_Multi () { # Multiple IP Address Mode
while read -r HostInfo;
do
HostName=$(echo "$HostInfo" | awk -F ' ' '{ print $1 }')
HostIP=$(echo "$HostInfo" | awk -F ' ' '{ print $2 }')
if [[ $PingOn -eq 1 ]]; then
cmd_Ping
else # ($PingOn -ne 1 )
PingOut='N/A'
fi
if [[ "$CheckPort" -eq 1 ]]; then
cmd_NMAP
else # ($CheckPort -ne 1)
PortOut='N/A'
fi
if [[ "$CheckNRPEOn" -eq 1 ]]; then
cmd_NRPE
NRPEOut='N/A'
fi
echo -e " $HostName, $HostIP, $PingOut, $PortOut, $NRPEOut"
done < "$HostFile"
}
mode_Single () { # Single IP Address Mode
HostIP=$HostAddr
if [[ $PingOn -eq 1 ]]; then
cmd_Ping
else # ($PingOn -ne 1)
PingOut='N/A'
fi
if [[ "$CheckPort" -eq 1 ]]; then
cmd_NMAP
else # ($CheckPort -ne 1)
PortOut='N/A'
fi
if [[ "$CheckPort2" -eq 1 ]]; then
cmd_TNET
else
PortOut='N/A'
fi
if [[ "$CheckNRPEOn" -eq 1 ]]; then
cmd_NRPE
else
NRPEOut='N/A'
fi
echo -e "$HostName, $HostIP, $PingOut, $PortOut, $NRPEOut"
}
if [[ "$RunMode" -eq 1 ]]; then
mode_Single
else
mode_Multi
fi
and here is the output for Single Mode :
I would run this script like this :
./HostChecker.sh -S <HostName> -H <HostIP> -PMN -p <port number>
+ getopts :H:S:T:f:p:PMN opt
+ case $opt in
+ HostAddr=10.119.4.106
+ RunMode=1
+ getopts :H:S:T:f:p:PMN opt
+ case $opt in
+ PingOn=1
+ getopts :H:S:T:f:p:PMN opt
+ case $opt in
+ CheckNRPEOn=1
+ getopts :H:S:T:f:p:PMN opt
+ case $opt in
+ CheckPort=1
+ getopts :H:S:T:f:p:PMN opt
+ case $opt in
+ NPort=5666
+ getopts :H:S:T:f:p:PMN opt
+ [[ 1 -eq 1 ]]
+ mode_Single
+ HostIP=10.x.x.x
+ [[ 1 -eq 1 ]]
+ cmd_Ping
++ ping -c 4 10.x.x.x
++ grep transmitted
++ awk -F ' ' '{ print $4 }'
+ PingResult=0
+ [[ 0 -eq 4 ]]
+ PingStatus=FAILED
++ echo -e 'Ping: FAILED'
+ PingOut='Ping: FAILED'
+ [[ 1 -eq 1 ]]
+ cmd_NMAP
++ sudo nmap -Pn -p 5666 10.119.4.106
++ grep 5666
++ awk -F ' ' '{ print $2 }'
+ PortStatus=filtered
+ [[ filtered = \o\p\e\n ]]
+ [[ filtered = \f\i\l\t\e\r\e\d ]]
++ echo -e 'Port 5666: FILTERED'
+ PortOut='Port 5666: FILTERED'
+ [[ '' -eq 1 ]]
+ PortOut=N/A
+ [[ 1 -eq 1 ]]
+ cmd_NRPE
++ sudo /usr/local/nagios/libexec/check_nrpe -H 10.x.x.x
+ NRPEtmp='CHECK_NRPE STATE CRITICAL: Socket timeout after 10 seconds.'
++ echo 'CHECK_NRPE STATE CRITICAL: Socket timeout after 10 seconds.'
++ awk -F ' ' '{ print $1 }'
+ NRPEnix=CHECK_NRPE
++ echo 'CHECK_NRPE STATE CRITICAL: Socket timeout after 10 seconds.'
++ cut -d ' ' -f4-
+ NRPEwin='Socket timeout after 10 seconds.'
+ [[ CHECK_NRPE = \N\R\P\E ]]
+ [[ Socket timeout after 10 seconds. = \s\e\e\m\ \t\o\ \b\e\ \d\o\i\n\g\ \f\i\n\e\.\.\. ]]
++ echo -e 'NPRE: Not Configured'
+ NRPEOut='NPRE: Not Configured'
+ echo -e ', 10.x.x.x , Ping: FAILED, N/A, NPRE: Not Configured'
, 10.x.x.x , Ping: FAILED, N/A, NPRE: Not Configured
If you go through the output of bash -x, you will otice that the function cmd_NMAP somehow evaluates the conditions for IF and ELSE as true. What baffled me is there is that condition " [[ '' -eq 1 ]]" which I don't know where it comes from.
I have a feeling that this is something simple that I have somehow overlook but I've been at it for hours now and i somehow can't see it. I've even checked using ShellCheck and it tells me all is good.
All help is much appreciated. Thank you in advance.
I suspect what is wrong with your logic is, let's see:
What happens if
CheckPortis1, butChecPort2is other than1?The first
ifstatement will executecmd_NMAPwhich will set upPortOut. But immediately after that, the nextifstatement will execute itselseand clobberPortOut.If you want all these cases to be exclusive, do it another way. Perhaps you wanted this?
Only if none of the
CheckPort*variables are true, then we fall back on settingPortOuttoN/A.Evidence from your log that it's the second
ifstatement:cmd_NMAPis called:cmd_NMAPassigns the variable and returns:And the next
ifstatement is now testing$CheckPort2, which is blank, thus executes theelsewhich clobbersPortOuttoN/A: