Introducción al SNMP


Introducción
Este texto pretende ser una pequeña introducción al protocolo snmp, a sus utilidades, al igual debe servir para destacar sus ventajas y defectos. Y digo pequeña porque el tema del snmp da como para llenar varios libros, que indudablemente no es mi objetivo. Lo que me ha motivado a escribir este texto es la falta de documentación en castellano que existe sobre el tema.

Descripción
El Simple Network Management Protocol es usado principalmente para monitorizar y controlar el status de dispositivos conectados a internet, en especial routers, aunque se puede usar en cualquier tipo de host que permita correr el snmpd. Ha sufrido numerosos cambios en los últimos años, cambios que intentare tratar con mas o menos profundidad a lo largo del texto, pero quiero dejar claro que el objetivo del texto son las siguientes versiones:

SNMPv1 La primera versión del protocolo. Véase rfc 1157
SNMPv2C Autentificación basada en los llamados "community strings"
SNMPv2U orientada a usuarios
REF RFC's 1901, 1905, 1906, 1909, 1910

Aparte de estas existen otras versiones, con mayor o menor grado de aceptación:

SNMPsec Es una versión poco aceptada / conocida, implementa una seguridad mucho mas fuerte. RFC's 1351,1352, 1353
SNMPv2p En esta versión se introdujeron muchas mejoras, pero es anterior a las 2C & 2U
SNMPv2* La versión mas avanzada del SNMPv2, combina lo mejor de todas las anteriores. Nunca se publicaron RFC's al respecto
SNMPv3 La mas nueva e interesante, es el estándar de SNMP del futuro. Una lastima que todavía no haya suficiente información sobre esta nueva versión como para escribir un articulo

Es en principio una típica aplicación cliente-servidor, donde el servidor (el agente de snmp) presenta información acerca de si mismo en un árbol jerárquico, información como el nombre del administrador, de la maquina, las configuraciones de sus tarjetas de red, etc... El servidor de snmp, el snmpd, usa para la comunicación con el cliente
(el llamado manager) el protocolo udp, y generalmente escucha en los puertos 161 y 162 (este ultimo para el snmptrapd, que explicare a continuación). Traps son paquetes enviados por el agente para informar de acontecimientos inusuales en su entorno, ya sea un reboot, que haya demasiado trafico en la red, un router que deja de responder, por poner unos ejemplos. Son la excepción a la regla que expongo en el siguiente párrafo, ya que los envía el agente sin haberlos solicitado previamente el manager.
Para solicitar información del agente (el servidor, por ultima vez), el manager emplea un mecanismo denominado get-request (no se me ha ocurrido ninguna traducción lógica), a lo que el agente responde con un (lógico) get-response.
Toda la información del agente se guarda en una base de datos denominada Management Information Base (MIB), formando una estructura de árbol, y presentada en forma de objetos, siendo la raíz el nodo .iso. Un ejemplo de una rama seria por ejemplo el siguiente:

system.sysContact.0 = "Ulandron"

Esto en realidad no es un buen ejemplo, porque no muestra toda la estructura del objeto, con todos los nodos descendiendo hasta el .iso Pero sirve para hacerse una idea de como funciona. El ejemplo especifica el objeto escalar .sysContact (escalar porque solo puede adoptar un valor en un determinado instante), del nodo system (el
system puede tener varios nodos, como serian el .sysName, el .sysLocation etc etc..), cuyo valor es "Ulandron". Al no tener un "." delante del system, se especifica que es
un nodo relativo, es decir, que se nos oculta una parte del nodo que es común a todos los objetos de ese sub-nodo, que seria el system. Esto usa una filosofía similar a la configuración de los Servidores de nombre, en los cuales puedes omitir el nombre de dominio si no terminas el nombre del host en punto, con lo que el dns lo completa automáticamente. Pero no me quiero ir por las ramas. Otros ejemplos de objetos pertenecientes al nodo system serian:

system.sysName.0 = "localhost" /* El nombre del host */
system.sysUpTime.0 = Timeticks: (45584) 0:07:35 /* El tiempo que lleva encendido */
system.sysDescr.0 = "Linux version 2.2.2 (root@localhost) (gcc versión 2.7.2.1) #5 SMP Tue Feb 16 22:44:54 CET 1999" /* La descripción */

