Archive

Archive for April, 2017

Nagios NRPE wrapper to encode meta-characters

April 23, 2017 Leave a comment

The Nagios Remote Plugin Executor allows remote execution of Nagios check commands, which is a powerful tool for monitoring the health of the machines and services on your network.

If your remote commands take command line parameters, you might run into trouble regarding special characters, typically required in regular expressions and other values you might want to send across. To actually see the error on the target machine, you need to Create a Log File for NRPE.

If your command fails due to this kind of error, then read on:

Apr 6 18:06:58 somehost nrpe[somepid]: Error: Request contained illegal metachars!
Apr 6 18:06:58 somehost nrpe[somepid]: Client request was invalid, bailing out...

NRPE inspects the arguments for characters that have special meaning for typical Unix shells to prevent shell command injection. If it encounters any charcaters deemed unsafe the command execution is rejected and you will see the error message above.

Unfortunately NRPE does not provide a way to safely encode and decode the parameter values.

To work around this, I created a wrapper script for the check_nrpe command, let’s call it check_nrpe_urlencoded.sh. I chose url-encoding for its simplicity and familiarity. The goal is to be able to create Nagios command definitions like this:

$USER1$/custom_scripts/check_nrpe_urlencoded.sh -H $HOSTADDRESS$ -c my_remote_command -a '$ARG1$' '$ARG2$'

And the remote command would bedefined in /etc/nagios/nrpe.cfg or under in a custom file under /etc/nrpe.d/, depending on your Linux distribtion:

command[my_remote_command]=/path_to_my_custom_nrpe_plugins/my_remote_command.sh '$ARG1$' '$ARG2$'

Here is a possible implementation of check_nrpe_urlencoded.sh:

#! /bin/bash

command='/usr/lib/nagios/plugins/check_nrpe'
args='no'

urlencode() {
    old_lc_collate=$LC_COLLATE
    LC_COLLATE=C

    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:i:1}"
        case ${c} in
            [a-zA-Z0-9.~_-]) printf "$c" ;;
            *) printf '%%%02X' "'$c" ;;
        esac
    done

    LC_COLLATE=${old_lc_collate}
}

for x in "$@"; do
  if [ ${x} = '-a' ]; then
    args='yes';
  else
    if [ ${args} = 'yes' ]; then
       x=$(urlencode ${x})
    fi
  fi
  command="${command} ${x}"
done

# execute the check_nrpe with the encoded args:
${command}

In the remote shell script like my_remote_command.sh, you would then decode the arguments like this:

function urldecode() {
  local url_encoded="${1//+/ }"
  printf '%b' "${url_encoded//%/\\x}"
}
arg1="$(urldecode $1)"
arg2="$(urldecode $2)"

And then use the decoded arguments as before.

Advertisements
Categories: bash, coding Tags: ,