Aktionen

Zabbix MAC-Adressen an Switchports auslesen und beim Client anzeigen lassen an welchen Switch und Port dieser angeschlossen ist: Unterschied zwischen den Versionen

Aus znilwiki

 
(3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 154: Zeile 154:
  ]
  ]
Zeitgleich zur Ausgabe hat das Skript auch eine Datei {{code|TESTSWITCH01.json}} im Unterverzeichnis {{code|macfinder}} abgelegt.<br>
Zeitgleich zur Ausgabe hat das Skript auch eine Datei {{code|TESTSWITCH01.json}} im Unterverzeichnis {{code|macfinder}} abgelegt.<br>
Der Name der Datei ist der des Switches, dieser wird per SNMP ermittelt. Ist der Name leer, wird die IP-Adresse genommen.<br>
Der Inhalt ist der gleiche wie die Ausgabe.<br>
Der Inhalt ist der gleiche wie die Ausgabe.<br>
Deshalb wurde der Befehl mit {{code|sudo}} ausgeführt damit der Besitzer der Datei dann auch {{code|zabbix}} ist.<br>
Deshalb wurde der Befehl mit {{code|sudo}} ausgeführt damit der Besitzer der Datei dann auch {{code|zabbix}} ist.<br>
Zeile 166: Zeile 167:
----
----
----
----
==Fortinet Switche==
 
===Avaya-Switche===
===Fortinet Switche===
Das folgende Skript wurde mit Avaya-Switchen vom Typ<br>
Das folgende Skript wurde mit Fortinet-Switchen / Fortiswitch vom Typ<br>
  Modelle:  3510GT-PWR+
  Modelle:  FortiSwitch-2048F
             3524GT-PWR+
             FortiSwitch-1048E
             4950GTS
             FortiSwitch-124F-FPOE
  Firmware: 5.x
  Firmware: v7.04.9
Software: v5.3.x
            v7.06.6
getestet.<br>
getestet.<br>
Die MAC-Adressen bei diesen Modellen finden sich hinter OID<br>
Die MAC-Adressen bei diesen Modellen finden sich hinter OID<br>
  1.3.6.1.2.1.17.4.3.1.2
  .1.3.6.1.2.1.17.4.3.1.1
ein {{code|snmpwalk}}, z.B. so ein Aufruf<br>
ein {{code|snmpwalk}}, z.B. so ein Aufruf<br>
  snmpwalk -v2c -On -c testcommu 192.168.0.1 1.3.6.1.2.1.17.4.3.1.2
  snmpwalk -v2c -On -c testcommu 192.168.0.1 .1.3.6.1.2.1.17.4.3.1.1
gibt eine Ausgabe wie folgt:<br>
gibt eine Ausgabe wie folgt:<br>
  .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.1.1 = Hex-STRING: 58 38 79 3E 2D F2
  .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.1.2 = Hex-STRING: DE 00 9E 6E 91 01
  .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.1.3 = Hex-STRING: 62 72 E3 37 2D ED
  .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.1.4 = Hex-STRING: 00 26 73 E6 1A CD
  .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.1.5 = Hex-STRING: 4C D7 17 91 C7 32
  .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.1.6 = Hex-STRING: 0A 3F 12 95 42 75
  .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.1.7 = Hex-STRING: AC B4 80 3F 64 B6
  .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.1.8 = Hex-STRING: 4C D7 17 7F DA D0
  .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.1.9 = Hex-STRING: 4C D7 17 7F DA AD
  .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.1.10 = Hex-STRING: 1C D1 1A 0D 43 FF
  .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.1.11 = Hex-STRING: 1C D1 1A 0D 43 FE
  .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.1.12 = Hex-STRING: 7A 05 9F 21 1E BC
  .1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.121 = INTEGER: 8193
  .1.3.6.1.2.1.17.4.3.1.1.13 = Hex-STRING: 08 00 0F F7 15 A9
 
.1.3.6.1.2.1.17.4.3.1.1.14 = Hex-STRING: DC 67 23 08 29 88
Wenn der Wert am Ende 0 oder 8193 ist, ist es eine MAC die er von einem anderem Switch hat.<br>
  .1.3.6.1.2.1.17.4.3.1.1.15 = Hex-STRING: 00 26 73 B8 99 50
