SNMP

Konzept

SNMP ist eigentlich zur Verwaltung ausgedehnter Netzwerke mit vielen Knoten gedacht. Über das SNMP-Protokoll kann man Daten über den Zustand eines Netzknotens abrufen, also beispielsweise über die Auslastung, den Datendurchsatz, etc. Mit einer geeigneten Software, beispielsweise HP OpenView, kann man sich ein ausgedehntes Netzwerk auch komplett visualisieren und dann gezielt auf einzelne Netzknoten “klicken”, um detaillierte Daten abzurufen. Aber auch im SOHO-Netzwerk kann man mit SNMP einige nützliche Dinge anstellen. Außerdem wird SNMP auch für mrtg benötigt.

Manche SNMP-fähigen Geräte können auch noch beim Auftreten bestimmter Bedingungen eine Nachricht an eine zentrale Station schicken. Man nennt dies einen Trap. Beispielsweise können Router eine Nachricht schicken, wenn eine Verbindung ausfällt.

Auf meinen Maschinen ist SNMP daher natürlich auch eingerichtet. Dabei werden Dienste auf Funktionsfähigkeit geprüft, Log-Dateien und die Maschinenauslastung überwacht, Verkehrsdaten erfasst und auch noch der angeschlossene WLAN-Router überwacht, der ebenfalls SNMP-fähig ist.

Weiterführende Informationen zum Thema SNMP gibt es bei Net-SNMP [1], bei Cisco [2] und natürlich bei Wikipedia [3]. Eine Übersicht von Standard-MIBs und OIDs findet sich bei ByteSphere [4] sowie auf [5] und [6].

Einrichtung des SNMP-Dienstes

Um SNMP einzurichten, muss das Paket net-snmp installiert werden. Dann führt man entweder das interaktive Skript snmpconf -g basic_setup aus, um eine erste Version der SNMP-Konfiguration zu erstellen oder man passt gleich die Datei /etc/snmp/snmpd.conf an, so wie sie hier abgedruckt ist. Eine Beispielkonfiguration mit verschiedenen Einstellungen findet sich auf [7].

###########################################################################
# SNMP-Konfiguration
#
# 05-Dec-2012 Gabriel Rüeck
#

rouser       public
rocommunity  public localhost
rocommunity  public 192.168.2.0/24
rocommunity  public 192.168.3.0/24
rocommunity  public 192.168.4.0/24

###########################################################################
# SECTION: System Information Setup
#

syslocation "中国110016 沈阳市和平区文体路"
syscontact  "Gabriel Rüeck <gabriel@caipirinha.homelinux.org>"
sysservices 78

###########################################################################
# SECTION: Monitor Various Aspects of the Running Host
#

#   The results are reported in the dskTable section.

disk  /                   30%
disk  /home               10%
disk  /home/public/Video   5%
disk  /var                20%
disk  /backup             10%

#   The results are reported in the fileTable section

file  /var/log/messages   100000
file  /var/log/warn       100000

#   The results are reported in the laTable section.

load  15  10  10

#   The results are reported in the prTable section.

proc  amavisd          3  1
proc  apcupsd          1  1
proc  atd              1  1
proc  authdaemond     10  1
proc  clamd            1  1
proc  couriertcpd      2  2
proc  cron             4  1
proc  cupsd            1  1
proc  dhcpd            1  1
proc  fail2ban-server  1  1
proc  famd             1  1
proc  freshclam        1  1
proc  httpd2-prefork  50  1
proc  icecast         10  1
proc  master           1  1
proc  mdadm            1  1
proc  minidlna         5  1
proc  mrtg             1  1
proc  mysqld           2  1
proc  named            1  1
proc  nmbd             1  1
proc  ntpd             1  1
proc  openvpn          6  5
proc  pure-ftpd        1  1
proc  rsyncd           5  1
proc  rsyslogd         1  1
proc  saslauthd        1  1
proc  sensord          1  1
proc  smartd           1  1
proc  smbd            20  1
proc  sshd            20  1
proc  tlsmgr           1  1

###########################################################################
# SECTION: Custom Programs
#

exec  mbox_gabriel  /root/bin/mailsize.sh  gabriel
exec  mbox_joselia  /root/bin/mailsize.sh  joselia
exec  bw_rueeck     /root/bin/bandwidth.sh rueeck.name
exec  bw_caipiroska /root/bin/bandwidth.sh caipiroska.homelinux.org
exec  ping_gw0      /root/bin/pingtimes.sh gw0
exec  ping_tun0     /root/bin/pingtimes.sh tun0
exec  ping_gw1      /root/bin/pingtimes.sh gw1
exec  ping_tun1     /root/bin/pingtimes.sh tun1
exec  ping_gw2      /root/bin/pingtimes.sh gw2
exec  ping_tun2     /root/bin/pingtimes.sh tun2
exec  vpn_tun0_r    /root/bin/vpn_traffic.sh tun0 read
exec  vpn_tun0_w    /root/bin/vpn_traffic.sh tun0 write
exec  vpn_tun1_r    /root/bin/vpn_traffic.sh tun1 read
exec  vpn_tun1_w    /root/bin/vpn_traffic.sh tun1 write
exec  vpn_tun2_r    /root/bin/vpn_traffic.sh tun2 read
exec  vpn_tun2_w    /root/bin/vpn_traffic.sh tun2 write

###########################################################################
# SECTION: Trap Destinations
#

authtrapenable  2
iquerySecName   public
createUser      public MD5 auth_pwd_local DES crypto_pwd_local
#trap2sink       localhost public
informsink      localhost public
#trapsess        -Ci -v3 -u public -a MD5 -A auth_pwd_trap -x DES -X crypto_pwd_trap -l authPriv localhost

