Archivi tag: nagios

CentOS 6 e Nagios: script bash per monitorare la scadenza dei certificati X.509

A quanti di voi sarà capitato di dover fare i conti con un certificato X.509 scaduto (magari installato su un server in produzione) che avete scordato (per un motivo o per un altro) di rinnovare?

Ebbene, tramite il seguente scrip bash (da integrare a Nagios) non dovremo più “appuntarci” la data di scadenza dei suddetti certificati, poichè sarà proprio l’NMS a ricordarci (a tempo debito) di procedere con il rinnovo.

nagiosEcco lo scrip:

#!/bin/bash

############Scrip powered by nightfly. Default values for warn and crit############
############(if not defined by command line) are 10 and 3 respectivley##############

host=$1
port=$2
warn=$3
crit=$4

function get_cert_datetime() {

        date=`echo | openssl s_client -connect $host:$port 2>/dev/null | openssl x509 -noout -dates | grep notAfter | awk -F "=" '{print $2 }'`

        day=`echo $date | awk '{print $2}'`

        case $day in

        1)

                day=01;
                ;;

        2)

                day=02;
                ;;

        3)

                day=03;
                ;;

        4)

                day=04;
                ;;

        5)

                day=05;
                ;;

        6)

                day=06;
                ;;

        7)

                day=07;
                ;;

        8)

                day=08;
                ;;

        9)

                day=09;
                ;;

        esac

        month=`echo $date | awk '{print $1}'`

        case $month in

        Jan)

                 month=01;
                ;;

        Feb)

                month=02;
                ;;

        Mar)

                month=03;
                ;;

        Apr)

                month=04;
                ;;

        May)

                month=05;
                ;;

        Jun)

                month=06;
                ;;

        Jul)

                month=07;
                ;;

        Aug)

                month=08;
                ;;

        Sep)

                month=09;
                ;;

        Oct)

                month=10;
                ;;

        Nov)

                month=11;
                ;;

        Dec)

                month=12;
                ;;
        esac

        year=`echo $date | awk '{print $4}'`

        time=`echo $date | awk '{print $3}'`

        hours=`echo $time | awk -F ":" '{print $1}'`

        minutes=`echo $time | awk -F ":" '{print $2}'`

        seconds=`echo $time | awk -F ":" '{print $3}'`

        datecheck="$year$month$day"

        datecheckepoch=`date -d "$datecheck" +"%s"`

        datenow=`date +"%Y%m%d"`

        datenowepoch=`date -d "$datenow" +"%s"`

}

get_cert_datetime;

get_time_diff() {

        #time difference in hours, minutes and seconds

        hoursnow=`date +"%H"`

        minutesnow=`date +"%M"`

        secondsnow=`date +"%S"`

        hourstoseconds=`expr $hoursnow "*" 3600`

        minutestosecond=`expr $minutesnow "*" 60`

        secondsnowtot=`expr $hourstoseconds + $minutestosecond + $secondsnow`

        hourschecktoseconds=`expr $hours "*" 3600`

        minuteschecktoseconds=`expr $minutes "*" 60`

        secondschecktot=`expr $hourschecktoseconds + $minuteschecktoseconds + $seconds`

        secondsdiff=`expr $secondschecktot - $secondsnowtot`

        secondstoexpire=`expr 86400 - $secondsnowtot + $secondschecktot`

        minutestoexpire=`expr $secondstoexpire / 60`

        spareseconds=`expr $secondstoexpire % 60`

        hourstoexpire=`expr $minutestoexpire / 60`

        spareminutes=`expr $minutestoexpire % 60`
}

get_time_diff;

timestamp_to_days() {

        #unix timestamp to days conversion

        secondsleft=`expr $datecheckepoch - $datenowepoch`

        minutesleft=`expr $secondsleft / 60`

        hoursleft=`expr $minutesleft / 60`

        daysleft=`expr $hoursleft / 24`

}

timestamp_to_days;

if [[ ! -z $host && ! -z $port ]];then

        if [[ $datecheckepoch -gt $datenowepoch ]];then

                if [[ -z $warn && -z $crit ]];then

                        if [[ $daysleft -ge 10 ]];then

                                echo "OK: the X.509 certificate will expire in $daysleft days $hourstoexpire hours $spareminutes minutes $spareseconds seconds | days_left=$daysleft"

                                exit 0

                        elif [[ $daysleft -lt 10 && $daysleft -gt 3 ]];then

                                echo "WARNING: the X.509 certificate will expire in $daysleft days $hourstoexpire hours $spareminutes minutes $spareseconds seconds | days_left=$daysleft"

                                exit 1

                        elif [[ $daysleft -lt 3 && $daysleft -gt 0 ]];then

                                echo "CRITICAL: the X.509 certificate will expire in $daysleft days $hourstoexpire hours $spareminutes minutes $spareseconds seconds | days_left=$daysleft"

                                exit 2

                        elif [[ $daysleft -eq 0 && $secondsdiff -gt 0 ]];then

                                echo "CRITICAL: the X.509 certificate will expire in $hourstoexpire hours $spareminutes minutes $spareseconds seconds"

                                exit 2

                        fi

                elif [[ ! -z $warn && ! -z $crit ]];then

                        if [[ $warn -gt $crit ]];then

                                if [[ $daysleft -ge $warn ]];then

                                        echo "OK: the X.509 certificate will expire in $daysleft days $hourstoexpire hours $spareminutes minutes $spareseconds seconds | days_left=$daysleft"

                                        exit 0

                                elif [[ $daysleft -lt $warn && $daysleft -gt $crit ]];then

                                        echo "WARNING: the X.509 certificate will expire in $daysleft days $hourstoexpire hours $spareminutes minutes $spareseconds seconds | days_left=$daysleft"

                                        exit 1

                                elif [[ $daysleft -lt $crit && $daysleft -gt 0 ]];then

                                        echo "CRITICAL: the X.509 certificate will expire in $daysleft days $hourstoexpire hours $spareminutes minutes $spareseconds seconds | days_left=$daysleft"

                                        exit 2

                                elif [[ $daysleft -eq 0 && $secondsdiff -gt 0 ]];then

                                        echo "CRITICAL: the X.509 certificate will expire in $hourstoexpire hours $spareminute minutes $spareseconds seconds | days_left=$daysleft"

                                        exit 2

                                fi

                        fi

                        else

                                echo "Usage: check_ssl_cert_exp <host> <port> [<warn left days> <crit left days>]"
                                echo "Warn threshold has to be greater then the Crit one"
                                exit 3
                        fi

                else

                        echo "Usage: check_ssl_cert_exp <host> <port> [<warn left days> <crit left days>]"
                        echo "Both thresholds have to be used"

                        exit 3
                fi
        else

                echo "CRITICAL: the X.509 certificate is expired"

                exit 2

        fi

else

        echo "Usage: check_ssl_cert_exp <host> <port> [<warn left days> <crit left days>]"
        echo "Please set the hostname and the port at least"

        exit 3
fi

Ho deciso di adoperare le funzioni in modo da suddividere logicamente le varie operazioni che vengono effettuate per il calcolo del tempo che intercorre alla data di scadenza del certificato.

I parametri da utilizzare sono 4 in tutto, di cui 2 mandatori (hostname/FQDN e porta) e 2 facoltativi (soglia di WARNING e soglia di CRITICAL).

Per prima cosa (tramite la funzione get_cert_datetime()) individuo la data di scadenza riportata sul certificato  (campo notAfter), utilizzando l’applicativo s_client della suite openssl. Successivamente effettuo un parsing dell’output, ricavando giorno, mese, anno, ora, minuto e secondo di scadenza, convertendo quindi tali informazioni in Unix epoch.

Successivamente, mediante la funzione get_time_diff(), calcolo la differenza (in termini di ore, minuti e secondi), tra l’ora attuale e quella di scadenza del certificato. Inoltre, utilizzando la variabile secondsdiff, nel caso in cui mi dovessi trovare proprio nel giorno di scadenza, riesco a capire se il certificato sta per scadere oppure è già scaduto.

A questo punto procedo con tutta una serie di confronti tra variabili e nella fattispecie verifico che la data attuale sia anteriore a quella di scadenza:

if [[ $datecheckepoch -gt $datenowepoch ]];then

Se è effettivamente questo il caso, controllo, rispettivamente, che le soglie di WARNING e di CRITICAL siano state definite e che siano logicamente coerenti (con WARNING > CRITICAL):

 elif [[ ! -z $warn && ! -z $crit ]];then                        
      if [[ $warn -gt $crit ]];then

Dopodichè faccio un confronto tra il giorno attuale e quello di scadenza, tenendo in considerazione le suddette soglie oppure i valori di default (10 e 3 nel caso in cui esse non siano state definite esplicitamente). Se mi trovo proprio nel giorno di scadenza verifico che la variabile secondsdiff sia un intero strettamente positivo, restituendo un errore di tipo CRITICAL ed il tempo mancante alla scadenza.

Ovviamente, anche nel caso in cui la data attuale sia successiva a quella di scadenza verrà restituito un errore di tipo CRITICAL segnalando che il certificato è già scaduto.

Configurazione di Nagios

Per prima cosa occorre definire il comando che fa uso del suddetto scrip (check_ssl_cert_exp), ovvero:

# 'check_ssl_exp' command definition
define command{
        command_name    check_ssl_exp
        command_line    $USER1$/check_ssl_cert_exp $HOSTADDRESS$ $ARG1$ $ARG2$ $ARG3$
        }

Successivamente possiamo creare il servizio che si occuperà di controllare la scadenza del certificato X.509:

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_descripion              SSL Certificate Expiration Date
        check_command                   check_ssl_exp!443!10!3
        notifications_enabled           0
        }

Infine riavviamo Nagios per rendere effettive le suddette modifiche:

[root@NMS ~]# service nagios reload

E’ tutto. Alla prossima.

NRPE_NT e Nagios: tenere sotto controllo gli aggiornamenti di Windows

Installare prontamente gli aggiornamenti di Windows, soprattutto se si ha a che fare con i security update, è sempre cosa buona e giusta. Spesso, però, capita che l’amministratore di sistema debba gestire N macchine e non abbia il tempo materiale di loggarsi su ciascuna di esse e constatare l’eventuale disposnibilità di aggiornamenti. Personalmente credo che non li si debba mai scaricare nè tantomeno installare automaticamente sulla macchina ospite, soprattutto se si ha a che fare con dei sistemi in produzione.