Die MAC selbst ist in der OID codiert, die letzten 6 Zahlen:<br>
...
OID:<br>
Die Hex-Werte sind schon die MAC-Adresse.<br>
  .1.3.6.1.2.1.17.4.3.1.2.48.19.137.37.241.112 = INTEGER: 11
Leider stehen an dieser Stelle wirklich alle MAC-Adressen und man kann nicht erkennen, ob diese direkt verbunden sind oder über einen anderen Switch kommen.<br>
die letzten 6 Zahlen:<br>
Aber mit der letzten Nummer der OID kann man an diese OID gehen:<br>
  48.19.137.37.241.112
  .1.3.6.1.2.1.17.4.3.1.2
sind die Dezimalwerte, in HEX ist das dann
und dort z.B. den Status des der Einträge abfragen:
  30:13:89:25:f1:70
.1.3.6.1.2.1.17.4.3.1.2.8 = INTEGER: 32768
Der Wert dahinter ist die Portnummer, in diesem Fall die 11. Über die OID
  .1.3.6.1.2.1.17.4.3.1.2.9 = INTEGER: 32768
  .1.3.6.1.2.1.2.2.1.2.11
.1.3.6.1.2.1.17.4.3.1.2.10 = INTEGER: 32768
  .1.3.6.1.2.1.17.4.3.1.2.11 = INTEGER: 12
.1.3.6.1.2.1.17.4.3.1.2.12 = INTEGER: 6
  .1.3.6.1.2.1.17.4.3.1.2.13 = INTEGER: 32768
.1.3.6.1.2.1.17.4.3.1.2.14 = INTEGER: 32768
  .1.3.6.1.2.1.17.4.3.1.2.15 = INTEGER: 32768
Ist die Zahl eine große ist, hier also {{code|32768}} (16 Bit Ganzzahl maximum), ist es keine lokale MAC.<br>
Bei 12 steht hier als Wert eine 6.<br>
Damit lässt sich per OID<br>
.1.3.6.1.2.1.17.1.4.1.2
die echte Portnummer abfragen:<br>
  .1.3.6.1.2.1.17.1.4.1.2.1 = INTEGER: 3
.1.3.6.1.2.1.17.1.4.1.2.2 = INTEGER: 4
.1.3.6.1.2.1.17.1.4.1.2.3 = INTEGER: 5
.1.3.6.1.2.1.17.1.4.1.2.4 = INTEGER: 6
.1.3.6.1.2.1.17.1.4.1.2.5 = INTEGER: 9
  .1.3.6.1.2.1.17.1.4.1.2.6 = INTEGER: 10
.1.3.6.1.2.1.17.1.4.1.2.7 = INTEGER: 15
  .1.3.6.1.2.1.17.1.4.1.2.8 = INTEGER: 16
.1.3.6.1.2.1.17.1.4.1.2.9 = INTEGER: 17
.1.3.6.1.2.1.17.1.4.1.2.10 = INTEGER: 18
.1.3.6.1.2.1.17.1.4.1.2.11 = INTEGER: 19
.1.3.6.1.2.1.17.1.4.1.2.12 = INTEGER: 20
Hier sehen wir, das die ID 6 für den Port 10 steht.<br>
Über die OID<br>
  .1.3.6.1.2.1.2.2.1.2.10
bekommen wir den Port Alias
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
  .1.3.6.1.2.1.2.2.1.2.10 = STRING: TESTPC02
Über
Über
  .1.3.6.1.2.1.31.1.1.1.18.11
  .1.3.6.1.2.1.31.1.1.1.18.10
die Port Beschreibung
die Port Beschreibung
  .1.3.6.1.2.1.31.1.1.1.18.11 = STRING: Panel W1
  .1.3.6.1.2.1.31.1.1.1.18.10 = STRING: port10
Aus diesen Informationen baut sich das Skript das zusammen.<br>
Aus diesen Informationen baut sich das Skript das zusammen.<br>
<br>
<br>
Das eigentliche Skript:<br>
Das eigentliche Skript:<br>
  nano  macportnameiptable-avaya
  nano  macportnameiptable-fortinet
<source lang="bash">
<source lang="bash">
#!/bin/bash
#!/bin/bash
Zeile 227: Zeile 253:
   exit 1
   exit 1