monitor -o prNames  -o prErrMessage "process table" prErrorFlag   != 0
monitor -o dskPath  -o dskErrorMsg  "dskTable"      dskErrorFlag  != 0
monitor -o laNames  -o laErrMessage "laTable"       laErrorFlag   != 0
monitor -o fileName -o fileErrorMsg "fileTable"     fileErrorFlag != 0

Den Community-Namen public sollte man aus Sicherheitsgründen durch einen selbst gewählten Namen ersetzen. Dieser muss dann aber bei allen SNMP-Knoten im Netzwerk gleich gewählt werden. Gleichermaßen müssen auth_pwd_local und crypto_pwd_local durch möglichst komplexe Passworte ersetzt werden. Diese Passworte dienen zur Authentifizierung (auth_pwd_local) und zur Verschlüsselung (crypto_pwd_local) beim Zugriff auf SNMP-Daten, wenn SNMP in der Version 3 (SNMPv3) zum Einsatz kommt.

Die hier gezeigte Konfigurationsdatei /etc/snmp/snmpd.conf gliedert sich in fünf Teile und beinhaltet Konfigurationsanweisungen sowohl für SNMPv2 als auch für SNMPv3. Im ersten Teil werden die Zugriffsberechtigungen festgelegt; aus Sicherheitsgründen sind diese auf reine Lesezugriffe vom Server selbst und aus dem SOHO-Netzwerk beschränkt. Dort sind 3 Netzwerke angegeben, weil der Caipirinha-Server über mehrere VPNs mit verschiedenen Netzwerken verbunden ist oder selbst über VPN-Dienste anbietet. Weiterhin wird für SNMPv3 ein Benutzername (hier: public) angelegt. SNMPv3 kennt verschiedene Sicherheitsmechanismen, welche man sich mit man 5 snmpd.conf vergegenwärtigen kann. Als Standard wird beim Zugriff auf SNMP-Daten über SNMPv3 zumindest Authentifizierung verlangt. Verschlüsselung ist optional.

Im zweiten Abschnitt sind die Kontaktdaten für den Administrator des Caipirinha-Servers und der Maschinenstandort angegeben. Diese Daten erleichtern bei einem umfangreichen Netzwerk die Lokalisierung von Ansprechpartnern, wenn Probleme auf der Maschine auftreten. Der Wert bei sysservices spiegelt die Fähigkeiten des Netzknotens wieder. Details zur Berechnung dieses Wertes finden sich auf [8].

Der dritten Abschnitt selbst gliedert sich in drei Unterabschnitte, in denen verschiedene Kenngrößen überwacht werden. Sobald eine Kenngröße in eine kritische Richtung durchschritten wird, wird eine Mitteilung an den snmptrapd geschickt.

  • Bei den angegebenen Partitionen ist der kritische Augenblick das Unterschreiten des angegeben Mindest-Prozentsatzes an freiem Speicher.
  • Bei den angegebenen Log-Dateien ist der kritische Augenblick das Überschreiten der Größe. Der angegebene Zahlenwert bezieht sich auf kB als Einheit.
  • Bei der Maschinenlast ist der kritische Augenblick das Überschreiten der angegebenen Grenzen. Die drei Werte entsprechen den Zeitintervallen der letzten Minute, der letzten 5 Minuten und der letzten 15 Minuten.
  • Bei den Prozessen ist die erste angegebene Zahl der zulässige Maximalwert und die zweite angegebene Zahl der zulässige Minimalwert. Ein Überschreiten des Maximalwertes oder ein Unterschreiten des Minimalwertes setzt ein Fehler-Flag und in der abgedruckten Konfiguration auch dazu, dass ein Trap geschickt wird. Der snmptrap-Dienst wird daraus eine E-Mail erzeugen und an den Systemadministrator schicken. Es macht natürlich nur Sinn, hier solche Prozesse beobachten zu lassen, die eigentlich ununterbrochen laufen sollen.

Im vierten Abschnitt sind Skripte angegeben, die aus dem SNMP-Dienst heraus mit festzulegenden Argumenten aufgerufen werden können. Jeder Aufruf selbst bekommt auch noch einen Namen (beispielsweise mbox_gabriel oder mbox_joselia). Die hier erwähnten Shell-Skripte mailsize.sh, bandwidth.sh, pingtimes.sh und vpn_traffic.sh sind in Admin-Skripte dokumentiert.

Im fünften Abschnitt sind schließlich die Daten für den snmptrapd angegeben. Man erkennt mehrere Schlüsselworte. Mit authtrapenable werden versuchte SNMP-Abfragen mit einem fehlerhaften Login entweder an den snmptrapd geschickt (authtrapenable 1) oder eben nicht (authtrapenable 2). Mit iquerySecName wird der SNMPv3-Benutzername festgelegt, unter dem die Abfragen beim snmpd durchgeführt werden. Dieser Name muss gleich dem unter dem Schlüsselwort rouser angegebenen Benutzernamen sein. Mit createUser werden die Algorithmen und die Passworte zur Authentifizierung (auth_pwd_local) und zur Verschlüsselung (crypto_pwd_local) beim Zugriff mit dem entsprechenden SNMPv3-Benutzernamen auf lokale SNMP-Daten festgelegt. Man kann das Verschlüsselungspasswort (crypto_pwd_local) auch weglassen und die Authentifizierung und Verschlüsselung mit dem gleichen Passwort (in diesem Fall dann auth_pwd_local) durchführen. In diesem Fall muss die createUser-Anweisung so lauten:

createUser      public MD5 auth_pwd_local DES crypto_pwd_local