Cosa fare dunque per automatizzare tale task di verifica della disponibilità degli aggiornamenti? Semplice, utilizzare il nostro NMS preferito, ovvero Nagios.

nagiosIngredienti

Per prima cosa è necessario che sulla macchina da monitorare sia installato (ed attivo) il servizio NRPE_NT. Inoltre, ai plugin utilizzati dal servizio in questione, occorre aggiungere uno scrip PowerShell creato appositamente. Infine,  occorre creare su Nagios un comando ed un servizio specifico, in modo che il nostro NMS sia in grado di effettuare il controllo degli aggiornamenti in modo automatico e ad intervalli di tempo regolari.

Configurazione di NRPE_NT

Poichè la verifica della disponibilità degli aggiornamenti è un’operazione che può richiedere parecchio tempo, è necessario fare in modo che il timeout di NRPE_NT venga appositamente incrementato, editando la direttiva command_timeout presente all’interno del file nrpe.cfg (nel mio caso ho impostato una soglia pari a 600 secondi):

command_timeout= 600

Per ciò che concerne lo scrip PowerShell, esso può essere scaricato da qui, per poi posizionarlo all’interno della directory Plugins di NRPE_NT. A questo punto, sempre lato NRPE_NT, è possibile creare un comando specifico che si occuperà di verificare la disponibilità degli aggiornamenti di Windows. Tale definizione va inserita all’interno del file V2_nrpe_commands.cfg e presenta la seguente struttura:

command[get_windows_updates]=cscrip.exe //nologo //T:600 c:\nrpe\plugins\v2\check_windows_updates.wsf /w:0 /c:1

Restartiamo infine il servizio NRPE_NT mediante i comandi:

net stop NRPE_NT
net start NRPE_NT

e passiamo alla configurazione di Nagios.

Configurazione di Nagios

Come già affermato in precedenza, la configurazione dell’NMS si basa su due passaggi: la creazione del comando e l’assegnazione del check che ne fa uso ad un servizio legato all’host da monitorare.

Di seguito riporto il comando (da inserire nel file commands.cfg presente in /etc/nagios/objects):

# nagios-WMI-windows-updates check command definition

define command {
        command_name    check_WMI_windows_updates
        command_line    /usr/lib64/nagios/plugins/check_nrpe -H $HOSTADDRESS$ -t $ARG1$ -c get_windows_updates
        }

Mentre il servizio è così definito:

define service{
        use                             generic-service         ; Name of service template to use
        host_name                       Windows-Machine
        service_description             query WMI Updates for Microsoft Windows Machine
        check_command                   check_WMI_windows_updates!600
        normal_check_interval           120
        }

Da notare che l’unico parametro passato al comando riguarda il numero di secondi di attesa (600) prima del timeout. Inoltre, ho fatto in modo che i check vengano eseguiti a distanza di 2 ore l’uno dall’altro (normal_check_interval 120).

A configurazione ultimata riavviamo Nagios per rendere effettive le modifiche:

[root@NMS ~]# service nagios reload

In caso di disponibilità di aggiornamenti, il cruscotto dell’NMS ci apparirà in un modo simile al seguente:

cruscotto_nagios

Alla prossima.

CentOS 6: monitorare le ACL del nostro router Cisco mediante Nagios ed snmptt

Durante gli ultimi mesi ho discusso ampiamente della configurazione di Nagios per la ricezione dei check passivi, quali trap SNMP o security alert. Adesso vi mostrerò come integrare le predette tipologie di allarmi in modo da riuscire a monitorare le ACL del nostro router Cisco.

Premessa

Esiste un modo più veloce per ottenere il monitoraggio delle ACL rispetto a quello che sto per illustrare. Esso consiste, fondamentalmente, nella configurazione di un syslog server (dotato dell’applicativo swatch per l’analisi in tempo reale dei file di log) a cui il nostro router Cisco dovrà puntare. Nel caso in cui un determinato pattern (ad esempio / denied /) dovesse essere matchato da swatch, quest’ultimo genererà un’opportuna notifica email da inoltrare all’amministratore di rete.

La mia configurazione, invece, si basa sulla logica seguente: il router Cisco genererà delle opportune trap SNMP segnalando ciò che avviene a livello di ACL (traffico consentito oppure negato). Esse verranno intercettate da snmptrapd e tradotte da snmptt, per poi essere elaborate dall’event handler submit_check_result e date in pasto a Nagios. Ho optato per tale configurazione poichè sulla mia linux box che funge da syslog server e da NMS sono già attivi sia snmptrapd che snmptt e quindi ho ritenuto conveniente sfruttarli piuttosto che mettere in funzione swatch.

nagiosConfigurazione del router Cisco

La configurazione del router Cisco si basa in 3 passaggi: settaggio della direttiva log per ciascuna entry che andrà a formare l’ACL da monitorare,  settaggio del syslog server a cui inviare le trap ed abilitazione di queste ultime.

Ad esempio, l’ACL di nostro interesse dovrà essere formata da entry di questo tipo:

access-list 102 deny ip host 255.255.255.255 any log

Inoltre, per definire la community string RO (read only) e l’indirizzo IP del server che si occuperà della ricezione delle trap, occorrerà digitare le seguenti direttive:

snmp-server host 192.168.1.1 keypublic
snmp-server community keypublic RO

mentre le trap potranno essere abilitate nel modo seguente:

snmp-server enable traps snmp authentication linkdown linkup coldstart warmstart
snmp-server enable traps tty
snmp-server enable traps config-copy
snmp-server enable traps config
snmp-server enable traps resource-policy
snmp-server enable traps cpu threshold
snmp-server enable traps syslog
snmp-server enable traps firewall serverstatus

 Contenuto dello scrip submit_check_result

Secondo quanto già riportato in questo post, sappiamo che snmptt effettua una traduzione “statica” delle trap (mediante il comando snmpttconvertmib). Per tale motivo, affinchè si possa indurre Nagios a generare dei security alert solo dopo la ricezione di trap ben determinate, occorre modificare il codice sorgente relativo all’event handler submit_check_result. Di seguito riporto il contenuto dello scrip in questione da me customizzato:

 echocmd="/bin/echo"

CommandFile="/var/spool/nagios/cmd/nagios.cmd"

# get the current date/time in seconds since UNIX epoch
datetime=`date +%s`

# create the command line to add to the command file
if [[ $1 == "ip router" ]];then

        if [[ $4 =~ "denied igmp" ]];then

                exit 0;

        elif  [[ $4 =~ "denied" ]];then

                service="Router ACL Connection Denied";

                output="$4 | connection_denied=1"
                cmdline="[$datetime] PROCESS_SERVICE_CHECK_RESULT;router;$service;$3;$output";

        else

                cmdline="[$datetime] PROCESS_SERVICE_CHECK_RESULT;router;$2;$3;$4";

        fi

else

   cmdline="[$datetime] PROCESS_SERVICE_CHECK_RESULT;$1;$2;$3;$4";

fi

# append the command to the end of the command file
`$echocmd $cmdline >> $CommandFile`

Nella fattispecie, vengono dapprima identificate le trap che riguardano il router. Successivamente, nel caso in cui esse contengano il pattern igmp denied, lo scrip uscirà senza effettuare alcuna operazione. Tale “scrematura” è stata necessaria poichè il mio ISP effettua regolarmente del polling IGMP mediante il proprio querier 192.168.100.1 (per il servizio IPTV).

Nel caso in cui, invece, le trap dovessero contenere la stringa denied, la variabile cmdline verrà popolata con l’host name dell’oggetto monitorato da Nagios (per il quale si dovrà aggiornare lo stato del servizio che si occupa di tenere d’occhio le ACL). Nel mio caso tale host name è semplicemente router. Inoltre, l’output  verrà rimaneggiato in modo da tenere traccia delle performance data (graficizzandole mediante l’uso di pnp4nagios).

MIB da utilizzare e configurazione di Nagios

Per prima cosa occorre scaricare le MIB CISCO-SYSLOG-MIB e CISCO-SYSLOG-MIB-V1SMI dal repository FTP della Cisco, effettuandone il parsing mediante snmpttconvertmib.

Successivamente, su Nagios occorrerà definire per l’host name router il servizio che si occuperà di monitorare le ACL:

define service{
        use                             local-service
        host_name                       router
        service_descripion              Router ACL Connection Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

Come ultimo step, a configurazione ultimata possiamo riavviare Nagios per rendere effettive le suddette modifiche:

[root@NMS ~]# service nagios reload

ed abbiamo finito.

A presto.

NRPE_NT: script powershell per la modifica della direttiva allowed_hosts in nrpe.cfg

Scenario

Sistema di monitoraggio (Nagios) connesso ad Internet mediante indirizzo IP pubblico di tipo dinamico. Esso deve tenere sotto controllo, tramite opportune query NRPE, alcuni servizi attivi su di un server remoto (Windows 2008 R2), raggiungibile mediante FQDN ed IP statico.

powershellProblema

Per evitare che eventuali client non autorizzati possanno connettersi al servizio NRPE_NT in ascolto sul server remoto (porta 5666/TCP), è possibile definire, all’interno del suo file di configurazione (nrpe.cfg), gli indirizzi IP a cui è consentito eseguire le query. Ad esempio, mediante la direttiva allowed_hosts, siamo in grado di dichiarare la seguente regola:

allowed_hosts=79.37.83.59

ed ecco, per l’appunto, dov’è il problema: essendo il suddetto indirizzo definito in modo statico, nel momento in cui, per un motivo o per un altro, Nagios dovesse cambiare il proprio IP pubblico, le query NRPE fallirebbero miseramente (check timeout).

Soluzione

A questo punto è necessario fare una premessa: esiste una soluzione più pulita di quella che sto per riportare, che consiste, fondamentalmente, nell’uso di NSClient++ abbinato ad NRPE_NT, grazie ai quali è possibile realizzare un meccanismo di autenticazione client/server mediante lo scambio di certificati X.509 (in tal caso la direttiva allowed_host sarebbe del tutto superflua poichè autenticazione e confidenzialità verrebbero garantite mediante i suddetti certificati).

Per ciò che concerne, invece, la soluzione da me individuata, essa consiste nella realizzazione di uno scrip powershell che “interroga” l’FQDN di Nagios ogni 5 minuti, verificando che il suo indirizzo IP pubblico sia diverso da quello presente nel file di configurazione di NRPE. In tal caso lo scrip modificherà l’IP definito nella direttiva allowed_hosts.

Di seguito riporto il contenuto dello scrip:

$IP = nslookup nagios.vostrodominio.com | Select-String -Pattern '\d{1,3}(\.\d{1,3}){3}' | Select-String -notmatch 'IP del server da monitorare'

$PublicIP = $IP.tostring().Split(" ")[-1]

$OldIP = (Get-Content C:\nrpe\bin\nrpe.cfg) | Select-String 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}'

