last update: 27/ jun / 2007

Monitoraggio di sistemi - parte3 - SNMP

Dopo aver concluso la trattazione di Nagios si ritorna dalla pratica alla teoria con SNMP.

SNMP

Il Simple Network Management Protocol è un protocollo per l'amministrazione delle reti definito dallo standard internet RFC1157 integrato da numerosi altri RFC successivi. Si tratta quindi di un protocollo e non di un applicazione specifica e fu sviluppato per fornire risposte alla necessità di un protocollo di amministrazione per le reti con gli obiettivi principali di semplicità e robustezza. Nelle specifiche veniva previsto un basso sovraccarico sia per i dispositivi che utilizzassero il protocollo sia per la rete.

La prima volta che ho affrontato questo protocollo ho fatto l'errore, comune a molti, di tradurre simple con semplice (nel senso di facile da usare) mentre una traduzione più consona potrebbe essere semplificato nel senso che la struttura e i metodi del protocollo sono semplificati. Vengono infatti supportati solo tre metodi fondamentali:

  • la scrittura di una variabile: comando set
  • la lettura di una variabile: comando get
  • la notifica di un evento: trap

Non si desidera di seguito entrare troppo nel dettaglio del protocollo ma è importante evidenziare che la semplicità è proprio nella struttura del pacchetto che consiste sempre di un pacchetto UDP monolitico (l'aggettivo inglese atomic rende meglio se tradotto con monolitico a mio parere).

Il pacchetto è costituito da:
  • un identificativo di versione,
  • un community name (che praticamente rappresenta una password),
  • un unità dati (Protocol Data Unit).

Le PDU contengono sia un identificativo di tipo sia i dati/variabili su cui si va ad agire.
Ci sono solo cinque tipi di PDU che sostanzialmente corrispondono a cinque diverse azioni: get-request, get-next-request, set-request, get-response e trap.

Un pacchetto get-request, inviato a un dispositivo, ottiene in risposta un get-response che restituisce il valore di una variabile.
Un pacchetto get-next-request è utilizzato per iterare fra gli elementi di un albero di variabili e ottiene sempre un get-response.
Un pacchetto set-request configura una variabile di un dispositivo. Anch'esso ottiene in risposta un get-response.

I trap sono differenti in quanto vengono inviati dal dispositivo ad un indirizzo IP configurato nel dispositivo stesso al verificarsi di determinati eventi per i quali il dispositivo è programmato. Il pacchetto in questione contiene una serie di variabili/valori che il dispositivo ritiene utili per descrivere l'evento. Non viene attesa risposta al trap. Cosa succede all'indirizzo di destinazione o, perfino, se esista qualcosa a quell'indirizzo non è a carico del dispositivo il quale si limita all'invio della segnalazione.
Le porte usate dal protocollo sono la UDP 161 per le richieste e le risposte e la UDP 162 come destinazione delle trap SNMP; è necessario tenerne conto quando gli apparecchi da monitorare e quelli di monitoraggio sono posti sui due lati di un firewall.
La versione 2, e successive, del protocollo implementano anche dei comandi aggiuntivi e delle estensioni agli oggetti gestiti. Vi rimando alla lettura degli RFC 1441 e 1442 per ulteriori dettagli.

Nelle immagini che seguono viene mostrato un pacchetto UDP inviato per richiedere un valore ad uno switch e la successiva risposta. Il pacchetto è stato rilevato con ethereal [http://www.ethereal.com/] e come si vede si tratta una richiesta di una variabile (GET) e della successiva risposta. In entrambe le immagini è identificabile la community string di default ("public").

Come già detto SNMP offre, per ogni dispositivo, una variabile detta comunity string che ha la funzione di una password. Si può vedere dalle immagini che la stringa in questione è visibile in chiaro, quindi, in realtà è una sicurezza debolissima ed è uno dei motivi per i quali sono state, teoricamente, abbandonate le versioni 1 e 2c del protocollo (anche se in realtà sono ancora le più utilizzate) a favore della versione 3.

Come già anticipato SNMP tratta degli oggetti che essenzialmente sono delle variabili. Tali variabili sono definite e descritte nella Management Information Base (MIB). MIB non è un database ma una struttura dati ovvero un file scritto in uno specifico linguaggio (SMI - Structure of Management Information) che elenca delle variabili assegnando ad ogni variabile un nome, un numero ed un elenco di permessi.

Il file viene visto come una gerarchia ad albero e ogni variabile è considerata una foglia nell' albero. Tutto ciò che riguarda SNMP si trova al di sotto del ramo denominato .iso.org.dod.internet che ha come identificativo numerico 1.3.6.1

L' immagine seguente è uno snapshot dal sito http://support.ipmonitor.com/ e rappresenta un esempio di gerarchia ad albero

L' identificativo numerico di ciascun oggetto è detto OID (Object Identifier) e non dovrebbe iniziare con un punto anche se, in molte notazioni, il punto iniziale viene sempre riportato. E' utile tenere presente che, in una qualsiasi operazione, qualora l' OID specificato non sia completo (ovvero qualora venga specificato un nodo anziché un oggetto) tutti gli oggetti del nodo richiesto saranno forniti in risposta.
Oltre all' albero standard definito dal comitato di standardizzazione esistono dei sotto-alberi registrati da aziende private presso l' ente di standardizzazione. Per impieghi interni all' azienda è, ovviamente, possibile definire un proprio sotto-albero qualora ve ne fosse la necessità.

Gli oggetti veri e propri, o variabili che dir si voglia, possono essere di cinque tipi:

  • Stringhe di caratteri - solitamente rappresentano delle descrizioni di altre variabili o nomi descrittivi o frasi che compaiono nei display.
  • Octect String (otteti) può rappresentare una stringa di caratteri o un dato binario secondo quanto specificato dal MIB
  • Interi - usati solitamente come indici per tabelle
  • Contatori - interi che crescono continuamente fino al loro limite e poi si azzerano. Sono a 32 o 64 bit
  • Gauge (traducibile con strumento di misura/indicatore) - è una variabile che può aumentare o diminuire nel tempo ed è utilizzata per misurare un valore es. carico di una CPU, velocità di una ventola o bps di un interfaccia.

In base al tipo di dispositivo vi sono un infinità di parametri che possono essere misurati o rilevati con SNMP ad esempio il carico di una CPU, il numero di processi di un server, i pacchetti in errore di un router, le collisioni di una rete, la memoria libera di una stampante e così via.

Il dispositivo che si incarica del monitoraggio SNMP e/o della ricezione dei trap, sia esso un server, un PC o un tester dedicato viene denominato Network Management Station (NMS).

Nel dispositivo da monitorare o amministrare, il protocollo SNMP, prevede la presenza di un programma, detto agente. Vi sono agenti SNMP nei routers, negli switch, nelle stampanti, ad esempio, ma vi sono agenti disponibili anche per i sistemi operativi sia per i vari UNIX e derivati sia per le varie versioni di Windows. L' agente oltre a rispondere a delle richieste dirette di tipo lettura o modifica di una variabile potrebbe venir programmato (qualora sia programmabile) per generare un trap in risposta ad un determinato evento.

Un esempio semplice è quello delle stampanti; molte di esse hanno il protocollo SNMP attivo al loro interno e sono in grado di generare un avviso per eventi quali l'esaurimento della carta o del toner. Il segnale in questione può essere monitorato da un utility dedicata o da un NMS predisposto per ricevere la notifica del problema.

Il vantaggio delle trap rispetto all'interrogazione delle variabili è che con quest'ultimo metodo può accadere di perdere un evento fra un interrogazione e l'altra mentre nel primo caso è proprio l'evento a creare la notifica e quindi è meno probabile che esso venga perso. La perdita di una segnalazione è comunque sempre possibile in quanto potrebbe accadere che, il server che gestisce le notifiche, se ha in carico un numero troppo elevato di dispositivi e molti di essi sono in errore, può non essere in grado di gestire tutte le segnalazioni. Chiaramente la situazione è improbabile in un ambiente ben dimensionato. Inoltre un server che interroga attivamente le variabili è soggetto ad un maggior carico elaborativo rispetto ad uno che si limita ad attendere passivamente la segnalazione di un problema e quindi l'interrogazione attiva sarebbe comunque meno efficiente.

Chiaramente se non si deve monitorare un evento ma effettuare delle misure a intervalli prestabiliti il metodo corretto è il polling da parte della NMS e non l'utilizzo delle trap.
Per quanto riguarda il carico creato dal polling sulla rete riporto una divertente indicazione di John Blommers:
"State per implementare un sistema di monitoraggio delle performance della rete basato su SNMP:

  • la misurazione dei pacchetti di get e relativa risposta danno una cifra fra i 200 e i 250 bytes
  • 250 è il valore più alto, utilizziamolo per i calcoli
  • si vuole mantenere il traffico SNMP al di sotto del 10% del link più lento della WAN per ciascuna rete contate il numero di misure da rilevare
  • assumete di utilizzare un intervallo di 1 minuto come punto di partenza
  • determinate i percorsi dei pacchetti SNMP attraverso l'intera rete
  • aggiungete i flussi che utilizzano lo stesso percorso per i pacchetti con dimensione maggiore di 250 byte
  • confrontate il flusso totale con la velocità della linea in ciascun punto
  • per flussi maggiori del 10% previsto riducete l'intervallo di polling o il numero di dispositivi monitorati.
Poi chiedetevi: perché gli amministratori di rete si devono preoccupare per l'aggiunta del traffico relativo al monitoraggio quando web e mail server vengono installati senza alcun dimensionamento e gli utenti navigano in rete senza riguardo o preoccupazione su quale impatto ciò abbia sulla rete?"

RMON

RMON è un MIB introdotto dalla versione 2 di SNMP che definisce uno standard per il monitoraggio di rete. In tale mib che inizia da .iso.org.dod.internet.mgmt.mib-2.rmon, e che ha come identificativo numerico 1.3.6.1 2.1.16 , sono definite 9 sezioni:

  1. statistic: mantiene dati relativi agli errori e all'utilizzo per ogni sotto-rete monitorata bytes, pacchetti, collisioni etc.
  2. history: campionamenti periodici prelevati tipicamente ogni 30 secondi
  3. alarm: gruppo che permette la definizione di valori di soglia, da utilizzare per gli alarmi, per ogni variabile di tipo contatore
  4. host: contatori per ogni host della sotto-rete
  5. hostTopN: statistiche relative agli host
  6. matrix: matrice di errori e utilizzo
  7. filter: si possono definire dei filtri da utilizzare per catturare i pacchetti che corrispondono al filtro definito
  8. capture: indicazioni sulla modalità di invio dei dati alla console di monitoraggio
  9. event: tabella di eventi generati dall'agente RMON
Chiaramente a seconda del dispositivo ciascun gruppo può essere o non essere implementato e avere o non avere un senso.

Ora, dopo aver ribadito più volte che SNMP è un protocollo e dopo aver capito che disponiamo di un database di informazioni (MIB) vediamo un implementazione che utilizza tale protocollo e passiamo dalla teoria alla pratica.

Net SNMP

l progetto Net SNMP, precedentemente noto come UCD-SNMP, è una raccolta di strumenti per gestire le informazioni SNMP in ambiente *NIX. Attraverso vari programmi permette le varie operazioni di lettura, scrittura e monitoraggio del protocollo fornendo sia quanto necessario per l'implementazione di un client sia gli strumenti per la gestione di una NMS. Il sito ufficiale è http://www.net-snmp.org/

I MIB supportati dal pacchetto sono:

  • MIB-2: Statistiche di rete conforme a RFC1213
  • Risorse degli host come da RFC1514 e 2790
  • SNMPv3 MIBS con il supporto alla versione 3
  • MTA-MIB con il supporto a sendmail
  • Estensioni a MIB privati

La prima versione di Net SNMP (la 5.0 in quanto le versioni precedenti sono state rilasciate come UCD-SNMP) ha adottato dall'inizio dei concetti di modularità, che non erano presenti in nella versione UCD, per cui, a titolo di esempio, per aggiungere un MIB a quelli in dotazione e sufficiente copiarlo in /usr/local/share/snmp/mibs (o /usr/share/snmp/mibs a seconda della distribuzione e del sistema operativo in uso) e con la stessa relativa semplicità è possibile estendere gli applicativi.

Non andrò, di seguito, a spiegare l'installazione dei programmi visto che ne esiste praticamente un pacchetto per ogni distribuzione, posso solo segnalare che nella versione per Fedora manca una qualche forma di collegamento fra il pacchetto del modulo SNMP perl e quello di Net SNMP e il browser grafico dei mib (tkmib) non funziona.

Non andrò nemmeno a spiegare in dettaglio tutti i comandi in quanto le man-pages sono esaustive in merito, ma mi limiterò ad una carrellata sui comandi principali con qualche esempio d'uso.

Snmpwalk:

Il primo comando da prendere in considerazione è snmpwalk. Questo comando produce come risultato la stampa dell'intero albero delle variabili di un dispositivo a partire dal punto passato come parametro. Se non si fornisce alcun punto di partenza il risultato sarà l'intero albero.
Ecco un esempio di output di snmpwalk che si riferisce ad uno switch:

# snmpwalk -m all 192.168.1.254 -c public
system.sysDescr.0 = "HP J4813A ProCurve Switch 2524, revision F.02.11, ROM F.02.01  (/sw/code/build/info(f00))"
system.sysObjectID.0 = OID: enterprises.11.2.3.7.11.19
system.sysUpTime.0 = Timeticks: (244993657) 28 days, 8:32:16.57
system.sysContact.0 = ""
system.sysName.0 = "Switch 5"
system.sysLocation.0 = "Corridoio 1"
system.sysServices.0 = 74
interfaces.ifNumber.0 = 28
interfaces.ifTable.ifEntry.ifIndex.1 = 1
interfaces.ifTable.ifEntry.ifIndex.2 = 2
interfaces.ifTable.ifEntry.ifIndex.3 = 3
interfaces.ifTable.ifEntry.ifIndex.4 = 4
interfaces.ifTable.ifEntry.ifIndex.5 = 5
interfaces.ifTable.ifEntry.ifIndex.6 = 6
interfaces.ifTable.ifEntry.ifIndex.7 = 7
interfaces.ifTable.ifEntry.ifIndex.8 = 8
[...]
il resto dell'output è stato troncato per brevità in quanto continuerebbe per molte pagine. A tal proposito, quando dovete esplorare un MIB, è molto utile redirigere l'output del comando verso un file in quanto spesso il buffer video non riesce a contenerlo completamente.
Indicando un solo ramo (ad esempio system) otteniamo un risultato più breve in quanto viene mostrato solo quanto richiesto:
# snmpwalk -mall -cpublic 192.168.1.254 system
system.sysDescr.0 = "HP J4813A ProCurve Switch 2524, revision F.02.11, ROM F.02.01  (/sw/code/build/info(f00))"
system.sysObjectID.0 = OID: enterprises.hp.nm.system.netElement.hpEtherSwitch.hpSwitchJ4813A
system.sysUpTime.0 = Timeticks: (262307843) 30 days, 8:37:58.43
system.sysContact.0 = ""
system.sysName.0 = "Switch 5"
system.sysLocation.0 = "Corridoio 1"
system.sysServices.0 = 74
Questo comando è molto utile in particolare per esplorare il "contenuto" di dispositivi dei quali non si conoscono le variabili. L'assenza di descrizioni in alcuni OID è sintomo della mancanza di un MIB specifico per il dispositivo esaminato e si risolve facilmente, se si riesce a rintracciare il MIB, installandolo come sopra accennato.

E' possibile utilizzare il comando in maniera molto "sporca" per dei monitoraggi improvvisati e a scopo di test. Nel esempio seguente, mancando il MIB specifico per una stampante di rete si voleva verificare se un certo ramo individuato era proprio quello relativo allo stato stampante.
Per individuare il ramo prima è stato eseguito un comando snmpwalk su tutto l'albero poi, per affinare la ricerca, è stata tolta la carta da due cassetti ed è stato eseguito il comando che segue:

# snmpwalk -mall -cpublic 192.168.1.236 43.18.1.1.8.1
43.18.1.1.8.1.3 = "Carta assente: Cassetto 4 {13500}"
43.18.1.1.8.1.84= "Carta assente: Cassetto 1 {13200}"
A questo punto uno script con un ciclo infinito ha permesso di verificare che il ramo individuato era quello corretto:
# vi testerrori.sh
inseriamo i seguenti comandi:
#!/bin/sh
while [ 1 ]; do
  snmpwalk -mall -cpublic 192.168.1.236 43.18.1.1.8.1
done
#Per bloccare lo script premere ctrl-C
e rendiamo lo script eseguibile:
# chmod 777 testerrori.sh
# ./testerrori.sh

43.18.1.1.8.1.90 = "Non rilevato: Cassetto 2 {12301}"
43.18.1.1.8.1.90 = "Non rilevato: Cassetto 2 {12301}"
43.18.1.1.8.1.90 = "Non rilevato: Cassetto 2 {12301}"
43.18.1.1.8.1.90 = "Non rilevato: Cassetto 2 {12301}"
43.18.1.1.8.1.90 = "Non rilevato: Cassetto 2 {12301}"
43.18.1.1.8.1.91 = "Non rilevato: Cassetto 3 {12401}"
43.18.1.1.8.1.91 = "Non rilevato: Cassetto 3 {12401}"
43.18.1.1.8.1.91 = "Non rilevato: Cassetto 3 {12401}"
43.18.1.1.8.1.91 = "Non rilevato: Cassetto 3 {12401}"
43.18.1.1.8.1.91 = "Non rilevato: Cassetto 3 {12401}"
Il risultato è stato ottenuto estraendo i cassetti. Ovviamente il monitoraggio vero è proprio è stato effettuato con altri strumenti ma niente vieta di migliorare lo script di cui sopra per gestioni molto semplici.

snmpget:

Il comando snmpget permette di ottenere il valore di una singola variabile: per esempio:

snmpget -Cf -mall 192.168.1.254 -c public .1.3.6.1.4.1.11.2.14.11.5.1.9.6.1.0
enterprises.11.2.14.11.5.1.9.6.1.0 = 13
Come si vede la forma dell’ OID nella risposta è abbreviata e manca tutto ciò che precede enterprises. La parte finale è invece in forma numerica per mancanza dello specifico MIB relativo al dispositivo interrogato. Una forma analoga con un MIB più completo è:
snmpget 192.168.1.236 public system.sysDescr.0
system.sysDescr.0 = NRG 3525/3508/3502 5.21 / NRG Network Printer C model / NRG Network Scanner C model
che, in questo esempio, permette di ottenere la descrizione del sistema (si tratta di una stampante).

Rifacendosi all'esempio citato nel comando snmpwalk, è possibile controllare la presenza della carta nella stessa stampante, in maniera molto più efficiente, con il seguente comando:

# snmpget -mall -cpublic 192.168.1.236 43.18.1.1.8.1.2
43.= "Carta assente: Cassetto 3 {13400}"
come è facile intuire è semplice costruire degli script che sfruttano il comando smpget e verificando le risposte ricevute segnalano un problema all'amministratore del dispositivo sotto controllo. Il linguaggio solitamente usato a tale scopo è il PERL (vedi ad es. The Cuddletech Guide to SNMP Programming all'indirizzo) ma nulla vieta di implementare dei semplici script di shell.

snmptable

A volte alcune informazioni di un mib sono correlate tra di loro come elementi di una tabella. La normale rappresentazione ad albero fa perdere la visione di insieme su tali elementi in quanto è difficile esaminare tali informazioni visualizzandole in maniera sequenziale. Il comando snmptable permette di ottenere una rappresentazione tabellare delle informazioni con l'unico inconveniente di risultare di difficile lettura per tabelle molto ampie.
Tale problema è poi risolvibile limitando l'output del comando a n. caratteri o con un copia ed incolla su un altro programma.
Vediamo come semplice esempio una tabella di indirizzi di uno switch:

# snmptable 192.168.1.253 ipAddrTable -cpublic
SNMP table: ip.ipAddrTable

  ipAdEntAddr ipAdEntIfIndex ipAdEntNetMask ipAdEntBcastAddr ipAdEntReasmMaxSize
     127.0.0.1          4124      255.0.0.0                1               65535
 192.168.1.253            29    255.255.0.0                1               65535
tale forma è sicuramente più leggibile dell'equivalente visualizzazione ad albero:
# snmpwalk 192.168.1.253 ipAddrTable -cpublic
ip.ipAddrTable.ipAddrEntry.ipAdEntAddr.127.0.0.1 = IpAddress: 127.0.0.1
ip.ipAddrTable.ipAddrEntry.ipAdEntAddr. 192.168.1.253 = IpAddress: 192.168.1.253
ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 4124
ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex. 192.168.1.253 = 29
ip.ipAddrTable.ipAddrEntry.ipAdEntNetMask.127.0.0.1 = IpAddress: 255.0.0.0
ip.ipAddrTable.ipAddrEntry.ipAdEntNetMask. 192.168.1.253 = IpAddress: 255.255.0.0
ip.ipAddrTable.ipAddrEntry.ipAdEntBcastAddr.127.0.0.1 = 1
ip.ipAddrTable.ipAddrEntry.ipAdEntBcastAddr. 192.168.1.253  = 1
ip.ipAddrTable.ipAddrEntry.ipAdEntReasmMaxSize.127.0.0.1 = 65535
ip.ipAddrTable.ipAddrEntry.ipAdEntReasmMaxSize. 192.168.1.253  = 65535

Traps

Come già anticipato una trap è un metodo per inviare da un dispositivo la notifica di un evento ad un NMS. Net SNMP oltre a permettere di creare delle trap ha in dotazione un demone che permette di costruire una NMS. Il demone in questione è snmptrapd ed ha la possibilità di ricevere delle trap ed attivare un programma in risposta a tale evento. Di default snmptrapd ascolta la porta UDP 162 per cui se attivate tale demone è opportuno verificare che tale porta non sia bloccata da un firewall.
Per poter intercettare un evento è necessario definire una traphandle (ovvero un aggancio) per tale evento nel file snmtrapd.conf. La sintassi per definire un traphandle è la seguente:

traphandle	OID 	commando 
quindi ad esempio per intercettare un errore da una stampante la configurazione potrebbe essere:
traphandle 	.1.3.6.1.2.1.25.3.2.1.5.1	/usr/local/bin/sendmessage_to_admin.sh
dove l’ipotetico comando /usr/local/bin/sendmessage_to_admin.sh è una shell che invia una mail ad un responsabile dell’operatività della stampante. E’ possibile passare a tale programma dei parametri predefiniti alcuni dei quali molto utili come ad esempio HOSTNAME e IPADDRESS che rappresentano il nome e l’indirizzo IP dell’host che ha generato la trap.

Concludo questa veloce panoramica su SNMP con la speranza di non aver tediato nessuno.
Il prossimo numero tratterà di RRDtool con qualche esempio pratico che forse risulter$agrave; più appetibile.
Come al solito vi invito a comenti critiche e suggerimenti.

Riferimenti bibliografici

  1. Essential SNMP di Kevin Schmidt, Douglas Mauro – O’Reilly - ISBN: 0596000200
  2. RFC 1157 su SNMP
  3. RFC 1351: SNMP Administrative model
  4. RFC 1441 Introduction to version 2 of INMF
  5. RFC 1442 Structure of MIF for SNMP v2
  6. NET SNMP FAQ
  7. The Simple Times magazine

di Rudi Giacomini Pilon