fi
fi
#s_systemname=$(snmpget -v2c -O qv -c $1 $2 1.3.6.1.2.1.1.5.0)
#s_systemname=$(snmpget -v2c -O qv -c $1 $2 1.3.6.1.2.1.1.5.0)
# 1. Systemnamen abfragen (Fehlermeldungen abfangen)
# 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)
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
# 2. Wenn s_systemname leer ist oder "No Such..." enthält, IP-Adresse ($2) nutzen
if [ -z "$s_systemname" ] || [[ "$s_systemname" == *"No Such"* ]]; then
if [ -z "$s_systemname" ] || [[ "$s_systemname" == *"No Such"* ]]; then
Zeile 239: Zeile 266:
fi
fi


output_from_command=$(snmpwalk -v2c -O nqx -c $1 $2 $3)
#echo "${output_from_command}"


output_from_command=$(snmpwalk -v2c -O nq -c $1 $2 $3)
# -O Parameter:
# -O Parameter:
# n = OID numerisch darstellen
# n = OID numerisch darstellen
Zeile 246: Zeile 274:
result="[\n"
result="[\n"
while IFS= read -r line; do
while IFS= read -r line; do
     # Zeile in OID und Port aufteilen
     # Beispielzeile: .1.3.6.1.2.1.17.4.3.1.1.248.177.86.223.76.59 "FE A0 49 BE 58 12 "
     # [0] ist die OID
 
     # [1] ist der Port
     # 1. Vollständige OID der Zeile extrahieren
     stringarray=($line)
    stringoid=$(echo "$line" | awk '{print $1}')
     if [ "${stringarray[1]}" -ne "8193" ] && [ "${stringarray[1]}" -ne "0" ]; then
 
        stringoid=${stringarray[0]}
     # 2. Suffix ab .1.3.6.1.2.1.17.4.3.1.1. isolieren (das ist die Dezimal-MAC)
         #echo "${stringoid}"
     mac_suffix=$(echo "$stringoid" | sed 's/^\.1\.3\.6\.1\.2\.1\.17\.4\.3\.1\.1\.//')
         IFS='.'; macnumbers=($stringoid); unset IFS;
 
        # .1.3.6.1.2.1.17.4.3.1.2.248.177.86.223.76.59 8193
     if [ -n "$mac_suffix" ]; then
        mac1=$( printf "%02x" ${macnumbers[12]} )
         # 3. Bridge-Port (bp) über dot1dTpFdbPort abfragen
         mac2=$( printf "%02x" ${macnumbers[13]} )
         fdb_port=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.17.4.3.1.2.${mac_suffix} 2>/dev/null | xargs)
         mac3=$( printf "%02x" ${macnumbers[14]} )
 
        mac4=$( printf "%02x" ${macnumbers[15]} )
         # Wenn kein Bridge-Port gefunden wird oder der Port 0 ist -> überspringen (Trunk/Uplink oder ungültig)
         mac5=$( printf "%02x" ${macnumbers[16]} )
         if [ -z "$fdb_port" ] || [ "$fdb_port" = "0" ] || [[ "$fdb_port" == *"No Such"* ]]; then
         mac6=$( printf "%02x" ${macnumbers[17]} )
            continue
         #echo "MAC: ${macnumbers[12]}:${macnumbers[13]}:${macnumbers[14]}:${macnumbers[15]}:${macnumbers[16]}:${macnumbers[17]}"
        fi
        mac_complete="${mac1}:${mac2}:${mac3}:${mac4}:${mac5}:${mac6}"
 
        # Beschreibung des Ports holen
         # 4. Bridge-Port in echten Interface Index (ifIndex) übersetzen
        s_portdescription=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.31.1.1.1.18.${stringarray[1]})
         if_index=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.17.1.4.1.2.${fdb_port} 2>/dev/null | xargs)
        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"
         # 5. Filtern: Nur fortfahren, wenn ein gültiger numeric ifIndex ermittelt wurde
        #result="${result}\"${stringarray[1]}\":\"${mac_complete}\",\n"
        if [[ "$if_index" =~ ^[0-9]+$ ]]; then
         #echo ${stringarray[1]} --- ${stringarray[0]}
 
            # 6. Portbeschreibung und Alias abfragen
            s_portdescription=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.31.1.1.1.18.${if_index} 2>/dev/null | xargs)
            s_portalias=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.2.2.1.2.${if_index} 2>/dev/null | cut -d "-" -f 2 | xargs)
 
            # Prüfen, ob eine gültige Portbeschreibung zurückkam (schließt Uplink/Virtuelle Interfaces aus)
            if [[ "$s_portdescription" == *"No Such"* ]] || [[ "$s_portalias" == *"No Such"* ]]; then
                continue
            fi
 
            # 7. MAC-Adresse aus der Ausgabe parsen (wie bisher)
            raw_mac=$(echo "$line" | sed -n 's/.*"\([^"]*\)".*/\1/p' | xargs | tr '[:upper:]' '[:lower:]')
            read -r mac1 mac2 mac3 mac4 mac5 mac6 <<< "$raw_mac"
            mac_complete="${mac1}:${mac2}:${mac3}:${mac4}:${mac5}:${mac6}"
 
            # JSON-Objekt zusammenbauen
            result="${result}{\"switchname\":\"${s_systemname}\",\"portnumber\":\"${if_index}\",\"portalias\":\"${s_portalias}\",\"portdescription\":\"${s_portdescription}\",\"mac\":\"${mac_complete}\"},\n"
 
            #echo "Port ${if_index} (${s_portalias}) --- MAC: ${mac_complete}"
         fi
     fi
     fi