$OldPublicIP = $OldIP.tostring().Split("=")[-1]

$data = Get-Date;

if ($PublicIP -ne $OldPublicIP -and $PublicIP)
{

    (Get-Content C:\nrpe\bin\nrpe.cfg) -replace 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}', "allowed_hosts=$(echo $PublicIP)" | Set-Content C:\nrpe\bin\nrpe.cfg

    net stop nrpe_nt

    Start-Sleep -s 5

    net start nrpe_nt

    echo "$data NRPE_NT configuration has been updated. The new authorized Public IP is $PublicIP"

    exit 0;
}
else
{
    echo "$data Nothing to do. Exiting..."

    exit 0;
}

Per prima cosa ho individuato l’indirizzo IP pubblico di Nagios mediante una query di tipo A effettuata mediante nslookup:

$IP = nslookup nagios.vostrodominio.com | Select-String -Pattern '\d{1,3}(\.\d{1,3}){3}' | Select-String -notmatch 'IP del server da monitorare'

$PublicIP = $IP.tostring().Split(" ")[-1]

Ovviamente ho dovuto formattare l’output relativo alla suddetta query, identificando, tramite espressione regolare, le stringhe che riportano gli indirizzi IP coinvolti, escludendo successivamente quella che contiene l’IP del server da monitorare. Inoltre, è stato necessario salvare (dopo opportuna conversione) l’indirizzo IP di Nagios all’interno della variabile $PublicIP.

Discorso molto simile riguarda l’individuazione dell’IP configurato all’interno di nrpe.cfg, ottenuta mediante l’applet Get-Content:

$OldIP = (Get-Content C:\nrpe\bin\nrpe.cfg) | Select-String 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}'

$OldPublicIP = $OldIP.tostring().Split("=")[-1]

A questo punto è stato possibile procedere con il confronto tra l’IP attuale di Nagios e quello presente nel file di configurazione di NRPE_NT. Nel caso in cui questi differiscano (e la variabile $PublicIP non sia nè vuota, nè nulla), la direttiva allowed_hosts verrà modificata, con il conseguente riavvio del servizio in oggetto:

(Get-Content C:\nrpe\bin\nrpe.cfg) -replace 'allowed_hosts=\d{1,3}(\.\d{1,3}){3}', "allowed_hosts=$(echo $PublicIP)" | Set-Content C:\nrpe\bin\nrpe.cfg

    net stop nrpe_nt

    Start-Sleep -s 5

    net start nrpe_nt

    echo "$data NRPE_NT configuration has been updated. The new authorized Public IP is $PublicIP"

Infine, per eseguire tale scrip in modo automatico, ho creato un task mediante l’applicativo Task Scheduler di Windows, il quale si ripete giornalmente ogni 5 minuti e la cui azione è la seguente:

powershell -command "C:\Users\Administrator\Documents\scrip\nrpe_ip_update.ps1 >> C:\nrpe_ip_update.log"

Da ora in poi le query NRPE da indirizzo IP dinamico non saranno un problema.

A presto.

CentOS 6: Riavviare automaticamente il servizio barnyard2 mediante Nagios e gli event handlers

In questo post ho mostrato il codice sorgente del demone barnyard2 da me customizzato. Esso, in soldoni, non fa altro che monitorare il contenuto del file alert generato da snort, in modo da poter individuare gli allarmi creati dall’IDS in questione, inserendoli (dopo un’opportuna formattazione) all’interno di uno specifico DBMS (nel nostro caso MySQL).

Purtroppo, però, tale servizio tende a crashare in modo randomico, ragion per cui ho deciso di creare un event handler (per Nagios) in grado di riavviarlo automaticamente.

nagios

Configurazione del SO che ospita L’NMS (Nagios)

Poichè l’operazione di riavvio del demone barnyard2 richiede i privilegi di root, è stato necessario fare in modo che l’utente nagios (che esegue gli event handlers) fosse abilitato all’interno del file /etc/sudoers:

nagios   ALL=NOPASSWD: /sbin/service barnyard2 restart

In particolare, ho fatto in modo che l’esecuzione del comando sudo non richiedesse la password (ALL=NOPASSWD:) solo per il comando /sbin/service barnyard2 restart (per la serie less is more). Inoltre, sempre all’interno del suddetto file, ho inserito, subito dopo la direttiva Defaults    requiretty, la stringa:

Defaults:nagios        !requiretty

in modo tale da consentire all’utente nagios di lanciare il comando sudo anche quando non è in possesso di un terminale (tty). Ciò è necessario poichè tutti gli event handlers vengono lanciati dal nostro NMS in assenza di sessione tty.

Un’altra modifica altrettanto importante ha riguardato SElinux. Esso, infatti, essendo attivo in modalità Enforcing, vietava puntualmente l’esecuzione dell’event handler in questione. Per “aggirare” tale divieto, ho dovuto modificare alcune regole MAC (Mandatory Access Control), attraverso 2 passaggi: il settaggio di una variabile booleana e la creazione di un modulo custom per SElinux.

Nel primo caso è stato sufficiente lanciare il comando:

[root@NMS]# setsebool -P nagios_run_sudo 1

mentre nel secondo caso ho dapprima creato il file permitnagioseventhandlers.te, di cui riporto il contenuto:

module permitnagioseventhandler 1.0;

require {
        type nagios_system_plugin_t;
        type nagios_unconfined_plugin_exec_t;
        type nagios_eventhandler_plugin_t;
        type httpd_t;
        class file { getattr };
        class dir { getattr search };
}

#============= nagios_system_plugin_t ==============
allow nagios_system_plugin_t nagios_unconfined_plugin_exec_t:file {getattr};

#============= httpd_t ==============
allow httpd_t nagios_eventhandler_plugin_t:dir { getattr search };

per poi verificarne la sintassi:

[root@NMS]#  checkmodule -M -m -o permitnagioseventhandler.mod permitnagioseventhandler.te

compliarlo:

[root@NMS]# semodule_package -o permitnagioseventhandler.pp -m permitnagioseventhandler.mod

ed installarlo:

[root@NMS]# semodule -i permitnagioseventhandler.pp

Configurazione di Nagios

Il riavvio del demone barnyard2 richiede parecchio tempo (soprattutto se esso è stato associato a più interfacce di rete, come nel mio caso). Per questo motivo si è reso necessario modificare il paramentro event_handler_timeout presente all’interno del file di configurazione Nagios (/etc/nagios/nagios.cfg), portandolo da 30 secondi (valore di default) a 300 secondi:

event_handler_timeout=400

Per ciò che concerne il servizio (relativo al nostro NMS) che si occupa del monitoraggio di barnyard2, è stata creata la seguente configurazione:

define service{
        use                             local-service         ; Name of service template to use
        host_name                       localhost
        service_descripion             Barnyard2 Service Status
        check_command                   check_local_process_status_all!2!2!barnyard2
        event_handler                   restart_barnyard
        }

dove il comando check_local_process_status_all è così definito:

# 'check_local_process_status_all' command definition
define command{
        command_name    check_local_process_status_all
        command_line    $USER1$/check_procs -c $ARG1$:$ARG2$ -C $ARG3$
        }

Nella fattispecie, le variabili $ARG1$ e $ARG2$ rappresentano, rispettivamente, il numero minimo e massimo di processi (recanti la stringa barnyard2, specificata mediante la variabile $ARG3$) attivi sulla macchina da monitorare.

Inoltre, è stato definito il comando restart_barnyard, il cui scopo è quello di eseguire l’event handler in questione:

# 'restart_barnyard' command definition
define command {
        command_name      restart_barnyard
        command_line      /usr/lib64/nagios/plugins/eventhandlers/restart_barnyard $SERVICESTATE$ $SERVICESTATETYPE$ $SERVICEATTEMPT$
}

Ho quindi riavviato Nagios per rendere effettive le suddette modifiche:

[root@NMS]# service nagios reload

Contenuto dell’event handler (restart_barnyard)

Una volta completata la fase preliminare relativa alla configurazione del SO e dell’NMS, mi sono dedicato alla creazione dell’event handler vero e proprio (che ho chiamato, molto semplicemente, restart_barnyard). Esso presenta il seguente contenuto:

#!/bin/bash

case "$1" in
OK)
        ;;
WARNING)
        ;;
UNKNOWN)
        ;;
CRITICAL)
       case "$2" in
                SOFT)
                        case "$3" in
                        3)
                                echo -n "Restarting barnyard2 service (3rd soft critical state)..."
                                /usr/bin/sudo /sbin/service barnyard2 restart
                                ;;
                                esac
                        ;;
                HARD)
                        echo -n "Restarting barnyard2 service..."
                        /usr/bin/sudo /sbin/service barnyard2 restart
                        ;;
                esac
                ;;
        esac

exit 0

ovvero non fa altro che riavviare il servizio in oggetto nel caso del terzo critical state (soft) o del quarto critical state (hard).

L’ho quindi reso eseguibile:

[root@NMS]# chmod +x restart_barnyard

e l’ho salvato all’interno della dir /usr/lib64/nagios/plugins/eventhandlers:

[root@NMS]# mv restart_barnyard /usr/lib64/nagios/plugins/eventhandlers

Test di funzionamento

Infine, ho testato il tutto semplicemente arrestando il servizio barnyard2:

[root@NMS]# service barnyard2 stop

verificando che Nagios svolgesse tutta la trafila per ritirarlo su in modo automatico:

[root@NMS]# tail -f /var/log/nagios/nagios.log

il cui output mi ha mostrato le diverse fasi di passaggio dallo stato CRITICAL allo stato OK:

[1448964811] SERVICE EVENT HANDLER: localhost;Barnyard2 Service Status;CRITICAL;SOFT;3;restart_barnyard
[1448965026] SERVICE ALERT: localhost;Barnyard2 Service Status;CRITICAL;HARD;4;PROCS CRITICAL: 0 processes with command name 'barnyard2'
[1448965026] SERVICE EVENT HANDLER: localhost;Barnyard2 Service Status;CRITICAL;HARD;4;restart_barnyard
[1448965313] SERVICE ALERT: localhost;Barnyard2 Service Status;OK;HARD;4;PROCS OK: 2 processes with command name 'barnyard2'
[1448965313] SERVICE EVENT HANDLER: localhost;Barnyard2 Service Status;OK;HARD;4;restart_barnyard

Inoltre, digitando il comando:

[root@NMS]# ps aux | grep barn

ho visualizzato i processi di barnyard2 durante il loro avvio da parte dell’event handler:

nagios    2799  0.0  0.0 108208  1352 ?        S    11:17   0:00 /bin/bash /usr/lib64/nagios/plugins/eventhandlers/restart_barnyard CRITICAL HARD 4
root      2800  0.1  0.1 189744  3392 ?        S    11:17   0:00 /usr/bin/sudo /sbin/service barnyard2 restart
root      2803  0.0  0.0 106460  1680 ?        S    11:17   0:00 /bin/sh /sbin/service barnyard2 restart
root      2809  0.0  0.0 108568  1868 ?        S    11:17   0:00 /bin/sh /etc/init.d/barnyard2 restart
root      3194 65.8  1.2  92668 40796 ?        Rs   11:18   1:06 barnyard2 -D -c /etc/snort/barnyard2eth0.conf -d /var/log/snort/eth0 -w /var/log/snort/eth0/barnyard2.waldo -l /var/log/snort/eth0 -a /var/log/snort/eth0/archive -f snort.log --pid-path /var/run
root      3196  0.0  0.0 108200  1284 ?        S    11:18   0:00 /bin/bash -c ulimit -S -c 0 >/dev/null 2>&1 ; barnyard2 -D -c /etc/snort/barnyard2eth1.conf -d /var/log/snort/eth1 -w /var/log/snort/eth1/barnyard2.waldo -l /var/log/snort/eth1 -a /var/log/snort/eth1/archive -f snort.log --pid-path /var/run
root      3197 61.4  0.2  58856  7808 ?        R    11:18   1:01 barnyard2 -D -c /etc/snort/barnyard2eth1.conf -d /var/log/snort/eth1 -w /var/log/snort/eth1/barnyard2.waldo -l /var/log/snort/eth1 -a /var/log/snort/eth1/archive -f snort.log --pid-path /var/run
root      3710  0.0  0.0 103268   864 pts/2    S+   11:20   0:00 grep barn

E’ tutto. Alla prossima.

CentOS 6: configurare Nagios per la ricezione delle trap SNMP

In questo post abbiamo visto come configurare Nagios per la ricezione dei check passivi. In quest’altro post, invece, ho spiegato come configurare snmptrapd per la ricezione delle trap SNMP provenienti dai dispositivi monitorati. Adesso vedremo come ricevere su Nagios le suddette trap.

Ingredienti

Oltre a Nagios ed al demone che si occupa della ricezione delle trap (ovvero snmptrapd), è necessario installare sulla macchina che funge da NMS un demone in grado di tradurre le informazioni ricevute in qualcosa di più umanemente comprensibile. Infatti, la difficile interpretazione dei dati riportati dalle trap SNMP rappresenta, sicuramente, uno dei maggiori ostacoli che un sysadmin deve affrontare. Il demone che svolge tale mansione prende il nome di snmptt.

Logica di funzionamento

A grandi linee, il giro del fumo si può riassumere come segue: il dispositivo monitorato genera, di sua sponte, una trap SNMP per segnalare un qualche tipo di anomalia. Essa verrà, successivamente, inoltrata all’NMS, sul quale è attivo il demone snmptrapd (in ascolto sulla porta UDP/162), il quale si occuperà di “passare” tali informazioni ad snmptt. A questo punto, snmptt “tradurrà” i dati che gli sono stati inviati, provvedendo anche inoltrare il relativo output ad uno scrip Nagios (submit_check_result, che potete scaricare da qui) in grado di carpirne il contenuto ed utilizzare quest’ultimo per aggiornare lo stato del servizio dotato di check passivo. Quanto detto fin’ora è riportato (in modo schematico) nell’immagine sottostante.

snmptt

Configurazione di Nagios

Come al solito, il primo step per la realizzazione del nostro ambiente, consiste nella configurazione dell’NMS. Il servizio di monitoraggio delle trap potrà essere simile al seguente:

 define service{
        use                   local-service
        host_name             localhost
        service_descripion   SNMP TRAP Interceptor
        check_command         check_passive
        passive_checks_enabled  1
        active_checks_enabled   0
        is_volatile             1
        check_freshness         1
        freshness_threshold     600
        flap_detection_enabled  0
        }

mentre il comando check_passive presenterà la seguente struttura:

# 'check_passive' command definition
define command{
        command_name check_passive
        command_line $USER1$/check_dummy 2 "No alerts received in 600 seconds"
}

Configurazione di snmptrapd

Rispetto alla configurazione vista qui, l’unica variazione consiste nell’aggiunta delle seguente direttiva:

traphandle default /usr/sbin/snmptt

e la configurazione in todo dovrà essere simile alla seguente:

traphandle default /usr/sbin/snmptt

authCommunity log,execute,net keypublic
format1 %l-%m-%y %h:%j:%k from %A: %b %P %N %W %v\n
format2 %l-%m-%y %h:%j:%k from %A: %b %P %N %W %v\n

Installazione e configurazione di snmptt

Per installare il software in questione è sufficiente utilizzare yum:

[root@NMS ~]# yum install snmptt net-snmp-perl

Una volta installato, si può procedere con la sua configurazione mediante l’editing del file /etc/snmp/snmptt.ini. Ecco le modifiche da me apportate:

net_snmp_perl_enable = 1
log_system_enable = 1
log_system_file = /var/log/snmptt/snmpttsystem.log

A questo punto occorrerà procedere con la “traduzione” delle MIB SNMP. Le si può pensare come una sorta di DB testuale, in cui è presente una descrizione “human friendly” di alcuni OID, anche per ciò che concerne le trap.

Il software che svolge tale mansione prende il nome di snmpttconvertmib e si potranno convertire trap presenti nelle MIB lanciando il seguente comando:

[root@NMS ~]# for i in *MIB*;do snmpttconvertmib --in=/usr/share/snmp/mibs/$i --out=/etc/snmp/snmptt.conf  --exec='/usr/lib64/nagios/plugins/eventhandlers/submit_check_result $r "SNMP TRAP Interceptor" 1';done

dove i parametri passati a submit_check_result sono:

1) $r, ovvero l’hostname del dispositivo che ha generato la trap;

2) SNMP TRAP Interceptor, ovvero il nome del servizio di Nagios che deve essere aggiornato mediante check passivo;

3) 1, evvero l’exit code da girare all’NMS (che, in tal caso, corrisponderà a WARNING).

Le trap “tradotte” andranno a popolare il file /etc/snmp/snmptt.conf, le cui entry saranno simili alle seguenti:

EVENT ucdShutdown .1.3.6.1.4.1.2021.251.2 "Status Events" Normal
FORMAT This trap is sent when the agent terminates $*
EXEC /usr/lib64/nagios/plugins/eventhandlers/submit_check_result $r TRAP 1 "This trap is sent when the agent terminates $*"
SDESC
This trap is sent when the agent terminates
Variables:
EDESC

Prima di continuare, una piccola nota a margine: per ciò che concerne i dispositivi Cisco, vi consiglio di consultare questo sito (per l’indentificazione ed il download delle MIB) e quest’altro (per la traduzione degli OID).

Inoltre, affinchè lo scrip submit_check_result sia in grado di scrivere all’interno del file nagios.cmd (dove vengono inoltrati tutti i comandi esterni), è necessario sostituire la stringa:

CommandFile="/usr/local/nagios/var/rw/nagios.cmd"

con:

CommandFile="/var/spool/nagios/cmd/nagios.cmd"

A configurazione di snmptt ultimata, possiamo fare in modo che il demone in questione venga eseguito automaticamente al boot:

[root@NMS ~]# chkconfig snmptt on

ed avviarlo:

[root@NMS ~]# service snmptt start

Inoltre, riavviamo snmptrapd per rendere effettive le modifiche apportate in precedenza:

[root@NMS ~]# service snmptrapd restart

e ricarichiamo la configurazione di Nagios:

[root@NMS ~]# service nagios reload

 Test e troubleshooting

La prima cosa da fare per capire se snmptt stia funzionando correttamente consiste nell’abilitazione delle opzioni di debug (presenti all’interno di snmptt.ini). Le direttive coinvolte sono le seguenti:

DEBUGGING = 0
DEBUGGING_FILE = /var/log/snmptt/snmptt.debug

Inoltre, è possibile (e opportuno) inviare al nostro handler una trap di test, recante il seguente formato:

[root@NMS ~]# snmptrap -v 1 -c keypublic 127.0.0.1 '.1.3.6.1.6.3.1.1.5.3' '0.0.0.0' 6 33 '55' .1.3.6.1.6.3.1.1.5.3 s “teststring000”

Se la suddetta trap verrà opportunamente gestita da snmptt e dell’event handler di Nagios (submit_check_result), con il successivo aggiornamento del servizio lato NMS, vorrà dire che il nostro sistema sta funzionando come dovrebbe.

Per ora è tutto. Alla prossima.

CentOS 6: configurare Nagios per la ricezione dei security alert

In questo post abbiamo visto come configurare e gestire i check passivi su Nagios. Ora vedremo come utilizzare tale configurazione per ricevere i security alert relativi agli host monitorati.

nagiosIngredienti

Ovviamente il primo ingrediente è l‘NMS (Nagios), integrato ad NRDP Server. Sulle macchine monitorate è installato NRDP Client, il quale dovrà interagire con un log analyzer in tempo reale (swatch).

