Bash Script - If Else statement evaluates TRUE

164 Views Asked by At

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.

1

There are 1 best solutions below

0
Kaz On

I suspect what is wrong with your logic is, let's see:

    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 

What happens if CheckPort is 1, but ChecPort2 is other than 1?

The first if statement will execute cmd_NMAP which will set up PortOut. But immediately after that, the next if statement will execute its else and clobber PortOut.

If you want all these cases to be exclusive, do it another way. Perhaps you wanted this?

    if [[ "$CheckPort" -eq 1 ]]; then
        cmd_NMAP
    elif [[ "$CheckPort2" -eq 1 ]]; then 
        cmd_TNET
    else 
        PortOut='N/A'
    fi

Only if none of the CheckPort* variables are true, then we fall back on setting PortOut to N/A.

Evidence from your log that it's the second if statement:

cmd_NMAP is called:

++ 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 ]]

cmd_NMAP assigns the variable and returns:

++ echo -e 'Port 5666: FILTERED'
+ PortOut='Port 5666: FILTERED'

And the next if statement is now testing $CheckPort2, which is blank, thus executes the else which clobbers PortOut to N/A:

+ [[ '' -eq 1 ]]
+ PortOut=N/A