Das Schlüsselwort trap2sink gibt das Ziel und den SNMPv2-Community-Namen an, an den die Traps geschickt werden. Achtung, hier wird SNMPv2 benutzt, während die Abfrage der SNMP-Werte beim snmpd mit SNMPv3 läuft! trap2sink ist hier allerdings auskommentiert, zu Gunsten von informsink. Durch informsink wird kein Trap, sondern eine Inform-Mitteilung an den snmptrapd geschickt. Das hat den Vorteil, dass der snmptrapd den Erhalt der Mitteilung bestätigt. Laufen sowohl snmpd als auch snmptrapd auf der gleichen Maschine, ist das unwichtig. Ist aber der snmptrapd auf einer entfernten Maschine, ist informsink eindeutig die bessere Wahl, denn so vermeidet man, dass die UDP-Pakete eines Trap verloren gehen können. Man kann bei beiden Schlüsselworten sowohl eine lokale als auch eine entfernte Maschine angeben. Beim Caipirinha-Server und Caipiroska-Server laufen die snmptrapd auf den gleichen Maschinen. Damit kann auch ein Trap gesendet werden, wenn die Netzwerkverbindung gerade down ist. In einem lokalen Netz, bei dem man sich sicher ist, dass die Verbindungen immer up sind, kann man den snmptrapd auch auf einer Maschine zentralisieren und von dort aus das gesamte Netzwerk überwachen.

Die vier monitor-Anweisungen legen fest, dass beim Auftreten einer Fehlerbedingung ein Trap zu schicken ist. Die entsprechende Syntax habe ich direkt aus man 5 snmpd.conf heraus kopiert. Man hätte auch die Anweisung defaultMonitors yes benutzen können, aber diese beinhaltet noch weitere Prüfungen, die ich hier nicht haben wollte.

Mit dem Schlüsselwort trapsess kann man Traps und Informs auch über SNMPv3 zu einem snmptrapd auf einer lokalen oder entfernten Maschine schicken. Im falle einer entfernten Maschine muss man localhost durch den Maschinennamen oder die IP-Adresse ersetzen. Die Parameter public, auth_pwd_trap und crypto_pwd_trap müssen denen des snmptrapd entsprechen. Mit dieser Konfiguration wird die Nachricht vom snmpd zum snmptrapd dann sowohl an einen gültigen Login gebunden als auch verschlüsselt. Die Option -Ci legt fest, dass eine Inform-Mitteilung geschickt wird. Fehlt diese Option, wird lediglich eine (unbestätigte) Trap-Mitteilung geschickt.

Zum Vergleich ist hier eine Konfigurationsdatei angegeben, bei der Inform-Mittelungen an eine entfernte Maschine geschickt werden:

###########################################################################
# SNMP-Konfiguration
#
# 05-Dec-2012 Gabriel Rüeck
#

rouser       public
rocommunity  public localhost
rocommunity  public 124.95.128.109/32

###########################################################################
# SECTION: System Information Setup
#

syslocation "辽宁省沈阳市"
syscontact  "Gabriel Rüeck <gabriel@rueeck.de>"
sysservices 78

###########################################################################
# SECTION: Monitor Various Aspects of the Running Host
#

#   The results are reported in the dskTable section.

disk  /                    50%
disk  /home                10%
disk  /tmp                 20%
disk  /var                 20%

#   The results are reported in the fileTable section

file  /var/log/messages    50000
file  /var/log/warn        50000

#   The results are reported in the laTable section.

load  5  3  1

#   The results are reported in the prTable section.

proc  atd               1  1
proc  clamd             1  1
proc  cron              4  1
proc  fail2ban-server   1  1
proc  famd              1  1
proc  freshclam         1  1
proc  httpd2-prefork  600  1
proc  master            1  1
proc  mdadm             1  1
proc  mrtg              1  1
proc  mysqld            2  1
proc  named             1  1
proc  ntpd              1  1
proc  openvpn           2  1
proc  rsyncd            5  1
proc  rsyslogd          1  1
proc  sensord           1  1
proc  smartd            1  1
proc  sshd             20  1

###########################################################################
# SECTION: Custom Programs
#

exec  bw_rueeck     /root/bin/bandwidth.sh rueeck.name
exec  bw_caipiroska /root/bin/bandwidth.sh caipiroska.homelinux.org

###########################################################################
# SECTION: Trap Destinations
#

authtrapenable  1
iquerySecName   public
createUser      public MD5 auth_pwd_local DES crypto_pwd_local
#informsink      caipirinha.homelinux.org public
trapsess        -Ci -v3 -u public -a MD5 -A auth_pwd_trap -x DES -X crypto_pwd_trap -l authPriv caipirinha.homelinux.org

monitor -o prNames  -o prErrMessage "process table" prErrorFlag   != 0
monitor -o dskPath  -o dskErrorMsg  "dskTable"      dskErrorFlag  != 0
monitor -o laNames  -o laErrMessage "laTable"       laErrorFlag   != 0
monitor -o fileName -o fileErrorMsg "fileTable"     fileErrorFlag != 0

Nach der Anpassung der Konfigurationsdatei /etc/snmp/snmpd.conf muss man noch den snmpd noch starten. Eigentlich geschieht dies ja mit /etc/init.d/snmpd start. Allerdings liest der snmpd beim Start gleich alle möglichen Konfigurationsdateien aus unterschiedlichen Verzeichnissen ein (siehe man 5 snmp_config). Das ist eine böse Falle, die mich viel Zeit gekostet hat. So werden unter anderem existierende SNMPv3-Benutzerdaten aus /var/lib/net-snmp/snmpd.conf eingelesen, die dann die Einstellungen aus der aktuellen Konfigurationsdatei zunichte machen. Deshalb sollte man nach dem Anpassen der Konfigurationsdatei den snmpd mit snmpd -C -c /etc/snmp/snmpd.conf unter alleiniger Berücksichtigung dieser Konfigurationsdatei neu starten. In diesem Fall werden dann die SNMPv3-Benutzer in /var/lib/net-snmp/snmpd.conf von der Konfigurationsdatei /etc/snmp/snmpd.conf übernommen.

Einrichtung des SNMPTRAP-Dienstes

