Aktionen

Zabbix MAC-Adressen an Switchports auslesen und beim Client anzeigen lassen an welchen Switch und Port dieser angeschlossen ist

Aus znilwiki


Dieses Thema ist noch nicht vollständig! Es wird noch daran gearbeitet!



Changelog:

  • 07.10.2026 erste öffentliche Version



Vorwort

Bei einem Kunden überwachen wir mit Zabbix auch alle CLients. Mit einem stark abgespeckten Template, die Admins interessieren sich an den Clients nur für wenige Dinge wie die Speicherplatzbelegung auf Laufwerk C:, wie schon nicht mehr gebootet wurde, die Seriennummern der Monitore und ob die IP-Adresseinstellungen stimmen.

In dem Zuge kam die Idee auf, beim Client auch gleich anzeigen zu lassen, an welchem Switch und Port dieser hängt, unter Latest data kann man sich das hier nun bei allen Clienst anzeigen lassen:


zusätzlich wird die Information auch umgekehrt hinterlegt, man könnte beim Switchport anzeigen lassen welcher Client daran hängt, die Information wird nach dem gleichen Prinzip (mehr dazu weiter in diesem Artikel) hinterlegt:



Das ganze funktioniert wie folgt:

  • Aus den Switchen werden die MAC-Adressen ausgelesen die direkt an einem Switchport hängen, also nicht von einem anderem intelligenten Switch kommen. Ist da ein dummer Switch hinter, werden alle MACs von diesem übernommen.
  • Das geschieht über ein Template welches ein Item vom Typ External Skript anstößt.
  • Pro Switch werden diese Informationen im JSON-Format in einem Verzeichnis auf dem Zabbix-Server gespeichert (unterhalb von {{code|/var/lib/zabbix/externalscripts), pro MAC-Adresse eine Zeile in der Textdatei
  • Die Client-Hosts haben ein Template welches per WMI die aktuelle MAC-Adresse ausliest
  • Mit dieser MAC macht ein Item vom Typ External Skript ein grep auf das Verzeichnis mit den ablegten JSON der Switche. Es bekommt die Zeile mit den Daten im JSON-Format zurück
  • Das JSON wird per Items vom Typ Dependent item in seine Einzelteile zerlegt.


In meinem Client-Template wird in einem 2. Unterordner pro Client ein JSON abgelegt mit diesen Daten. Darauf könnte man mit der gleichen Methode am Switch die Client-IP und Namen hinterlegen. Das habe ich nicht umgesetzt da hier die Beschreibung der Ports gepflegt wird, die Information wäre also redundant.


MAC-Adressen von Switchen abrufen

Meldet euch per SSH am Zabbix-Server an und wechselt in das External-Skript Verzeichnis:

cd /usr/lib/zabbix/externalscripts

Erstellt das Verzeichnis im welchen die JSONs abgelegt werden und setzt den Zabbix-Benutzer als Besitzer:

mkdir macfinder
chown zabbix:zabbix macfinder

Das funktioniert je nach Switch anders, deshalb gibt es für verschiedene Switch-Hersteller und -Typen verschiedene Skripte:


Avaya-Switche

Das folgende Skript wurde mit Avaya-Switchen vom Typ

Modelle:   3510GT-PWR+
           3524GT-PWR+
           4950GTS
Firmware: 5.x
Software: v5.3.x

getestet.
Die MAC-Adressen bei diesen Modellen finden sich hinter OID

1.3.6.1.2.1.17.4.3.1.2

ein snmpwalk, z.B. so ein Aufruf

snmpwalk -v2c -On -c testcommu 192.168.0.1 1.3.6.1.2.1.17.4.3.1.2

gibt eine Ausgabe wie folgt:

.1.3.6.1.2.1.17.4.3.1.2.40.99.54.224.67.188 = INTEGER: 8193
.1.3.6.1.2.1.17.4.3.1.2.40.99.54.236.96.83 = INTEGER: 10
.1.3.6.1.2.1.17.4.3.1.2.40.99.54.236.96.84 = INTEGER: 10
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.21.14.81 = INTEGER: 14
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.21.148.216 = INTEGER: 77
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.139.121 = INTEGER: 8193
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.97 = INTEGER: 8193
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.103 = INTEGER: 8193
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.109 = INTEGER: 15
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.110 = INTEGER: 15
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.112 = INTEGER: 11
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.113 = INTEGER: 11
.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.121 = INTEGER: 8193

Wenn der Wert am Ende 0 oder 8193 ist, ist es eine MAC die er von einem anderem Switch hat.
Die MAC selbst ist in der OID codiert, die letzten 6 Zahlen:
OID:

.1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.112 = INTEGER: 11

die letzten 6 Zahlen:

48.19.137.37.241.112

sind die Dezimalwerte, in HEX ist das dann

30:13:89:25:f1:70

Der Wert dahinter ist die Portnummer, in diesem Fall die 11. Über die OID

.1.3.6.1.2.1.2.2.1.2.11

bekommen wir den Port Alias

.1.3.6.1.2.1.2.2.1.2.11 = STRING: Avaya Ethernet Routing Switch 3524GT PWR+ Module - Unit 1 Port 11

Über

.1.3.6.1.2.1.31.1.1.1.18.11

die Port Beschreibung

.1.3.6.1.2.1.31.1.1.1.18.11 = STRING: Panel W1

Aus diesen Informationen baut sich das Skript das zusammen.

Das eigentliche Skript:

nano  macportnameiptable-avaya
#!/bin/bash

# $1 = Community
# $2 = IP-Address or FQDN
# $3 = Base OID
if [[ $# -ne 3 ]]; then
   echo "Error - not 3 Parameter!"
   echo "Usage:"
   echo "macportnameiptable community IP-Address-or-FQDN Base-OID"
   echo " "
   exit 1
fi
#s_systemname=$(snmpget -v2c -O qv -c $1 $2 1.3.6.1.2.1.1.5.0)
# 1. Systemnamen abfragen (Fehlermeldungen abfangen)
s_systemname=$(snmpget -v2c -O qv -c $1 $2 1.3.6.1.2.1.1.5.0 2>/dev/null | xargs)

# 2. Wenn s_systemname leer ist oder "No Such..." enthält, IP-Adresse ($2) nutzen
if [ -z "$s_systemname" ] || [[ "$s_systemname" == *"No Such"* ]]; then
    s_systemname="$2"
else
    # Leerzeichen im Systemnamen durch Unterstriche ersetzen
    s_systemname="${s_systemname// /_}"
fi


output_from_command=$(snmpwalk -v2c -O nq -c $1 $2 $3)
# -O Parameter:
# n = OID numerisch darstellen
# q = kurze Ausgabe - OID, Leerzeichen, Wert
result="[\n"
while IFS= read -r line; do
    # Zeile in OID und Port aufteilen
    # [0] ist die OID
    # [1] ist der Port
    stringarray=($line)
    if [ "${stringarray[1]}" -ne "8193" ] && [ "${stringarray[1]}" -ne "0" ]; then
        stringoid=${stringarray[0]}
        #echo "${stringoid}"
        IFS='.'; macnumbers=($stringoid); unset IFS;
        # .1.3.6.1.2.1.17.4.3.1.2.248.177.86.223.76.59 8193
        mac1=$( printf "%02x" ${macnumbers[12]} )
        mac2=$( printf "%02x" ${macnumbers[13]} )
        mac3=$( printf "%02x" ${macnumbers[14]} )
        mac4=$( printf "%02x" ${macnumbers[15]} )
        mac5=$( printf "%02x" ${macnumbers[16]} )
        mac6=$( printf "%02x" ${macnumbers[17]} )
        #echo "MAC: ${macnumbers[12]}:${macnumbers[13]}:${macnumbers[14]}:${macnumbers[15]}:${macnumbers[16]}:${macnumbers[17]}"
        mac_complete="${mac1}:${mac2}:${mac3}:${mac4}:${mac5}:${mac6}"
        # Beschreibung des Ports holen
        s_portdescription=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.31.1.1.1.18.${stringarray[1]})
        s_portalias=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.2.2.1.2.${stringarray[1]} | cut -d "-" -f 2 | xargs)
        result="${result}{\"switchname\":\"${s_systemname}\",\"portnumber\":\"${stringarray[1]}\",\"portalias\":\"${s_portalias}\",\"portdescription\":\"${s_portdescription}\",\"MAC\":\"${mac_complete}\"},\n"
        #result="${result}\"${stringarray[1]}\":\"${mac_complete}\",\n"
        #echo ${stringarray[1]} --- ${stringarray[0]}
    fi
done <<< "$output_from_command"
result="${result::-3}\n]"
echo -e $result > /usr/lib/zabbix/externalscripts/macfinder/${s_systemname}.json
echo -e $result

Das Skript ausführbar machen und den Besitz an den Benutzer zabbix übertragen:

chmod +x macportnameiptable-avaya
chown zabbix:zabbix macportnameiptable-avaya


Testen könnt Ihr das Skript dann mit

sudo -u zabbix ./macportnameiptable snmp-community-string 192.168.0.1 1.3.6.1.2.1.17.4.3.1.2

Beispielausgabe:

[
{"switchname":"TESTSWITCH01","portnumber":"1","portalias":"Port 1","portdescription":"Zeiterfassungsterminal 54","MAC":"00:01:02:03:04:05"},
{"switchname":"TESTSWITCH01","portnumber":"4","portalias":"Port 4","portdescription":"PC Testbenutzer","MAC":"aa:bb:cc:00:00:f1"},
{"switchname":"TESTSWITCH01","portnumber":"4","portalias":"Port 4","portdescription":"PC Testbenutzer","MAC":"aa:bb:cc:00:00:f2"}
]

Zeitgleich zur Ausgabe hat das Skript auch eine Datei TESTSWITCH01.json im Unterverzeichnis macfinder abgelegt.
Der Inhalt ist der gleiche wie die Ausgabe.
Deshalb wurde der Befehl mit sudo ausgeführt damit der Besitzer der Datei dann auch zabbix ist.