Como puedes ver en todos se omite el "." al principio, con lo que el programa se encarga de anteponer el .iso.org.dod.internet....

Pasemos a otro tema: Como se decide quien puede y quien no puede ver/cambiar en esta base de datos llena de información útil. Inicialmente se usaba un método de autentificación (bastante gracioso por cierto) que se basaba en community strings. Esto son una especie de claves (sin nombre de usuario) que asignas a un determinado acto, que puede ser una de dos: leer o escribir a la MIB.
Es decir, una vez que habías adivinado el community string, tenias acceso total a la base de datos, pudiendo leer de la misma, cambiarla u hacer otras cosas interesantes que comentare en el siguiente apartado. Y lo mas gracioso es que el manager envía la clave al agente sin encriptar, en plain text, con lo que eso conlleva. Mas sobre SNMP sniffer en el proximo apartado.
Por cierto, los community strings por defecto son "public" y "private". Esto era así en el SNMPv1. Posteriormente en SNMPv2 se discutieron varios modelos de autentificación,
empezando con uno basado en listas de control de acceso, en el cual los derechos que tiene cada manager sobre el agente se basan es su dirección ip, en diversas claves de autentificación, en la acción solicitada por el manager (get o set), etc...
Pero una vez mas este modelo esta anticuado, y se ha pasado a otro modelo denominado USEC, User based Security Model, mejorando considerablemente la autentificación, control de acceso y privacidad de todo el sistema.


Utilidad practica
Estoy seguro que se ya se esta acabando tu paciencia en lo que a teoría respecta, y que tienes ganas de verle una utilidad practica a esto. Pues adelante, déjame introducirte en las aplicaciones practicas de todo este rollo.
Como ya he mencionado el snmp se basa en un servidor (agente), el snmpd, del que ya he hablado suficiente. Para el cliente existen varias herramientas. Normalmente un administrador de red tendrá su bonita interfaz grafica de Microsoft(r), con la que se
sentirá el rey y no tendrá ni que saber lo que significa SNMP, solo que con ese programita puede consultar datos de los hosts de su red, y en caso de que haya algún problema llamar al jodido loco que se encarga de administrar las maquinas esas raras que no traen ni portaminas por defecto, creo que se llamaban unix o algo asi. Brrrrr.

Pero como tu no eres uno de estos (ya que si no no hubieras leído hasta aquí), voy a pasar a comentar un poco algunos de los programas que se pueden usar para conocer mas sobre el protocolo y por consiguiente sobre la maquina que lo implementa.

Las utilidades básicas para trabajar con una MIB a la que tengas acceso, son las siguientes:

snmpget
Este programa sirve para obtener información de la base de datos, mediante las get-requests que he mencionado mas arriba.

snmpget [-p <puerto>] host community nombre-de-variable [variable]...
ej:

localhost:/root # snmpget localhost public system.sysContact.0
system.sysContact.0 = "Ulandron"

snmpset
Programa que se puede usar para modificar el contenido de la base de datos.
snmpset [-p puerto] [-d] [-r reintentos] [-t timeout] host
community nombre-de-variable tipo valor [variable tipo valor]...
opciones:
-p puerto -- especifica el puerto (161 por defecto)
-t timeout -- Tiempo de espera
-r reintentos-- Reintentos
-d -- Mostrar paquetes (dump)
Son posibles los siguientes tipos: i, s, x, d, n, o, t, a
i: INTEGER, s: STRING, x: HEX STRING, d: DECIMAL STRING
n: NULLOBJ, o: OBJID, t: TIMETICKS, a: IPADDRESS

ej:
localhost:/root # snmpget localhost public system.sysContact.0
system.sysContact.0 = "Ulandron"
localhost:/root # snmpset localhost public system.sysContact.0 s NiteBlade
system.sysContact.0 = "NiteBlade"
system.sysContact.0 = "NiteBlade"
localhost:/root # snmpget localhost public system.sysContact.0
system.sysContact.0 = "NiteBlade"