Wie bereits erwähnt, läuft auf meinen Maschinen nicht nur der snmpd, sondern auch noch der snmptrapd. Der Caipirinha-Server [9] ist damit zugleich Quelle von SNMP-Mitteilungen, die den Server selbst betreffen als auch zentrale Station zur Aufnahme aller Meldungen von Geräten aus dem entsprechenden lokalen Netz. Es handelt sich also bei snmptrapd um einen eigenständigen Dienst, der auf Port 162/udp auf eingehende Mitteilungen von SNMP-Agenten wartet.

Auch für den snmptrapd gibt es eine Konfigurationsdatei, nämlich /etc/snmp/snmptrapd.conf. Diese ist hier abgedruckt:

###########################################################################
# SNMPTRAP-Konfiguration
#
# 30-Nov-2012 Gabriel Rüeck
#

# donotfork: Do not fork from the shell
#   arguments: (1|yes|true|0|no|false)
doNotFork      no

# pidfile: Store Process ID in file
#   arguments: PID file
pidFile  /var/run/snmptrapd.pid

# ignoreauthfailure: Ignore authentication failure traps
#   arguments: (1|yes|true|0|no|false)
ignoreAuthFailure  yes

authCommunity    log,execute  public
authUser         log,execute  public
authUser         log,execute  public_2
createUser       public MD5 auth_pwd_trap DES crypto_pwd_trap
createUser       public_2 MD5 auth_pwd_trap_2 DES crypto_pwd_trap_2

traphandle default /usr/bin/traptoemail -f "System Administrator <root@caipirinha.homelinux.org>" root@caipirinha.homelinux.org

format1  %04.4y-%02.2m-%02.2l %02.2h:%02.2j From %B: %W \n
format2  %04.4y-%02.2m-%02.2l %02.2h:%02.2j From %B: %W \n

Auch hier muss der Community-Name public durch den im gesamten Netzwerk einheitlich benutzten Community-Namen ersetzt werden. Mit authUser und createUser wird ein SNMPv3-Benutzer angelegt. auth_pwd_trap ist das Passwort zur Authentifizierung beim snmptrapd, und crypto_pwd_trap ist das Passwort zum Verschlüsseln der Daten. MD5 ist der bei der Authentifizierung zum Einsatz kommende Algorithmus, und DES kommt bei der Verschlüsselung zum Einsatz. auth_pwd_trap und crypto_pwd_trap müssen gleich sein wie bei der Konfiguration des snmpd auf einer Maschine, die diesem snmptrapd einen Trap oder eine Inform-Mitteilung schicken will. Auch hier kann man das Verschlüsselungspasswort (crypto_pwd_trap) weglassen und die Authentifizierung und Verschlüsselung mit dem gleichen Passwort (in diesem Fall dann auth_pwd_trap) durchführen. In diesem Fall muss die createUser-Anweisung so lauten:

createUser      public MD5 auth_pwd_trap DES

Es ist auch möglich, mehrere SNMPv3-Benutzer anzulegen. Im Beispiel hier wurde mit public_2, auth_pwd_trap_2 und crypto_pwd_trap_2 ein zweiter SNMPv3-Benutzer angelegt, der diesem snmptrapd Mitteilungen schicken kann. Dies macht dann Sinn, wenn der snmptrapd Traps von unterschiedlichen Maschinen in Empfang nehmen soll, bei denen aber die jeweiligen Administratoren nichts von den Logins der anderen Maschinen wissen sollen. Man könnte natürlich auch generell für den snmptrapd einen ganz anderen SNMPv3-Benutzer nehmen, der nichts mit irgendeinem SNMPv3-Benutzer auf einer der Maschinen zu tun hat. Dies wäre ohne Zweifel die sicherste Lösung.

Die Anweisung traphandle legt fest, was beim Auftreten eines Traps zu tun ist. In diesem Fall wird eine E-Mail an root geschickt. format1 und format2 legen das Format für SNMPv1-Traps und SNMPv2/SNMPv3-Traps fest. Ich habe hier noch ein Format für SNMPv1 festgelegt, obwohl SNMPv1 nun inzwischen wirklich aus der Mode kommt, weil einige einfachen Router tatsächlich auch heute nur SNMPv1 beherrschen.

Es gibt für die Konfigurationsdatei auch eine Anweisung logOption, mit dem man in der Konfigurationsdatei einstellen können sollte, wohin die Meldungen geloggt werden sollen. Allerdings funktioniert diese bei OpenSuSE 11.4 nicht, und wenn man snmptrapd -H aufruft, kommt ja auch eine entsprechende Meldung, die besagt, lass kein Log-Handling aktiv ist. Alle Mitteilungen werden daher leider nach /var/log/messages geschrieben, ob man das will oder nicht. Beim Caipiroska-Server [10] sieht das dann beispielsweise so aus:

Nov 26 07:40:49 caipiroska snmptrapd[18445]: localhost [UDP: [127.0.0.1]:56402->[127.0.0.1]:162]: Trap , DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (22) 0:00:00.22, SNMPv2-MIB::snmpTrapOID.0 = OID: DISMAN-EVENT-MIB::mteTriggerFired, DISMAN-EVENT-MIB::mteHotTrigger.0 = STRING: process table, DISMAN-EVENT-MIB::mteHotTargetName.0 = STRING: , DISMAN-EVENT-MIB::mteHotContextName.0 = STRING: , DISMAN-EVENT-MIB::mteHotOID.0 = OID: UCD-SNMP-MIB::prErrorFlag.24, DISMAN-EVENT-MIB::mteHotValue.0 = INTEGER: 1, UCD-SNMP-MIB::prNames.24 = STRING: smbd, UCD-SNMP-MIB::prErrMessage.24 = STRING: No smbd process running
Nov 26 07:40:49 caipiroska snmptrapd[18445]: localhost [UDP: [127.0.0.1]:56402->[127.0.0.1]:162]: Trap , DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (23) 0:00:00.23, SNMPv2-MIB::snmpTrapOID.0 = OID: DISMAN-EVENT-MIB::mteTriggerFired, DISMAN-EVENT-MIB::mteHotTrigger.0 = STRING: dskTable, DISMAN-EVENT-MIB::mteHotTargetName.0 = STRING: , DISMAN-EVENT-MIB::mteHotContextName.0 = STRING: , DISMAN-EVENT-MIB::mteHotOID.0 = OID: UCD-SNMP-MIB::dskErrorFlag.3, DISMAN-EVENT-MIB::mteHotValue.0 = INTEGER: 1, UCD-SNMP-MIB::dskPath.3 = STRING: /home/public/Video, UCD-SNMP-MIB::dskErrorMsg.3 = STRING: /home/public/Video: less than 5% free (= 100%)