Scenario

La topologia utilizzata nell’ambito di questa guida è abbastanza minimale e prevede un server su cui è installato Nagios ed un altro server (da monitorare) che funge da antispam. Si vuole fare in modo che i security alert generati da quest’ultimo vengano inoltrati all’NMS, il quale dovrà successivamente aggiornare lo stato dei check passivi di riferimento, inviando opportune notifiche ai sysadmin.

Configurazione di Nagios

La configurazione dell’NMS è del tutto simile a quella vista qui, ma la riporto per completezza:

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Access Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Domain Not Found
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Cannot Find Your Reverse Hostname
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam SPF Reject
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Relay Access Denied
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Amavis Blocked
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Spam
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

define service{
        use                             local-service
        host_name                       server-antispam
        service_description             Antispam Spammy
        check_command                   check_passive
        passive_checks_enabled          1
        active_checks_enabled           0
        max_check_attempts              1
        is_volatile                     1
        check_freshness                 1
        freshness_threshold             600
        flap_detection_enabled          0
        }

Il comando check_passive, invece, è così definito:

# 'check_passive' command definition
define command{
        command_name check_passive
        command_line $USER1$/check_dummy 0 "No Security Alert"
}

La logica di funzionamento è banale: se un security alert non viene ricevuto entro 600 secondi significa che non vi sono eventi rilevanti e, di conseguenza, lo stato del check passivo tornerà ad essere OK. Inoltre, poichè l’alert deve generare immediatamente una notifica (HARD STATE), è necessario settare il campo max_check_attempts a 1 (anzichè 4 che è il valore di default).

Come ultimo step ricarichiamo la configurazione di Nagios:

[root@NMS ~]# service nagios reload

Configurazione del server antispam

Una volta configurato l’NMS possiamo dedicarci alla configurazione del server da monitorare. In questo caso il lavoro sporco verrà svolto da swatch, il cui compito è quello di analizzare in tempo reale (tail -f) il contenuto del file di log relativo al servizio di antispam (/var/log/maillog), alla ricerca di determinati error code. Ad ogni error code corrisponderà un security alert specifico, e, una volta identificato, verrà richiamato NRDP Client per l’invio dell’evento a Nagios.

Ma bando alle ciance ed ecco la configurazione di swatch:

#SMTP Domain not found
watchfor  /Domain not found/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Domain Not Found' --output\='$_'"

#SMTP Sender address rejected
watchfor  /Access denied/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Access Denied' --output\='$_'"

#SMTP Cannot find your reverse hostname
watchfor  /cannot find your reverse hostname/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Cannot Find Your Reverse Hostname' --output\='$_'"

#SMTP SPF reject
watchfor  /openspf/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam SPF Reject' --output\='$_'"

#SMTP Relay access denied/
watchfor /Relay access denied/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Relay Access Denied' --output\='$_'"

#SMTP Amavis blocked
watchfor /Blocked/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Amavis Blocked' --output\='$_'"

#SMTP Spam
watchfor /SPAM/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Spam' --output\='$_'"

watchfor /SPAMMY/
     echo
     exec "/usr/bin/php /usr/lib/nagios/plugins/send_nrdp.php --url\=http://IPNMS/nrdp --token\=vostrotoken --host\=server-antispam --state\=1 --service\='Antispam Spammy' --output\='$_'"

Nella fattispecie, NRDP Client viene richiamato mediante la direttiva exec, facendo attenzione al carattere = (utilizzato per specificare i dati da inviare a Nagios), poichè trattasi di un carattere speciale per swatch (che quindi dovrà essere munito di escape \).

A questo punto lanciamo il comando:

[root@server-antispam ~]# swatch -c /etc/swatch.conf -t /var/log/maillog --daemon

ed inseriamolo all’interno del file /etc/rc.local (per automatizzare l’esecuzione del suddetto applicativo dopo ogni riavvio).

Test

Per testare il corretto funzionamento della configurazione appena riportata, possiamo, ad esempio, generare un error code 450 (cannot find your reverse hostname).
Lanciamo dunque il comando:

[root@client ~]# telnet server-antispam.vostrodominio.com 25

ed inviamo al server antispam le seguenti direttive:

helo server-antispam.vostrodominio.com
250 server-antispam
mail from:<n.latella@ciao.it>
250 2.1.0 Ok
rcpt to:<n.latella@ciao.ot>
450 4.7.1 Client host rejected: cannot find your reverse hostname, [5.170.*.*]

A questo punto il servizio Antispam Cannot Find Your Reverse Hostname dovrebbe generare un WARNING, segnalando quanto avvenuto mediante email.

Nei prossimi post vedremo come configurare Nagios per la ricezione delle trap SNMP.

Alla prossima.

CentOS 6: configurare Nagios/NRDP per la ricezione dei check passivi

In questo blog ho ampiamente discusso del mio MNS preferito (Nagios), mostrandone le diverse modalità di utilizzo e pubblicando, con una certa frequenza, alcuni plugin (da me realizzati) in grado di tenere sotto controllo un determinato servizio attivo su uno o più dispositivi.

Occorre precisare, però, che fin’ora ho discusso solo ed esclusivamente dei cosiddetti check attivi, ovvero quelli che vengono inizializzati dall’NMS ad intervalli di tempo specifici (di default ogni 5 minuti). Tale configurazione è più che sufficiente nella stragrande maggioranza dei casi, ma ovviamente esistono delle ecezioni.

nagiosUna di queste riguarda, ad esempio, la presenza di un firewall tra Nagios ed il server da tenere sotto controllo, il quale potrebbe bloccare i tentativi di connessione diretti verso quest’ultimo. Un’altra, invece, potrebbe riguardare l’individuazione di eventi totalmente asincroni (ad esempio le trap SNMP oppure i security alert), i quali, per loro natura, non possono essere collezionati mediante del semplice polling.

Per configurare in modo corretto i check passivi, occorre utilizzare alcuni elementi indispensabili:

1) Un tool da integrare a Nagios (NRDP Server) in grado di riconoscere gli eventi generati dai dispositivi monitorati e di girarli all’NMS;

2) Un client (NRDP Client per i sistemi *nix oppure NSCA Client per i sistemi Windows), il cui compito è quello di inviare gli eventi all’NMS.

Logica di funzionamento

NRDP Server è una Web applicaiton sviluppata in PHP, contattabile utilizzando il protocollo HTTP (o, in alternativa, HTTPS). Essa rimane in ascolto su una specifica porta (solitamente la TCP 80, ma dipende dalla configurazione dei Web server), in attesa degli eventi generati dai client NRDP. Nella fattispecie, anche in quest’ultimo caso, parliamo di uno scrip PHP il cui scopo è quello di generare un codice XML (in base ai parametri che gli vengono dati in pasto), da inoltrare al server. A questo punto, dopo aver ricevuto l’evento, il server NRDP popolerà il file nagios.cmd con una stringa che reca il seguente formato:

PROCESS_SERVICE_CHECK_RESULT;host;servicedescription;checkresult;output

ad esempio:

PROCESS_SERVICE_CHECK_RESULT;mysql-server1;test;1;questo è un evento di test

In seguitò verrà generato un file temporaneo all’interno della directory /var/log/nagios/spool/checkresults, il quale verrà poi processato da Nagios per l’aggiornamento dello status del servizio interessato.

Installazione e configurazione di NRDP Server

Per prima cosa scarichiamo il suddetto applicativo e scompattiamo l’archivio:

[root@linuxbox ~]# cd /usr/local

[root@linuxbox ~]# wget https://assets.nagios.com/downloads/nrdp/nrdp.zip

[root@linuxbox local]# unzip nrdp.zip

[root@linuxbox local]# chown -R nagios:nagios /usr/local/nrdp

Creiamo quindi la directory in cui Nagios dovrà salvare i file temporanei (/var/log/nagios/spool/tmp):

[root@linuxbox local]# mkdir /var/log/nagios/spool/tmp

[root@linuxbox local]# chown apache:nagios /var/log/nagios/spool/tmp

[root@linuxbox local]# chmod 770 /var/log/nagios/spool/tmp

Inoltre, poichè NRDP Server gira grazie ad un Web server opportuno (ad esempio Apache), è necessario fare in modo che nella directory /var/log/nagios/spool/checkresults/ (in cui Nagios salverà i risultati dei check attivi e passivi utilizzando dei file temporanei), Apache abbia i diritti di lettura e scrittura:

[root@linuxbox local]# chown apache:nagios /var/log/nagios/spool/checkresults

[root@linuxbox local]# chmod 770 /var/log/nagios/spool/checkresults

A questo punto possiamo dedicarci alla configurazione vera e propria di NRDP Server, editando il file /usr/local/nrdp/server/config.inc.php.

Di seguito riporto quella da me utilizzata:

$cfg['authorized_tokens'] = array(
"vostrotoken",
);
$cfg["nagios_command_group"]="nagios";
// full path to Nagios external command file
$cfg["command_file"]="/var/spool/nagios/cmd/nagios.cmd";
// full path to check results spool directory
$cfg["check_results_dir"]="/var/log/nagios/spool/checkresults";
// full path to directory where temp scratch files can be written
// NOTE: the Apache user need to be able create files here, and the Nagios user needs to read/delete those same files, so the /tmp system directory won't work (it has a sticky bit on it)
$cfg["tmp_dir"]="var/log/nagios/spool/tmp";

Passiamo ora alla configurazione di Apache, creando un file opportuno (nrdp.conf) all’interno della directory /etc/httpd/conf.d, il cui contenuto dovrebbe essere simile al seguente:

Alias /nrdp "/usr/local/nrdp/server"

<Directory "/usr/local/nrdp">
   Options None
   AllowOverride None
   Order allow,deny
   Allow from all
   Order deny,allow
   Deny from all
   Allow from <IP1>
   Allow from <IP2>
   Allow from <IP3>
</Directory>

Come si può notare, ho consentito l’accesso alla suddetta pagina Web solo a determinati indirizzi IP (quelli di management e quelli dei server che devono inviare i check a Nagios/NRDP).

Ricarichiamo la configurazione di Apache per rendere effettive le suddette modifiche:

[root@linuxbox local]# service httpd reload

e finalmente NRDP Server dovrebbe essere attivo e funzionante. Per esserne sicuri al 100% conviene contattare la seguente URL:

http://IPNAGIOS/nrdp

e popolare il campo Token: con quello da noi inserito nella configurazione del server (config.inc.php), lasciando il campo Check Data: inalterato. Se entrambi i check vegnono processati correttamente da NRDP Server significa che il suddetto applicativo sta funzionando come dovrebbe.

Un consiglio: verificate che anche l’invio dei comandi via NRDP Server vada a buon fine (attraverso la sezione Submit Nagios Command:), in modo da scongiurare eventuali blocchi perpetrati da SElinux.

Installazione e configurazione di NRDP Client

Il primo step per mettere in funzione il suddetto client consiste nel copiarlo sui server da monitorare:

[root@linuxbox ~]# scp /usr/local/nrdp/client/send_nrdp.php root@serverdamonitorare:/usr/lib64/nagios/plugins

Una volta fatto ciò si può procedere con l’invio di un check di prova, utilizzando, ad esempio, la seguente sintassi:

[root@linuxbox ~]# /usr/bin/php send_nrdp.php --url=http://IPNAGIOS/nrdp --token="vostrotoken" --host="mysql-server" --state="1" --service="Test" --output="Questo è un evento di test"

Per una maggiore compatibilità con il sistema ospite, consiglio di modificare lo scrip send_nrdp.php, sostituendo il tag di apertura <? con <?php. Inoltre, se si vuole fare un pò di troubleshooting, conviene decommentare alcune parti di codice, ad esempio:

 echo "XML=\n$xml\n";

linea 162;

echo "URL=$theurl\n";

linea 168;

echo "RESULT=\n";
print_r($result);

linee 177 e 178.

Configurazione di Nagios

Come ultimo passo procediamo con la creazione del servizio in grado di ricevere i check passivi, associandolo ad un determinato host.

Ad esempio:

 define service{
        use                   local-service
        host_name             localhost
        service_description   Test
        check_command         check_passive
        passive_checks_enabled  1
        active_checks_enabled   0
        is_volatile             1
        check_freshness         1
        freshness_threshold     600
        flap_detection_enabled  0
        }

In particolare, ho abilitato le opzioni is_volatile, check_freshness e freshness_threshold. La prima serve a far generare un alert anche nel caso in cui vi sia solo una variazione dell’output restituito dal check (e non necessariamente un cambio di stato); la seconda serve a verificare che un determinato evento venga ricevuto entro un tempo limite (espresso in secondi), specificato mediante la terza direttiva, ovvero freshness_threshold.

Inoltre ho disabilitato la flap detection, poichè i check passivi possono cambiare stato molto frequentemente ed è mia intenzione tenere traccia (mediante alert) di tutti gli eventi.

Per ciò che concerne il comando check_passive (definito in /etc/nagios/objects/commands.cfg), esso presenta la seguente struttura:

# 'check_passive' command definition
define command{
        command_name check_passive
        command_line $USER1$/check_dummy 2 "No alerts received in 600 seconds"
}

dove l’applicativo check_dummy non fa altro che restituire lo stato (in questo caso 2, ovvero CRITICAL), affiancato da un’opportuna descrizione (No alerts received in 600 seconds).

Ricarichiamo la configurazione di Nagios:

[root@linuxbox local]# service nagios reload

ed abbiamo finito. Alla prossima

CentOS 6: monitorare le performance di Nagios mediante MRTG

Il compito di un NMS, si sa, è quello di monitorare le prestazioni e lo stato di salute di server, router, switch, firewall e chi più ne ha più ne metta. Nel caso in cui gli oggetti da tenere sotto osservazione siano relativamente pochi (qualche centinatio) ed il server su cui è ospitato Nagios sia abbastanza corazzato (almeno 4/8 GB di RAM), il nostro NMS dovrebbe riuscire a svolgere il suo compito senza grosse difficoltà. Tutto si complica, ovviamente, se il numero degli oggetti da monitorare risulta piuttosto elevato (parliamo qualche migliaio). In tal caso è conveniente tenere sotto controllo le performance del nostro sistema di monitoring (e non solo quelle del server su cui è in esecuzione), poichè potrebbero essere presenti alcuni colli di bottiglia che ne inficiano il corretto funzionamento.

Esistono numerosi plugin sviluppati appositamente per Nagios ed in grado di restituirci dei feedback relativi allo stato di salute dell’NMS in questione, ma, per ovvie ragioni, ho deciso di demandare tale compito ad un tool esterno (leggasi Nagios indipendente): MRTG.

mrtg_logo

In questo post abbiamo visto come installarlo e come creare una configurazione valida per la misurazione della banda associata alle interfacce del nostro router. Adesso vedremo come integrarlo a Nagios in modo da ottenere (e graficizzare) le sue performance.

Di seguito riporto il contenuto del file nagios.cfg (presente all’interno della directory /etc/mrtg/), usato da MRTG per svolgere il proprio compito di monitoraggio:

WorkDir: /var/www/mrtg/nagios

# Service Latency and Execution Time
Target[nagios-a]: `/usr/bin/nagiostats --mrtg --data=AVGACTSVCLAT,AVGACTSVCEXT,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-a]: 100000
Title[nagios-a]: Average Service Check Latency and Execution Time
PageTop[nagios-a]: <H1>Average Service Check Latency and Execution Time</H1>
Options[nagios-a]: growright,gauge,nopercent
YLegend[nagios-a]: Milliseconds
ShortLegend[nagios-a]: &nbsp;
LegendI[nagios-a]: &nbsp;Latency:
LegendO[nagios-a]: &nbsp;Execution Time:
Legend1[nagios-a]: Latency
Legend2[nagios-a]: Execution Time
Legend3[nagios-a]: Maximal 5 Minute Latency
Legend4[nagios-a]: Maximal 5 Minute Execution Time

# Service Percent State Change
Target[nagios-b]: `/usr/bin/nagiostats --mrtg --data=AVGACTSVCPSC,AVGPSVSVCPSC,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-b]: 100
Title[nagios-b]: Average Service State Change
PageTop[nagios-b]: <H1>Average Service State Change</H1>
Options[nagios-b]: growright,gauge,nopercent
YLegend[nagios-b]: Percent
ShortLegend[nagios-b]: &nbsp;
LegendI[nagios-b]: &nbsp;Active Check % Change:
LegendO[nagios-b]: &nbsp;Passive Check % Change:
Legend1[nagios-b]: State Change
Legend2[nagios-b]: State Change
Legend3[nagios-b]: Maximal 5 Minute State Change
Legend4[nagios-b]: Maximal 5 Minute State Change

# Host Latency and Execution Time
Target[nagios-c]: `/usr/bin/nagiostats --mrtg --data=AVGACTHSTLAT,AVGACTHSTEXT,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-c]: 100000
Title[nagios-c]: Average Host Check Latency and Execution Time
PageTop[nagios-c]: <H1>Average Host Check Latency and Execution Time</H1>
Options[nagios-c]: growright,gauge,nopercent
YLegend[nagios-c]: Milliseconds
ShortLegend[nagios-c]: &nbsp;
LegendI[nagios-c]: &nbsp;Latency:
LegendO[nagios-c]: &nbsp;Execution Time:
Legend1[nagios-c]: Latency
Legend2[nagios-c]: Execution Time
Legend3[nagios-c]: Maximal 5 Minute Latency
Legend4[nagios-c]: Maximal 5 Minute Execution Time

# Host Percent State Change
Target[nagios-d]: `/usr/bin/nagiostats --mrtg --data=AVGACTHSTPSC,AVGPSVHSTPSC,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-d]: 100
Title[nagios-d]: Average Host State Change
PageTop[nagios-d]: <H1>Average Host State Change</H1>
Options[nagios-d]: growright,gauge,nopercent
YLegend[nagios-d]: Percent
ShortLegend[nagios-d]: &nbsp;
LegendI[nagios-d]: &nbsp;Active Check % Change:
LegendO[nagios-d]: &nbsp;Passive Check % Change:
Legend1[nagios-d]: State Change
Legend2[nagios-d]: State Change
Legend3[nagios-d]: Maximal 5 Minute State Change
Legend4[nagios-d]: Maximal 5 Minute State Change

# Hosts/Services Actively Checked
Target[nagios-e]: `/usr/bin/nagiostats --mrtg --data=NUMHSTACTCHK5M,NUMSVCACTCHK5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-e]: 7000
Title[nagios-e]: Hosts/Services Actively Checked
PageTop[nagios-e]: <H1>Hosts/Services Actively Checked</H1>
Options[nagios-e]: growright,gauge,nopercent
YLegend[nagios-e]: Total
ShortLegend[nagios-e]: &nbsp;
LegendI[nagios-e]: &nbsp;Hosts:
LegendO[nagios-e]: &nbsp;Services:

# Hosts/Services Passively Checked
Target[nagios-f]: `/usr/bin/nagiostats --mrtg --data=NUMHSTPSVCHK5M,NUMSVCPSVCHK5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-f]: 7000
Title[nagios-f]: Hosts/Services Passively Checked
PageTop[nagios-f]: <H1>Hosts/Services Passively Checked</H1>
Options[nagios-f]: growright,gauge,nopercent
YLegend[nagios-f]: Total
ShortLegend[nagios-f]: &nbsp;
LegendI[nagios-f]: &nbsp;Hosts:
LegendO[nagios-f]: &nbsp;Services:

# Used/Avail External Command Buffers
Target[nagios-g]: `/usr/bin/nagiostats --mrtg --data=TOTCMDBUF,USEDCMDBUF,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-g]: 7000
Title[nagios-g]: External Command Buffers
PageTop[nagios-g]: <H1>External Command Buffers</H1>
Options[nagios-g]: growright,gauge,nopercent
YLegend[nagios-g]: Buffers
ShortLegend[nagios-g]: &nbsp;
LegendI[nagios-g]: &nbsp;Total:
LegendO[nagios-g]: &nbsp;Used:

# Active Host Checks
Target[nagios-i]: `/usr/bin/nagiostats --mrtg --data=NUMSACTHSTCHECKS5M,NUMOACTHSTCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-i]: 7000
Title[nagios-i]: Active Host Checks
PageTop[nagios-i]: <H1>Active Host Checks</H1>
Options[nagios-i]: growright,gauge,nopercent
YLegend[nagios-i]: Checks
ShortLegend[nagios-i]: &nbsp;
LegendI[nagios-i]: &nbsp;Scheduled Checks:
LegendO[nagios-i]: &nbsp;On-Demand Checks:

# Active Service Checks
Target[nagios-j]: `/usr/bin/nagiostats --mrtg --data=NUMSACTSVCCHECKS5M,NUMOACTSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-j]: 7000
Title[nagios-j]: Active Service Checks
PageTop[nagios-j]: <H1>Active Service Checks</H1>
Options[nagios-j]: growright,gauge,nopercent
YLegend[nagios-j]: Checks
ShortLegend[nagios-j]: &nbsp;
LegendI[nagios-j]: &nbsp;Scheduled Checks:
LegendO[nagios-j]: &nbsp;On-Demand Checks:

# Passive Host/Service Checks
Target[nagios-k]: `/usr/bin/nagiostats --mrtg --data=NUMPSVHSTCHECKS5M,NUMPSVSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-k]: 7000
Title[nagios-k]: Passive Host/Service Checks
PageTop[nagios-k]: <H1>Passive Host/Service Checks</H1>
Options[nagios-k]: growright,gauge,nopercent
YLegend[nagios-k]: Checks
ShortLegend[nagios-k]: &nbsp;
LegendI[nagios-k]: &nbsp;Host Checks:
LegendO[nagios-k]: &nbsp;Service Checks:

# Cached Host/Service Checks
Target[nagios-l]: `/usr/bin/nagiostats --mrtg --data=NUMCACHEDHSTCHECKS5M,NUMCACHEDSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-l]: 7000
Title[nagios-l]: Cached Host/Service Checks
PageTop[nagios-l]: <H1>Cached Host/Service Checks</H1>
Options[nagios-l]: growright,gauge,nopercent
YLegend[nagios-l]: Checks
ShortLegend[nagios-l]: &nbsp;
LegendI[nagios-l]: &nbsp;Host Checks:
LegendO[nagios-l]: &nbsp;Service Checks:

# External Commands
Target[nagios-m]: `/usr/bin/nagiostats --mrtg --data=NUMEXTCMDS5M,0,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-m]: 7000
Title[nagios-m]: External Commands
PageTop[nagios-m]: <H1>External Commands</H1>
Options[nagios-m]: growright,gauge,nopercent
YLegend[nagios-m]: Commands
ShortLegend[nagios-m]: &nbsp;
LegendI[nagios-m]: &nbsp;Commands:
LegendO[nagios-m]: &nbsp;

# Parallel/Service Host Checks
Target[nagios-n]: `/usr/bin/nagiostats --mrtg --data=NUMPARHSTCHECKS5M,NUMSERHSTCHECKS5M,PROGRUNTIME,NAGIOSVERPID`
MaxBytes[nagios-n]: 7000
Title[nagios-n]: Parallel/Serial Host Checks
PageTop[nagios-n]: <H1>Parallel/Serial Host Checks</H1>
Options[nagios-n]: growright,gauge,nopercent
YLegend[nagios-n]: Checks
ShortLegend[nagios-n]: &nbsp;
LegendI[nagios-n]: &nbsp;Parallel Checks:
LegendO[nagios-n]: &nbsp;Serial Checks:

Il giro del fumo può banalmente essere riassunto in questo modo: viene lanciato l’applicativo nagiostats, al quale vengono affiancate alcune flag come –mrtg e –data (quest’ultima serve a specificare i parametri da monitorare, ad esempio NUMPSVHSTCHECKS5M,NUMPSVSVCCHECKS5M,PROGRUNTIME,NAGIOSVERPID).

Occorre precisare, inoltre,  che nagiostats viene eseguito direttamente dal crontab che richiama MRTG, ragion per cui è indispensabile configurare SElinux in modo da consentire tale operazione.

Creiamo la directory che ospiterà la pagina Web contenente le i grafici associati alle prestazioni di Nagios:

[root@linuxbox ~]# mkdir -p /var/www/mrtg/nagios

e successivamente passiamo alla creazione della pagina index.html:

[root@linuxbox ~]# indexmaker --output=/var/www/mrtg/nagios/index.html /etc/mrtg/nagios.cfg

Infine, modifichiamo il contenuto del file /etc/cron.d/mrtg, aggiungendo la stringa:

*/5 * * * * root LANG=C LC_ALL=C /usr/bin/mrtg /etc/mrtg/nagios.cfg --lock-file /var/lock/mrtg/nagios_l --confcache-file /var/lib/mrtg/nagios.ok

Come ultimo step creiamo la configurazione di Apache per l’accesso alla pagina Web in cui sono presenti i grafici generati da MRTG:

[root@linuxbox ~]# nano /etc/httpd/conf.d/mrtg.conf

Il cui contenuto dovrà essere simile al seguente:

Alias /mrtg /var/www/mrtg

<Location /mrtg>
    Order deny,allow
    Allow from all
    AuthName "MRTG Access"
    AuthType Basic
    AuthUserFile /etc/mrtg/passwd
    Require valid-user
</Location>

Infine, creiamo il file contenente user e pass per l’accesso alla suddetta pagina Web:

[root@linuxbox ~]# htpasswd -c /etc/mrtg/passwd <vostrouser>

Ricarichiamo la configurazione di Apache:

[root@linuxbox ~]# service apache reload

ed abbiamo finito:

mrtg-nagios

Alla prossima.

check_noise_margin e check_attenuation: script Nagios per verificare la qualità della nostra linea ADSL

Premessa

Vi sono numerosi fattori che possono influenzare negativamente o positivamente la qualità della nostra linea ADSL, ma i più importanti sono sicuramente il rapporto segnale rumore (SNR o noise margin) e l’attenuazione.

In particolare, nel primo caso un valore elevato indica una qualità migliore; viceversa, nel secondo caso, un valore elevato indica una qualità peggiore. Inoltre, i valori di attenuazione sono molto influenzati dalla distanza che intercorre tra la nostra abitazione e la centrale di zona dell’ISP (va da se che maggiore sarà questa distanza, maggiore sarà l’attenuazione).

Esistono comunque dei valori di massima (sia per l’SNR che per l’attenuazione) sui quali ci si può basare per fare una stima qualitativa del nostro collegamento ADSL. Li riporto di seguito:

SNR

1) <= 6dB : pessimo, numerosi errori si sincronizzazione con la portante;
2) tra i 7dB ed i 10dB: scarso;
3) tra gli 11dB ed i 20dB: buono;
4) tra i 20dB ed i 28dB: eccellente;
5) >= 29dB: eccezionale.

 Attenuazione

1) < = 20dB: eccezionale;
2) tra i 20dB ed i 30dB: eccellente:
3) tra i 30dB ed i 40dB: molto buona;
4) tra i 40dB ed i 50dB: buona;
5) tra i 50dB ed i 60dB: scarsa, con diversi errori di connessione.
6) >= 60dB: pessima, con numerosi errori di connessione.

Tenendo conto dei suddetti valori, ho deciso di realizzare 2 scrip bash (da integrare a Nagios), in modo da tenere traccia dei valori di SNR ed attenuazione relativi alla mia linea ADSL. Il router di riferimento è un Cisco 877.

Entrambi gli scrip in questione (check_noise_margin e check_attenuation), si basano su un ulteriore scrip expect (get_dsl_info) che esegue la query sul router, lanciando il comando sh dsl int atm0.

Il contenuto di tale scrip è il seguente:

#!/usr/bin/expect

set ip [lindex $argv 0]
set password1 [lindex $argv 1]
set password2 [lindex $argv 2]

spawn ssh -l nightfly "$ip"
expect "*?assword:*"
send "$password1\r"
expect ">"
send "ena\r"
expect "Password:"
send "$password2\r"
expect "#"
send "sh dsl int atm0\r"
send " "
expect "#"
send "exit\r"
expect eof

L’output da esso generato verrà quindi dato in pasto ed elaborato da check_noise_margin e da check_attenuation. Il loro contenuto è molto simile ed è (rispettivamente):

#!/bin/bash

host=$1
password1=$2
password2=$3
warning=$4
critical=$5

usage="check_noise_margin <host> <password1> <password2> <warning> <critical>"

if [ -n "$host" ]; then

        if [ -n "$password1" ];then

                if [ -n "$password2" ];then

                        if [ -n "$warning" ];then

                                if [ -n "$critical" ];then

                                        if [ "$critical" -gt "$warning" ];then

                                                echo "UNKNOWN: critical has to be less than warning"
                                                exit 3;

                                        else

                                                output=`/usr/lib64/nagios/plugins/get_dsl_info $1 $2 $3 | grep "Noise"  | awk -F " " '{print $3,$5}'`
                                                output1=`echo $output | awk '{print $1}'`
                                                output2=`echo $output | awk '{print $2}'`
                                                unit="db"
                                        fi

                                        if [ -n "$output" ];then

                                                if [ $(echo "$output1 < $critical" | bc) -eq 1 -o $(echo "$output2 < $critical" | bc) -eq 1 ];then

                                                        echo "CRITICAL: downstream noise margin is $output1 db, upstream noise margin is $output2 db | downstream_noise_margin=$output1$unit;$warning;$critical upstream_noise_margin=$output2$unit;$warning;$critical";
                                                        exit 2;

                                                elif [ $(echo "$output1 > $critical" | bc) -eq 1 -a  $(echo "$output1 < $warning" | bc) -eq 1 -o $(echo "$output2 > $critical" | bc) -eq 1 -a $(echo "$output2 < $warning"  |bc) -eq 1 ];then

                                                        echo "WARNING: downstream noise margin is $output1 db, upstream noise margin is $output2 db| downstream_noise_margin=$output1$unit;$warning;$critical upstream_noise_margin=$output2$unit;$warning;$critical" ;
                                                        exit 1;

                                                else

                                                        echo "OK: downstream noise margin is $output1 db, upstream noise margin is $output2 db | downstream_noise_margin=$output1$unit;$warning;$critical upstream_noise_margin=$output2$unit;$warning;$critical";
                                                        exit 0;

                                                fi
                                        else

                                                echo "UNKNOWN: output is null"
                                                exit 3;

                                        fi

                                else

                                        echo "$usage"
                                        exit 3;
                                fi

                        else

                                echo "$usage"
                                exit 3;
                        fi

                else

                        echo "$usage"
                        exit 3;
                fi
        else

                echo "$usage"
                exit 3;
        fi