Estos datos además se guardan (al menos en mi implementación, CMU-SNMP) en
un archivo en el hosts, que en mi caso es el archivo de configuración: /etc/snmpd.conf

snmpwalk
Programa muy útil para examinar una base de datos, sin tener que pedir cada variable una a una.

snmpwalk [-p <puerto>] host community [variable]
ej:
localhost:/root # snmpwalk localhost public system
system.sysDescr.0 = "Linux version 2.2.1 (root@localhost) (gcc versión 2.7.2.1)
#5 SMP Tue Feb 16 22:44:54 CET 1999"
system.sysObjectID.0 = OID: enterprises.tubs.ibr.linuxMIB
system.sysUpTime.0 = Timeticks: (64074) 0:10:40
system.sysContact.0 = "Ulandron"
system.sysName.0 = "localhost"
....

snmpnetstat
snmpnetstat hostname community [-airsn] [-I interfaz] [-p protocolo] [intervalo]
opciones:
-a : información de todos los sockets
-i : idem de las interfaces
-r : Mostrar la tabla de enrutamiento
-s : Estadísticas ordenadas por protocolo
-n : Mostrar direcciones numéricas
ej:
localhost:/root # snmpnetstat localhost public -i
Name Mtu Network Address Ipkts Ierrs Opkts
lo0 3924 none none 3568576 25575 0
eth0 1500 none none 0 0 0
sit0* 1480 none none 0 0 0
.......

snmptest
Util para depurar problemas con el snmp

snmptest host community

ej:
localhost:/root # snmptest localhost public
Please enter the variable name: system.sysContact.0
Please enter the variable name:
Received GET RESPONSE from 127.0.0.1
requestid 0x2 errstat 0x0 errindex 0x0
system.sysContact.0 = "Ulandron"

Estas son las utilidades que vienen con la distribución del snmp por defecto, y que son suficientes si conoces el community string. El problema surge si desconoces dicho string, porque no podrás acceder a la base de datos. Para descubrirlo tienes muchas opciones:

Instalar un sniffer.
Si tienes acceso a la red puedes instalar un sniffer para snmp, siempre que el entorno te lo permita (smart switching hub's, etc.) y que se use el SNMPv1, ya que el v2 encripta la clave. Te preguntaras pq poner un sniffer para esto pudiendo instalar uno normal y corriente. Imagínate que usan ssh para el login, https para los servidores web, túneles seguros para pop, etc etc etc. Aunque si te encuentras a gente así, seria muy raro que descuidasen sus agentes de snmp, pero quien sabe. Por supuesto los sniffers sirven para depurar problemas con el snmp, y para aprender mas sobre el mismo.

Esto son el tipo de paquetes que genera el snmp (tcpdump).

17:19:41.232999 cloud.1042 > localhost.snmp: GetRequest(19)
.iso.org.dod[|snmp]
/* Cloud establece una conexion desde su puerto 1042 al agente snmp en el
puerto 161, mandando un getrequest */
17:19:41.233385 localhost.snmp > cloud.1042: GetResponse(17) [|snmp]
/* Localhost responde con un Getresponse, que contiene los datos pedidos, o
el erro correspondiente si no los puede facilitar por una razon u otra */

Otra manera es intentar adivinar el community string a lo bestia, para ello existe un un programa de ADM llamado ADMsnmp (original ehhh), al que le das un diccionario para que pruebe, ademas de crear variaciones del nombre del host para intentarlo. El programa tiene un pequeño efecto secundario desagradable, y es que si consigue conectar con el objetivo cambia el objeto system.sysName.0 a "ADMsnmp", lo cual da mucho el cante. El problema es un error en el fuente por lo que puedo ver. Si esto no es
asi ruego se me corrija. El parche esta al final del documento. También añade un "\n" a la ultima linea de la ayuda, queda mejor ;).


Por ultimo, para quien no le haya quedado claro la utilidad de todo esto: Mediante el snmp puedes obtener información valiosísima sobre un host, como son las interfaces de red, las tablas de encaminamiento, datos del sistema operativo, etc etc etc.
Puedes reiniciar la maquina, puedes cambiar las variables adaptándolas a tu propósito, ... Incluso en algunas situaciones puedes ejecutar programas en el host, con
lo que esto implica.