Die erste Meldung sagt aus, dass kein smbd-Prozess läuft. Die zweite Meldung sagt aus, dass auf der Partition /home/public/Video weniger als 5% freier Festplattenspeicher ist. Der snmptrapd schickt auch entsprechende E-Mails, und die zu den zwei Meldungen gehörenden E-Mails haben genau den gleichen Inhalt, wie man hier erkennen kann:

Host: localhost (UDP: [127.0.0.1]:56402->[127.0.0.1]:162)
  DISMAN-EVENT-MIB::sysUpTimeInstance  0:0:00:00.22
            SNMPv2-MIB::snmpTrapOID.0  DISMAN-EVENT-MIB::mteTriggerFired
    DISMAN-EVENT-MIB::mteHotTrigger.0  process table
 DISMAN-EVENT-MIB::mteHotTargetName.0  
DISMAN-EVENT-MIB::mteHotContextName.0  
        DISMAN-EVENT-MIB::mteHotOID.0  UCD-SNMP-MIB::prErrorFlag.24
      DISMAN-EVENT-MIB::mteHotValue.0  1
             UCD-SNMP-MIB::prNames.24  smbd
        UCD-SNMP-MIB::prErrMessage.24  No smbd process running
Host: localhost (UDP: [127.0.0.1]:56402->[127.0.0.1]:162)
  DISMAN-EVENT-MIB::sysUpTimeInstance  0:0:00:00.23
            SNMPv2-MIB::snmpTrapOID.0  DISMAN-EVENT-MIB::mteTriggerFired
    DISMAN-EVENT-MIB::mteHotTrigger.0  dskTable
 DISMAN-EVENT-MIB::mteHotTargetName.0  
DISMAN-EVENT-MIB::mteHotContextName.0  
        DISMAN-EVENT-MIB::mteHotOID.0  UCD-SNMP-MIB::dskErrorFlag.3
      DISMAN-EVENT-MIB::mteHotValue.0  1
              UCD-SNMP-MIB::dskPath.3  /home/public/Video
          UCD-SNMP-MIB::dskErrorMsg.3  /home/public/Video: less than 5% free (= 100%)

Durch den E-Mail-Mechanismus kann man sich als Systemadministrator daher direkt informieren lassen, wenn auf einem der Server etwas aus dem Ruder läuft. Das ist eine sehr praktische Sache, insbesondere, wenn man eine solche E-Mail gleich noch auf dem Smartphone empfangen kann.

SNMP-Konfiguration bei einem WLAN-Router
SNMP-Konfiguration bei einem WLAN-Router

Der snmptrapd muss über das Kommando snmptrapd gestartet werden. Es ist leider nicht möglich, einen automatischen Start über den Runlevel-Editor einzustellen. Dies wird auf dem Caipirinha-Server im Rahmen eines Skripts durchgeführt, welches der Systemadministrator nach dem Start des Systems ausführen muss. Wie beim spnmd sollte man den snmptrapd nach dem Ändern der Konfigurationsdatei mit snmptrapd -C -c /etc/snmp/snmptrapd.conf starten, weil auch der snmptrapd beim Start mehrere Konfigurationsdateien aus unterschiedlichen Verzeichnissen einliest (siehe man 5 snmp_config), unter anderem aus /var/lib/net-snmp/snmptrapd.conf.

Konfiguration von SNMP bei DSL-Routern

Oft ist es möglich, selbst bei SOHO-Routern SNMP zu konfigurieren; das nebenstehende Bild zeigt, wie man dies bei der “EasyBox 602” von Vodafone macht. Trägt man dort die IP-Adresse des Caipiroska-Servers im Heimnetzwerk ein und konfiguriert den Community-Namen korrekt, so kann der DSL-Router Traps an den Caipiroska-Server schicken, beispielsweise, wenn die DSL-Verbindung wegen des in Deutschland einmal am Tag stattfindenden IP-Adresswechsels kurzzeitig zusammenbricht. Dann bekommt man mindestens einen Trap mit der “Line down”-Information und einen mit der “Line up”-Information, üblicherweise kurze Zeit danach. Man erkennt hier auch, dass es Sinn macht, einen snmptrapd im Heimnetz laufen zu lassen und nicht auf eine entfernte Maschine zu verweisen, die ja dann nicht verfügbar ist, wenn die DSL-Verbindung gerade zusammengebrochen ist. Bei der von snmptrapd erzeugten E-Mail wird dagegen vom smtpd über einen längeren Zeitraum hinweg mehrmals eine Zustellung versucht.

Beispiele für SNMP-Abfragen

Einen ersten Überblick über die SNMP-Variablen einer Maschine verschafft man sich mit snmpwalk -v2c -cpublic localhost oder, wenn SNMPv3 zum Einsatz kommen soll, mit snmpwalk -v3 -u public -l authNoPriv -a MD5 -A auth_pwd_local localhost. Die Option authNoPriv besagt, dass hier zwar eine Authentifizierung durchgeführt wird, aber keine Verschlüsselung der Daten, die übertragen werden. Leider habe ich mit der Option authPriv und der Angabe des crypto_pwd_local nur eine Fehlermeldung bekommen.