done <<< "$output_from_command"
done <<< "$output_from_command"
result="${result::-3}\n]"
 
echo -e $result > /usr/lib/zabbix/externalscripts/macfinder/${s_systemname}.json
# 1. Prüfen, ob nach der Schleife nur der Initialwert "[\n" in $result steht
echo -e $result
if [ "$result" = "[\n" ]; then
    # Fallback: Kein einziges finales Endgerät am Switch gefunden
    result_output="Keine direkten MAC-Adressen"
    #echo "Info: Keine direkten MAC-Adressen an lokalen Ports gefunden."
else
    # Validieren & Schließen des JSON-Arrays:
    result_output="${result::-3}\n]"
fi
 
#result="${result::-3}\n]"
echo -e $result_output > /usr/lib/zabbix/externalscripts/macfinder/${s_systemname}.json
echo -e $result_output
#echo "Systemname: ${s_systemname}"
</source>
</source>


Das Skript ausführbar machen und den Besitz an den Benutzer zabbix übertragen:<br>
Das Skript ausführbar machen und den Besitz an den Benutzer zabbix übertragen:<br>
  chmod +x macportnameiptable-avaya
  chmod +x macportnameiptable-fortinet
  chown zabbix:zabbix macportnameiptable-avaya
  chown zabbix:zabbix macportnameiptable-fortinet
<br>
<br>
Testen könnt Ihr das Skript dann mit
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
  sudo -u zabbix ./macportnameiptable-fortinet snmp-community-string 192.168.0.1 .1.3.6.1.2.1.17.4.3.1.1
Beispielausgabe:<br>
Beispielausgabe:<br>
  [
  [
Zeile 289: Zeile 348:
  ]
  ]