else

        echo "$usage"
        exit 3;

fi

per check_noise_margin, e:

#!/bin/bash

host=$1
password1=$2
password2=$3
warning=$4
critical=$5

usage="check_attenuation <host> <password1> <password2> <warning> <critical>"

if [ -n "$host" ]; then

        if [ -n "$password1" ];then

                if [ -n "$password2" ];then

                        if [ -n "$warning" ];then

                                if [ -n "$critical" ];then

                                        if [ "$critical" -lt "$warning" ];then

                                                echo "UNKNOWN: critical has to be greater than warning"
                                                exit 3;

                                        else

                                                output=`/usr/lib64/nagios/plugins/get_dsl_info $1 $2 $3 | grep "Attenuation"  | awk -F " " '{print $2, $4}'`

                                                output1=`echo $output | awk '{print $1}'`
                                                output2=`echo $output | awk '{print $2}'`
                                                unit="db"
                                        fi

                                        if [ -n "$output" ];then

                                                if [ $(echo "$output1 > $critical" | bc) -eq 1 -o $(echo "$output2 > $critical" | bc) -eq 1 ];then

                                                        echo "CRITICAL: downstream attenuation is $output1 db, upstream attenuation is $output2 db | downstream_attenuation=$output1$unit;$warning;$critical upstream_attenuation=$output2$unit;warning;$critical";
                                                        exit 2;

                                                elif [ $(echo "$output1 < $critical" | bc) -eq 1 -a  $(echo "$output1 > $warning" | bc) -eq 1 -o $(echo "$output2 < $critical" | bc) -eq 1 -a  $(echo "$output2 > $warning" | bc) -eq 1 ];then

                                                        echo "WARNING: downstream attenuation is $output1 db, upstream attenuation is $output2 db | downstream_attenuation=$output1$unit;$warning;$critical upstream_attenuation=$output2$unit;$warning;$critical";
                                                        exit 1;

                                                else

                                                        echo "OK: downstream attenuation is $output1 db, upstream attenuation is $output2 db | downstream_attenuation=$output1$unit;$warning;$critical upstream_attenuation=$output2$unit;$warning;$critical";
                                                        exit 0;

                                                fi
                                        else

                                                echo "UNKNOWN: output is null"
                                                exit 3;

                                        fi

                                else

                                        echo "$usage"
                                        exit 3;
                                fi

                        else

                                echo "$usage"
                                exit 3;
                        fi

                else

                        echo "$usage"
                        exit 3;
                fi
        else

                echo "$usage"
                exit 3;
        fi

else

        echo "$usage"
        exit 3;

fi

per check_attenuation.

Da notare che in entrambi i casi ho aggiunto le perfdata da dare in pasto a pnp4nagios. Inoltre, poichè i valori restituiti possono contenere dei decimali, ho dovuto utilizzare il comando bc per i calcoli aritmetici. Ciò si è reso necessario poichè bash tratta nativamente le variabili come stringhe.

Una volta fatto ciò, ho semplicemente creato i comandi per Nagios:

# 'check_noise_margin' command definition
 define command{
 command_name    check_noise_margin
 command_line    $USER1$/check_noise_margin $HOSTADDRESS$ $ARG1$ $ARG2$ $ARG3$ $ARG4$
 }
# 'check_attenuation' command definition
 define command{
 command_name    check_attenuation
 command_line    $USER1$/check_attenuation $HOSTADDRESS$ $ARG1$ $ARG2$ $ARG3$ $ARG4$
 }

collegandoli, successivamente, ai servizi del router Cisco:

define service{
 use                             local-service         ; Name of service template to use
 host_name                       router
 service_descripion             Noise Margin
 check_command                   check_noise_margin!pass1!pass2!10!6
 }
define service{
 use                             local-service         ; Name of service template to use
 host_name                       router
 service_descripion             Attenuation
 check_command                   check_attenuation!pass1!pass2!51!61
 }

Infine, ho lanciato un reload del servizio:

[root@nightbox objects]# service nagios reload

e finalmente la qualità della mia linea ADSL è sotto monitoraggio.

Alla prossima.

PS: per chi le preferisse, ecco le varianti in Perl dei suddetti scrip:

#!/usr/bin/perl

use strict;
use warnings;

my $host=$ARGV[0];
my $password1=$ARGV[1];
my $password2=$ARGV[2];
my $warning=$ARGV[3];
my $critical=$ARGV[4];

my $usage="check_noise_margin.pl <host> <password1> <password2> <warning> <critical>";

if ($host ne "") {
        if ($password1 ne "")
        {
                if ($password2 ne "")
                {
                        if ($warning ne "")
                        {
                                if ($critical ne "")
                                {
                                        if ($critical > $warning)
                                        {
                                                print "UNKNOWN: critical has to be less than warning";
                                                exit 3;
                                        }
                                        else
                                        {
                                                my $output=`/usr/lib64/nagios/plugins/get_dsl_info $host $password1 $password2 | /bin/grep "Noise"`;

                                                if($output ne "")
                                                {

                                                        my @columns = split /\s+/, $output;
                                                        my $downstream = $columns[2];
                                                        my $upstream = $columns[4];
                                                        my $unit = "db";

                                                        if ($downstream < $critical || $upstream < $critical)
                                                        {
                                                                print "CRITICAL: downstream noise margin is $downstream db; upstream noise margin is $upstream db | downstream_noise_margin=$downstream$unit;$warning;$critical upstream_noise_margin=$upstream$unit;$warning;$critical\n";
                                                                exit 2;
                                                        }
                                                        elsif ($downstream > $critical && $downstream < $warning || $upstream > $critical && $upstream < $warning)
                                                        {
                                                                print "WARNING: downstream noise margin is $downstream db; upstream noise margin is $upstream db | downstream_noise_margin=$downstream$unit;$warning;$critical upstream_noise_margin=$upstream$unit;$warning;$critical\n";
                                                                exit 1;
                                                        }
                                                        else
                                                        {
                                                                print "OK: downstream noise margin is $downstream db, upstream noise margin is $upstream db | downstream_noise_margin=$downstream$unit;$warning;$critical upstream_noise_margin=$upstream$unit;$warning;$critical\n";
                                                                exit 0;
                                                        }
                                                }
                                                else
                                                {
                                                                print "UNKNOWN: output is null";
                                                                exit 3;
                                                }
                                        }
                                }
                                else
                                {
                                        print "$usage";
                                        exit 3;
                                }
                        }
                        else
                        {
                                print "$usage";
                                exit 3;
                        }
                }
                else
                {
                        print "$usage";
                        exit 3;
                }
        }
        else
        {
                print "$usage";
                exit 3;
        }
}
else
{
        print "$usage";
        exit 3;
}

e

#!/usr/bin/perl

use strict;
use warnings;

my $host=$ARGV[0];
my $password1=$ARGV[1];
my $password2=$ARGV[2];
my $warning=$ARGV[3];
my $critical=$ARGV[4];

my $usage="check_attenuation.pl <host> <password1> <password2> <warning> <critical>";

if ($host ne "") {
        if ($password1 ne "")
        {
                if ($password2 ne "")
                {
                        if ($warning ne "")
                        {
                                if ($critical ne "")
                                {
                                        if ($critical < $warning)
                                        {
                                                print "UNKNOWN: critical has to be more than warning";
                                                exit 3;
                                        }
                                        else
                                        {
                                                my $output=`/usr/lib64/nagios/plugins/get_dsl_info $host $password1 $password2 | /bin/grep "Attenuation"`;

                                                if($output ne "")
                                                {

                                                        my @columns = split /\s+/, $output;
                                                        my $downstream = $columns[1];
                                                        my $upstream = $columns[3];
                                                        my $unit = "db";

                                                        if ($downstream > $critical || $upstream > $critical)
                                                        {
                                                                print "CRITICAL: downstream attenuation is $downstream db; upstream attenuation is $upstream db | downstream_attenuation=$downstream$unit;$warning;$critical upstream_attenuation=$upstream$unit;$warning;$critical\n";
                                                                exit 2;
                                                        }
                                                        elsif ($downstream < $critical && $downstream > $warning || $upstream < $critical && $upstream > $warning)
                                                        {
                                                                print "WARNING: downstream attenuation is $downstream db; upstream attenuation is $upstream db | downstream_attenuation=$downstream$unit;$warning;$critical upstream_attenuation=$upstream$unit;$warning;$critical\n";
                                                                exit 1;
                                                        }
                                                        else
                                                        {
                                                                print "OK: downstream attenuation is $downstream db, upstream attenuation is $upstream db | downstream_attenuation=$downstream$unit;$warning;$critical upstream_attenuation=$upstream$unit;$warning;$critical\n";
                                                                exit 0;
                                                        }
                                                }
                                                else
                                                {
                                                                print "UNKNOWN: output is null";
                                                                exit 3;
                                                }
                                        }
                                }
                                else
                                {
                                        print "$usage";
                                        exit 3;
                                }
                        }
                        else
                        {
                                print "$usage";
                                exit 3;
                        }
                }
                else
                {
                        print "$usage";
                        exit 3;
                }
        }
        else
        {
                print "$usage";
                exit 3;
        }
}
else
{
        print "$usage";
        exit 3;
}

PPS: se sul vostro router è stato abilitato il protocollo SNMP, gli OID che consentono di monitorare SNR ed attenuazione sono i seguenti:

.1.3.6.1.2.1.10.94.1.1.3.1.5.11 = downstream attenuation 
.1.3.6.1.2.1.10.94.1.1.2.1.5.11 = upstream attenuation 
.1.3.6.1.2.1.10.94.1.1.3.1.4.11 = downstream noise margin
.1.3.6.1.2.1.10.94.1.1.2.1.4.11 = upstream noise margin

In particolare, l’ultima parte dell’OID (.11) si riferisce all’Interface Index della Dialer (nel mio caso si tratta della Dialer0).