Die Ausgabe dieser Abfrage kann jedenfalls zu einer recht langen Liste führen.

System-Statistiken kann man sich mit snmpwalk -v2c -cpublic localhost .1.3.6.1.4.1.2021.11 bzw. snmpwalk -v3 -u public -l authNoPriv -a MD5 -A auth_pwd_local localhost .1.3.6.1.4.1.2021.11 anzeigen lassen [11], [12]. Dies liefert beispielsweise:

UCD-SNMP-MIB::ssIndex.0 = INTEGER: 1
UCD-SNMP-MIB::ssErrorName.0 = STRING: systemStats
UCD-SNMP-MIB::ssSwapIn.0 = INTEGER: 0 kB
UCD-SNMP-MIB::ssSwapOut.0 = INTEGER: 0 kB
UCD-SNMP-MIB::ssIOSent.0 = INTEGER: 353 blocks/s
UCD-SNMP-MIB::ssIOReceive.0 = INTEGER: 0 blocks/s
UCD-SNMP-MIB::ssSysInterrupts.0 = INTEGER: 537 interrupts/s
UCD-SNMP-MIB::ssSysContext.0 = INTEGER: 796 switches/s
UCD-SNMP-MIB::ssCpuUser.0 = INTEGER: 0
UCD-SNMP-MIB::ssCpuSystem.0 = INTEGER: 1
UCD-SNMP-MIB::ssCpuIdle.0 = INTEGER: 95
UCD-SNMP-MIB::ssCpuRawUser.0 = Counter32: 7043838
UCD-SNMP-MIB::ssCpuRawNice.0 = Counter32: 1157149
UCD-SNMP-MIB::ssCpuRawSystem.0 = Counter32: 5023506
UCD-SNMP-MIB::ssCpuRawIdle.0 = Counter32: 147653397
UCD-SNMP-MIB::ssCpuRawWait.0 = Counter32: 9671287
UCD-SNMP-MIB::ssCpuRawKernel.0 = Counter32: 0
UCD-SNMP-MIB::ssCpuRawInterrupt.0 = Counter32: 352
UCD-SNMP-MIB::ssIORawSent.0 = Counter32: 1866410120
UCD-SNMP-MIB::ssIORawReceived.0 = Counter32: 2797478450
UCD-SNMP-MIB::ssRawInterrupts.0 = Counter32: 597294992
UCD-SNMP-MIB::ssRawContexts.0 = Counter32: 1239253106
UCD-SNMP-MIB::ssCpuRawSoftIRQ.0 = Counter32: 338170
UCD-SNMP-MIB::ssRawSwapIn.0 = Counter32: 0
UCD-SNMP-MIB::ssRawSwapOut.0 = Counter32: 0

Angaben über Partitionen und dere Auslastung bekommt man mit snmpwalk -v2c -cpublic localhost .1.3.6.1.4.1.2021.9 bzw. snmpwalk -v3 -u public -l authNoPriv -a MD5 -A auth_pwd_local localhost .1.3.6.1.4.1.2021.9 [13], [14]. Auf dem Caipirinha-Server ergibt dies dann:

UCD-SNMP-MIB::dskIndex.1 = INTEGER: 1
UCD-SNMP-MIB::dskIndex.2 = INTEGER: 2
UCD-SNMP-MIB::dskIndex.3 = INTEGER: 3
UCD-SNMP-MIB::dskIndex.4 = INTEGER: 4
UCD-SNMP-MIB::dskIndex.5 = INTEGER: 5
UCD-SNMP-MIB::dskPath.1 = STRING: /
UCD-SNMP-MIB::dskPath.2 = STRING: /home
UCD-SNMP-MIB::dskPath.3 = STRING: /home/public/Video
UCD-SNMP-MIB::dskPath.4 = STRING: /var
UCD-SNMP-MIB::dskPath.5 = STRING: /backup
UCD-SNMP-MIB::dskDevice.1 = STRING: rootfs
UCD-SNMP-MIB::dskDevice.2 = STRING: /dev/mapper/cr_md2
UCD-SNMP-MIB::dskDevice.3 = STRING: /dev/md3
UCD-SNMP-MIB::dskDevice.4 = STRING: /dev/mapper/cr_md1
UCD-SNMP-MIB::dskDevice.5 = STRING: /dev/mapper/cr_sde1
...
UCD-SNMP-MIB::dskMinPercent.1 = INTEGER: 30
UCD-SNMP-MIB::dskMinPercent.2 = INTEGER: 10
UCD-SNMP-MIB::dskMinPercent.3 = INTEGER: 5
UCD-SNMP-MIB::dskMinPercent.4 = INTEGER: 20
UCD-SNMP-MIB::dskMinPercent.5 = INTEGER: 10
UCD-SNMP-MIB::dskTotal.1 = INTEGER: 51612944
UCD-SNMP-MIB::dskTotal.2 = INTEGER: 901563648
UCD-SNMP-MIB::dskTotal.3 = INTEGER: 2147483647
UCD-SNMP-MIB::dskTotal.4 = INTEGER: 8253744
UCD-SNMP-MIB::dskTotal.5 = INTEGER: 1922857728
UCD-SNMP-MIB::dskAvail.1 = INTEGER: 37133060
UCD-SNMP-MIB::dskAvail.2 = INTEGER: 622951360
UCD-SNMP-MIB::dskAvail.3 = INTEGER: 922618048
UCD-SNMP-MIB::dskAvail.4 = INTEGER: 2117264
UCD-SNMP-MIB::dskAvail.5 = INTEGER: 1687921664
UCD-SNMP-MIB::dskUsed.1 = INTEGER: 11858084
UCD-SNMP-MIB::dskUsed.2 = INTEGER: 232815424
UCD-SNMP-MIB::dskUsed.3 = INTEGER: 2147483647
UCD-SNMP-MIB::dskUsed.4 = INTEGER: 5717212
UCD-SNMP-MIB::dskUsed.5 = INTEGER: 234936064
UCD-SNMP-MIB::dskPercent.1 = INTEGER: 24
UCD-SNMP-MIB::dskPercent.2 = INTEGER: 27
UCD-SNMP-MIB::dskPercent.3 = INTEGER: 76
UCD-SNMP-MIB::dskPercent.4 = INTEGER: 73
UCD-SNMP-MIB::dskPercent.5 = INTEGER: 12
...
UCD-SNMP-MIB::dskErrorFlag.1 = INTEGER: noError(0)
UCD-SNMP-MIB::dskErrorFlag.2 = INTEGER: noError(0)
UCD-SNMP-MIB::dskErrorFlag.3 = INTEGER: noError(0)
UCD-SNMP-MIB::dskErrorFlag.4 = INTEGER: noError(0)
UCD-SNMP-MIB::dskErrorFlag.5 = INTEGER: noError(0)
UCD-SNMP-MIB::dskErrorMsg.1 = STRING:
UCD-SNMP-MIB::dskErrorMsg.2 = STRING:
UCD-SNMP-MIB::dskErrorMsg.3 = STRING:
UCD-SNMP-MIB::dskErrorMsg.4 = STRING:
UCD-SNMP-MIB::dskErrorMsg.5 = STRING:

Einen Überblick über die Interfaces an einer Maschine bekommt man mit snmpwalk -v2c -cpublic localhost .1.3.6.1.2.1.2.2.1 bzw. snmpwalk -v3 -u public -l authNoPriv -a MD5 -A auth_pwd_local localhost .1.3.6.1.2.1.2.2.1 [15]. Dies liefert als Ausgabe auf dem Caipirinha-Server:

IF-MIB::ifIndex.1 = INTEGER: 1
IF-MIB::ifIndex.2 = INTEGER: 2
IF-MIB::ifIndex.3 = INTEGER: 3
IF-MIB::ifIndex.68 = INTEGER: 68
IF-MIB::ifIndex.70 = INTEGER: 70
IF-MIB::ifIndex.72 = INTEGER: 72
IF-MIB::ifIndex.73 = INTEGER: 73
IF-MIB::ifIndex.74 = INTEGER: 74
IF-MIB::ifDescr.1 = STRING: lo
IF-MIB::ifDescr.2 = STRING: eth0
IF-MIB::ifDescr.3 = STRING: eth1
IF-MIB::ifDescr.68 = STRING: tun2
IF-MIB::ifDescr.70 = STRING: tun0
IF-MIB::ifDescr.72 = STRING: tun1
IF-MIB::ifDescr.73 = STRING: tun4
IF-MIB::ifDescr.74 = STRING: tun3
...
IF-MIB::ifMtu.1 = INTEGER: 16436
IF-MIB::ifMtu.2 = INTEGER: 1500
IF-MIB::ifMtu.3 = INTEGER: 1500
IF-MIB::ifMtu.68 = INTEGER: 1500
IF-MIB::ifMtu.70 = INTEGER: 1500
IF-MIB::ifMtu.72 = INTEGER: 1500
IF-MIB::ifMtu.73 = INTEGER: 1500
IF-MIB::ifMtu.74 = INTEGER: 1500
IF-MIB::ifSpeed.1 = Gauge32: 10000000
IF-MIB::ifSpeed.2 = Gauge32: 1000000000
IF-MIB::ifSpeed.3 = Gauge32: 10000000
IF-MIB::ifSpeed.68 = Gauge32: 0
IF-MIB::ifSpeed.70 = Gauge32: 0
IF-MIB::ifSpeed.72 = Gauge32: 0
IF-MIB::ifSpeed.73 = Gauge32: 0
IF-MIB::ifSpeed.74 = Gauge32: 0
...
IF-MIB::ifAdminStatus.1 = INTEGER: up(1)
IF-MIB::ifAdminStatus.2 = INTEGER: up(1)
IF-MIB::ifAdminStatus.3 = INTEGER: down(2)
IF-MIB::ifAdminStatus.68 = INTEGER: up(1)
IF-MIB::ifAdminStatus.70 = INTEGER: up(1)
IF-MIB::ifAdminStatus.72 = INTEGER: up(1)
IF-MIB::ifAdminStatus.73 = INTEGER: up(1)
IF-MIB::ifAdminStatus.74 = INTEGER: up(1)
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
IF-MIB::ifOperStatus.2 = INTEGER: up(1)
IF-MIB::ifOperStatus.3 = INTEGER: down(2)
IF-MIB::ifOperStatus.68 = INTEGER: up(1)
IF-MIB::ifOperStatus.70 = INTEGER: up(1)
IF-MIB::ifOperStatus.72 = INTEGER: up(1)
IF-MIB::ifOperStatus.73 = INTEGER: up(1)
IF-MIB::ifOperStatus.74 = INTEGER: up(1)
...
IF-MIB::ifInOctets.1 = Counter32: 123922180
IF-MIB::ifInOctets.2 = Counter32: 2916738370
IF-MIB::ifInOctets.3 = Counter32: 0
IF-MIB::ifInOctets.68 = Counter32: 3764554219
IF-MIB::ifInOctets.70 = Counter32: 99214022
IF-MIB::ifInOctets.72 = Counter32: 5293853
IF-MIB::ifInOctets.73 = Counter32: 0
IF-MIB::ifInOctets.74 = Counter32: 0
...

Interessanter is es aber, diese Abfrage bei einem Router zu machen. Ein solches Beispiel ist hier wiedergegeben:

IF-MIB::ifIndex.1 = INTEGER: 1
IF-MIB::ifIndex.2 = INTEGER: 2
IF-MIB::ifIndex.3 = INTEGER: 3
IF-MIB::ifIndex.4 = INTEGER: 4
IF-MIB::ifIndex.12 = INTEGER: 12
IF-MIB::ifIndex.21 = INTEGER: 21
IF-MIB::ifIndex.22 = INTEGER: 22
IF-MIB::ifIndex.23 = INTEGER: 23
IF-MIB::ifIndex.24 = INTEGER: 24
IF-MIB::ifIndex.25 = INTEGER: 25
IF-MIB::ifIndex.26 = INTEGER: 26
IF-MIB::ifDescr.1 = STRING: LOCAL_LOOPBACK
IF-MIB::ifDescr.2 = STRING: LAN
IF-MIB::ifDescr.3 = STRING: WLAN
IF-MIB::ifDescr.4 = STRING: ATM1
IF-MIB::ifDescr.12 = STRING: PPPoE1
IF-MIB::ifDescr.21 = STRING: WDS1
IF-MIB::ifDescr.22 = STRING: WDS2
IF-MIB::ifDescr.23 = STRING: WDS3
IF-MIB::ifDescr.24 = STRING: WDS4
IF-MIB::ifDescr.25 = STRING: WAN2
IF-MIB::ifDescr.26 = STRING: COM1
...
IF-MIB::ifMtu.1 = INTEGER: 1500
IF-MIB::ifMtu.2 = INTEGER: 1500
IF-MIB::ifMtu.3 = INTEGER: 1500
IF-MIB::ifMtu.4 = INTEGER: 1500
IF-MIB::ifMtu.12 = INTEGER: 1492
IF-MIB::ifMtu.21 = INTEGER: 1500
IF-MIB::ifMtu.22 = INTEGER: 1500
IF-MIB::ifMtu.23 = INTEGER: 1500
IF-MIB::ifMtu.24 = INTEGER: 1500
IF-MIB::ifMtu.25 = INTEGER: 1500
IF-MIB::ifMtu.26 = INTEGER: 1500
IF-MIB::ifSpeed.1 = Gauge32: 0
IF-MIB::ifSpeed.2 = Gauge32: 100000000
IF-MIB::ifSpeed.3 = Gauge32: 54000000
IF-MIB::ifSpeed.4 = Gauge32: 224000
IF-MIB::ifSpeed.12 = Gauge32: 2304000
IF-MIB::ifSpeed.21 = Gauge32: 54000000
IF-MIB::ifSpeed.22 = Gauge32: 54000000
IF-MIB::ifSpeed.23 = Gauge32: 54000000
IF-MIB::ifSpeed.24 = Gauge32: 54000000
IF-MIB::ifSpeed.25 = Gauge32: 100000000
IF-MIB::ifSpeed.26 = Gauge32: 0
...
IF-MIB::ifAdminStatus.1 = INTEGER: up(1)
IF-MIB::ifAdminStatus.2 = INTEGER: up(1)
IF-MIB::ifAdminStatus.3 = INTEGER: up(1)
IF-MIB::ifAdminStatus.4 = INTEGER: up(1)
IF-MIB::ifAdminStatus.12 = INTEGER: up(1)
IF-MIB::ifAdminStatus.21 = INTEGER: up(1)
IF-MIB::ifAdminStatus.22 = INTEGER: up(1)
IF-MIB::ifAdminStatus.23 = INTEGER: up(1)
IF-MIB::ifAdminStatus.24 = INTEGER: up(1)
IF-MIB::ifAdminStatus.25 = INTEGER: 0
IF-MIB::ifAdminStatus.26 = INTEGER: 0
IF-MIB::ifOperStatus.1 = INTEGER: up(1)
IF-MIB::ifOperStatus.2 = INTEGER: up(1)
IF-MIB::ifOperStatus.3 = INTEGER: up(1)
IF-MIB::ifOperStatus.4 = INTEGER: up(1)
IF-MIB::ifOperStatus.12 = INTEGER: up(1)
IF-MIB::ifOperStatus.21 = INTEGER: up(1)
IF-MIB::ifOperStatus.22 = INTEGER: up(1)
IF-MIB::ifOperStatus.23 = INTEGER: up(1)
IF-MIB::ifOperStatus.24 = INTEGER: up(1)
IF-MIB::ifOperStatus.25 = INTEGER: 0
IF-MIB::ifOperStatus.26 = INTEGER: 0
...
IF-MIB::ifInOctets.1 = Counter32: 210
IF-MIB::ifInOctets.2 = Counter32: 0
IF-MIB::ifInOctets.3 = Counter32: 101309606
IF-MIB::ifInOctets.4 = Counter32: 511415216
IF-MIB::ifInOctets.12 = Counter32: 250011578
IF-MIB::ifInOctets.21 = Counter32: 0
IF-MIB::ifInOctets.22 = Counter32: 0
IF-MIB::ifInOctets.23 = Counter32: 0
IF-MIB::ifInOctets.24 = Counter32: 0
IF-MIB::ifInOctets.25 = Counter32: 0
IF-MIB::ifInOctets.26 = Counter32: 0
...
IF-MIB::ifOutOctets.1 = Counter32: 0
IF-MIB::ifOutOctets.2 = Counter32: 62445328
IF-MIB::ifOutOctets.3 = Counter32: 0
IF-MIB::ifOutOctets.4 = Counter32: 109637356
IF-MIB::ifOutOctets.12 = Counter32: 50021044
IF-MIB::ifOutOctets.21 = Counter32: 0
IF-MIB::ifOutOctets.22 = Counter32: 0
IF-MIB::ifOutOctets.23 = Counter32: 0
IF-MIB::ifOutOctets.24 = Counter32: 0
IF-MIB::ifOutOctets.25 = Counter32: 0
IF-MIB::ifOutOctets.26 = Counter32: 0

Die interessanten Interfaces sind hier #12 (PPPoE1), welches Statistiken der über ADSL transportierten Datenmengen an diesem Router zählt und #3, welches die über das WLAN transportierten Datenmengen protokolliert.

Posted on: 2012-12-08Gabriel Rüeck