Zeitgleich zur Ausgabe hat das Skript auch eine Datei {{code|TESTSWITCH01.json}} im Unterverzeichnis {{code|macfinder}} abgelegt.<br>
Zeitgleich zur Ausgabe hat das Skript auch eine Datei {{code|TESTSWITCH01.json}} im Unterverzeichnis {{code|macfinder}} abgelegt.<br>
Der Name der Datei ist der des Switches, dieser wird per SNMP ermittelt. Ist der Name leer, wird die IP-Adresse genommen.<br>
Der Inhalt ist der gleiche wie die Ausgabe.<br>
Der Inhalt ist der gleiche wie die Ausgabe.<br>
Deshalb wurde der Befehl mit {{code|sudo}} ausgeführt damit der Besitzer der Datei dann auch {{code|zabbix}} ist.<br>
Deshalb wurde der Befehl mit {{code|sudo}} ausgeführt damit der Besitzer der Datei dann auch {{code|zabbix}} ist.<br>
Zeile 294: Zeile 354:
<br>
<br>
Hier ist das Template für Zabbix 7.0.0:<br>
Hier ist das Template für Zabbix 7.0.0:<br>
<big>'''[[Media:Template_Avaya_Switch_MAC_V2026-10-07.zip|Template_Avaya_Switch_MAC_V2026-10-07.zip]]'''</big><br>
<big>'''[[Media:Template_FortiSwitch_MAC_2026-10-06.zip|Template_FortiSwitch_MAC_2026-10-06.zip]]'''</big><br>
Das besteht nur aus einem Item:<br>
Das besteht nur aus einem Item:<br>
:[[Datei:ClipCapIt-261007-135236.PNG]]<br>
:[[Datei:ClipCapIt-261007-142746.PNG]]<br>
In der Oberfläche könnte ihr unter {{code|Latest data}} kontrollieren ob der Abruf klappt.<br>
In der Oberfläche könnte ihr unter {{code|Latest data}} kontrollieren ob der Abruf klappt.<br>
<br>
<br>
----
----
----
----
==Client-Template==
Im Verzeichnis
/usr/lib/zabbix/externalscripts
müsst ihr noch das folgende Script hinterlegen:<br>
nano hostmacgrep
Inhalt:<br>
<source lang="bash">
#!/bin/bash
# $1 = MAC
if [[ $# -ne 1 ]]; then
  echo "Error - not 1 Parameter!"
  echo "Usage:"
  echo "hostmacgrep 00:00:00:00:00:00"
  echo " "
  exit 1
fi
result=$(grep -ih $1 /usr/lib/zabbix/externalscripts/hostmac/* | sed -zr 's/,([^,]*$)/\1/')
echo -e $result
</source>
Besitzer anpassen und Ausführbar machen:<br>
chown zabbix:zabbix hostmacgrep
chmod +x hostmacgrep

Aktuelle Version vom 7. Oktober 2026, 14:56 Uhr


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 Name der Datei ist der des Switches, dieser wird per SNMP ermittelt. Ist der Name leer, wird die IP-Adresse genommen.
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.


Hier ist das Template für Zabbix 7.0.0:
Template_Avaya_Switch_MAC_V2026-10-07.zip
Das besteht nur aus einem Item:


In der Oberfläche könnte ihr unter Latest data kontrollieren ob der Abruf klappt.



Fortinet Switche

Das folgende Skript wurde mit Fortinet-Switchen / Fortiswitch vom Typ

Modelle:   FortiSwitch-2048F
           FortiSwitch-1048E
           FortiSwitch-124F-FPOE
Firmware:  v7.04.9
           v7.06.6

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

.1.3.6.1.2.1.17.4.3.1.1

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.1

gibt eine Ausgabe wie folgt:

.1.3.6.1.2.1.17.4.3.1.1.1 = Hex-STRING: 58 38 79 3E 2D F2
.1.3.6.1.2.1.17.4.3.1.1.2 = Hex-STRING: DE 00 9E 6E 91 01
.1.3.6.1.2.1.17.4.3.1.1.3 = Hex-STRING: 62 72 E3 37 2D ED
.1.3.6.1.2.1.17.4.3.1.1.4 = Hex-STRING: 00 26 73 E6 1A CD
.1.3.6.1.2.1.17.4.3.1.1.5 = Hex-STRING: 4C D7 17 91 C7 32
.1.3.6.1.2.1.17.4.3.1.1.6 = Hex-STRING: 0A 3F 12 95 42 75
.1.3.6.1.2.1.17.4.3.1.1.7 = Hex-STRING: AC B4 80 3F 64 B6
.1.3.6.1.2.1.17.4.3.1.1.8 = Hex-STRING: 4C D7 17 7F DA D0
.1.3.6.1.2.1.17.4.3.1.1.9 = Hex-STRING: 4C D7 17 7F DA AD
.1.3.6.1.2.1.17.4.3.1.1.10 = Hex-STRING: 1C D1 1A 0D 43 FF
.1.3.6.1.2.1.17.4.3.1.1.11 = Hex-STRING: 1C D1 1A 0D 43 FE
.1.3.6.1.2.1.17.4.3.1.1.12 = Hex-STRING: 7A 05 9F 21 1E BC
.1.3.6.1.2.1.17.4.3.1.1.13 = Hex-STRING: 08 00 0F F7 15 A9
.1.3.6.1.2.1.17.4.3.1.1.14 = Hex-STRING: DC 67 23 08 29 88
.1.3.6.1.2.1.17.4.3.1.1.15 = Hex-STRING: 00 26 73 B8 99 50
...

Die Hex-Werte sind schon die MAC-Adresse.
Leider stehen an dieser Stelle wirklich alle MAC-Adressen und man kann nicht erkennen, ob diese direkt verbunden sind oder über einen anderen Switch kommen.
Aber mit der letzten Nummer der OID kann man an diese OID gehen:

.1.3.6.1.2.1.17.4.3.1.2

und dort z.B. den Status des der Einträge abfragen:

.1.3.6.1.2.1.17.4.3.1.2.8 = INTEGER: 32768
.1.3.6.1.2.1.17.4.3.1.2.9 = INTEGER: 32768
.1.3.6.1.2.1.17.4.3.1.2.10 = INTEGER: 32768
.1.3.6.1.2.1.17.4.3.1.2.11 = INTEGER: 12
.1.3.6.1.2.1.17.4.3.1.2.12 = INTEGER: 6
.1.3.6.1.2.1.17.4.3.1.2.13 = INTEGER: 32768
.1.3.6.1.2.1.17.4.3.1.2.14 = INTEGER: 32768
.1.3.6.1.2.1.17.4.3.1.2.15 = INTEGER: 32768

Ist die Zahl eine große ist, hier also 32768 (16 Bit Ganzzahl maximum), ist es keine lokale MAC.
Bei 12 steht hier als Wert eine 6.
Damit lässt sich per OID

.1.3.6.1.2.1.17.1.4.1.2

die echte Portnummer abfragen:

.1.3.6.1.2.1.17.1.4.1.2.1 = INTEGER: 3
.1.3.6.1.2.1.17.1.4.1.2.2 = INTEGER: 4
.1.3.6.1.2.1.17.1.4.1.2.3 = INTEGER: 5
.1.3.6.1.2.1.17.1.4.1.2.4 = INTEGER: 6
.1.3.6.1.2.1.17.1.4.1.2.5 = INTEGER: 9
.1.3.6.1.2.1.17.1.4.1.2.6 = INTEGER: 10
.1.3.6.1.2.1.17.1.4.1.2.7 = INTEGER: 15
.1.3.6.1.2.1.17.1.4.1.2.8 = INTEGER: 16
.1.3.6.1.2.1.17.1.4.1.2.9 = INTEGER: 17
.1.3.6.1.2.1.17.1.4.1.2.10 = INTEGER: 18
.1.3.6.1.2.1.17.1.4.1.2.11 = INTEGER: 19
.1.3.6.1.2.1.17.1.4.1.2.12 = INTEGER: 20

Hier sehen wir, das die ID 6 für den Port 10 steht.
Über die OID

.1.3.6.1.2.1.2.2.1.2.10

bekommen wir den Port Alias

.1.3.6.1.2.1.2.2.1.2.10 = STRING: TESTPC02

Über

.1.3.6.1.2.1.31.1.1.1.18.10

die Port Beschreibung

.1.3.6.1.2.1.31.1.1.1.18.10 = STRING: port10

Aus diesen Informationen baut sich das Skript das zusammen.

Das eigentliche Skript:

nano  macportnameiptable-fortinet
#!/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 nqx -c $1 $2 $3)
#echo "${output_from_command}"

# -O Parameter:
# n = OID numerisch darstellen
# q = kurze Ausgabe - OID, Leerzeichen, Wert
result="[\n"
while IFS= read -r line; do
    # Beispielzeile: .1.3.6.1.2.1.17.4.3.1.1.248.177.86.223.76.59 "FE A0 49 BE 58 12 "

    # 1. Vollständige OID der Zeile extrahieren
    stringoid=$(echo "$line" | awk '{print $1}')

    # 2. Suffix ab .1.3.6.1.2.1.17.4.3.1.1. isolieren (das ist die Dezimal-MAC)
    mac_suffix=$(echo "$stringoid" | sed 's/^\.1\.3\.6\.1\.2\.1\.17\.4\.3\.1\.1\.//')

    if [ -n "$mac_suffix" ]; then
        # 3. Bridge-Port (bp) über dot1dTpFdbPort abfragen
        fdb_port=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.17.4.3.1.2.${mac_suffix} 2>/dev/null | xargs)

        # Wenn kein Bridge-Port gefunden wird oder der Port 0 ist -> überspringen (Trunk/Uplink oder ungültig)
        if [ -z "$fdb_port" ] || [ "$fdb_port" = "0" ] || [[ "$fdb_port" == *"No Such"* ]]; then
            continue
        fi

        # 4. Bridge-Port in echten Interface Index (ifIndex) übersetzen
        if_index=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.17.1.4.1.2.${fdb_port} 2>/dev/null | xargs)

        # 5. Filtern: Nur fortfahren, wenn ein gültiger numeric ifIndex ermittelt wurde
        if [[ "$if_index" =~ ^[0-9]+$ ]]; then

            # 6. Portbeschreibung und Alias abfragen
            s_portdescription=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.31.1.1.1.18.${if_index} 2>/dev/null | xargs)
            s_portalias=$(snmpget -v2c -O qv -c $1 $2 .1.3.6.1.2.1.2.2.1.2.${if_index} 2>/dev/null | cut -d "-" -f 2 | xargs)

            # Prüfen, ob eine gültige Portbeschreibung zurückkam (schließt Uplink/Virtuelle Interfaces aus)
            if [[ "$s_portdescription" == *"No Such"* ]] || [[ "$s_portalias" == *"No Such"* ]]; then
                continue
            fi

            # 7. MAC-Adresse aus der Ausgabe parsen (wie bisher)
            raw_mac=$(echo "$line" | sed -n 's/.*"\([^"]*\)".*/\1/p' | xargs | tr '[:upper:]' '[:lower:]')
            read -r mac1 mac2 mac3 mac4 mac5 mac6 <<< "$raw_mac"
            mac_complete="${mac1}:${mac2}:${mac3}:${mac4}:${mac5}:${mac6}"

            # JSON-Objekt zusammenbauen
            result="${result}{\"switchname\":\"${s_systemname}\",\"portnumber\":\"${if_index}\",\"portalias\":\"${s_portalias}\",\"portdescription\":\"${s_portdescription}\",\"mac\":\"${mac_complete}\"},\n"

            #echo "Port ${if_index} (${s_portalias}) --- MAC: ${mac_complete}"
        fi
    fi
done <<< "$output_from_command"

# 1. Prüfen, ob nach der Schleife nur der Initialwert "[\n" in $result steht
if [ "$result" = "[\n" ]; then
    # Fallback: Kein einziges finales Endgerät am Switch gefunden
    result_output="Keine direkten MAC-Adressen"
    #echo "Info: Keine direkten MAC-Adressen an lokalen Ports gefunden."
else
    # Validieren & Schließen des JSON-Arrays:
    result_output="${result::-3}\n]"
fi

#result="${result::-3}\n]"
echo -e $result_output > /usr/lib/zabbix/externalscripts/macfinder/${s_systemname}.json
echo -e $result_output
#echo "Systemname: ${s_systemname}"

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

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


Testen könnt Ihr das Skript dann mit

sudo -u zabbix ./macportnameiptable-fortinet snmp-community-string 192.168.0.1 .1.3.6.1.2.1.17.4.3.1.1

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 Name der Datei ist der des Switches, dieser wird per SNMP ermittelt. Ist der Name leer, wird die IP-Adresse genommen.
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.


Hier ist das Template für Zabbix 7.0.0:
Template_FortiSwitch_MAC_2026-10-06.zip
Das besteht nur aus einem Item:


In der Oberfläche könnte ihr unter Latest data kontrollieren ob der Abruf klappt.



Client-Template

Im Verzeichnis

/usr/lib/zabbix/externalscripts

müsst ihr noch das folgende Script hinterlegen:

nano hostmacgrep

Inhalt:

#!/bin/bash

# $1 = MAC
if [[ $# -ne 1 ]]; then
   echo "Error - not 1 Parameter!"
   echo "Usage:"
   echo "hostmacgrep 00:00:00:00:00:00"
   echo " "
   exit 1
fi
result=$(grep -ih $1 /usr/lib/zabbix/externalscripts/hostmac/* | sed -zr 's/,([^,]*$)/\1/')
echo -e $result

Besitzer anpassen und Ausführbar machen:

chown zabbix:zabbix hostmacgrep
chmod +x hostmacgrep