PhpIPAM MAC-Adressen per arp ermitteln und hinzufügen: Unterschied zwischen den Versionen
Aus znilwiki
BLinz (Diskussion | Beiträge) Die Seite wurde neu angelegt: „<u>'''Changelog:'''</u><br> * 19.05.2025 erste Version ---- ==Vorwort== '''phpIPAM''' kann zu den IP-Adressen auch die MAC-Adressen zuordnen:<br> :Datei:ClipCapIt-250519-084748.PNG<br> Dazu wird jedoch ausschließlich SNMP verwendet. Man muss ein Gerät vom Typ '''Switch''' einrichten und die Abfrage der MAC-Adress-Tabelle per SNMP einrichten.<br> Das macht ja durchaus sinn, jedoch sind meine Allnet-Switche zum Beispiel nicht kompatibel damit.<br> <br…“ |
BLinz (Diskussion | Beiträge) K →Vorwort |
||
Zeile 16: | Zeile 16: | ||
<br> | <br> | ||
---- | ---- | ||
==Das geänderte Skript== | |||
nano phpipam-update-mac-from-arp_V1.1.sh | |||
<source lang="bash"> | |||
#!/bin/bash | |||
# V1.1 | |||
# Original by "lazynooblet" => https://github.com/lazynooblet/scripts/tree/main/bash/phpipam-update-mac-from-arp | |||
# Modified 2025-05-19 by Bernhard Linz => https://znil.net/index.php?title=PhpIPAM_MAC-Adressen_per_arp_ermitteln_und_hinzuf%C3%BCgen | |||
# Changes V1.1: | |||
# - Remove USER and PASSWORD Authentification, use TOKEN instead | |||
# - Add fping before checking MAC-Adresses to fill up ARP-Cache | |||
URL='https://phpipam.znil.local/api' | |||
APP='ARP-CronJob' | |||
#USER='user' | |||
#PASS='passwort' | |||
TOKEN='dI4iAJlvuo9z78xlCUt5N4ubmy1FPyoL' | |||
SUBNET='192.168.0.0/22' | |||
INTERFACE='ens33' | |||
INVALIDTAGS=("3" "4") | |||
#echo "[INFO] Fetching token" | |||
#TOKEN=$(curl -X POST --user ${USER}:${PASS} ${URL}/${APP}/user/ -s | jq --raw-output .data.token) | |||
#if [ "$?" != "0" ]; then | |||
# echo "[FAIL] Error fetching token from PHPIPAM" 1>&2 | |||
# exit 1 | |||
#fi | |||
#if [ -z "${TOKEN}" ]; then | |||
# echo "[FAIL] Didn't receive valid token from PHPIPAM" 1>&2 | |||
# exit 1 | |||
#fi | |||
#echo "[INFO] Fetching token expiry (token test)" | |||
#EXPIRES=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/user/ -s | jq --raw-output .data.expires) | |||
#if [ "$?" != "0" ]; then | |||
# echo "[FAIL] Error fetching token expiry from PHPIPAM" 1>&2 | |||
# exit 1 | |||
#fi | |||
#if [ -z "${EXPIRES}" ]; then | |||
# echo "[FAIL] Didn't receive valid token expiry from PHPIPAM" 1>&2 | |||
# exit 1 | |||
#fi | |||
echo "[INFO] fping subnet" | |||
fping -4 -a -q -g ${SUBNET} | |||
echo "[INFO] Fetching subnet id" | |||
SUBNETID=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/subnets/search/${SUBNET} -s | jq --raw-output .data[0].id) | |||
if [ "$?" != "0" ]; then | |||
echo "[FAIL] Error fetching subnet id from PHPIPAM" 1>&2 | |||
exit 1 | |||
fi | |||
if [ -z "${SUBNETID}" ]; then | |||
echo "[FAIL] Didn't receive valid subnet id from PHPIPAM" 1>&2 | |||
exit 1 | |||
fi | |||
_update() { | |||
ip=${1} | |||
mac=${2} | |||
IPID=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/addresses/${ip}/${SUBNETID} -s | jq --raw-output .data.id) | |||
if [ "$?" != "0" ]; then | |||
echo "[FAIL] Error fetching ip id from PHPIPAM" 1>&2 | |||
exit 1 | |||
fi | |||
if [ -z "${IPID}" ] || [ "${IPID}" = "null" ]; then | |||
echo "[INFO] address not in phpipam database: ${ip}" | |||
return | |||
fi | |||
NOUPDATE=0 | |||
JSON=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/addresses/${IPID}/ -s) | |||
if [ "$?" != "0" ]; then | |||
echo "[FAIL] Error fetching ip data from PHPIPAM" 1>&2 | |||
exit 1 | |||
fi | |||
IPTAG=$(echo ${JSON} | jq --raw-output .data.tag) | |||
for tag in ${INVALIDTAGS[@]}; do | |||
if [ "${IPTAG}" = "${tag}" ]; then | |||
echo "[INFO] refusing to update ip with tag: ${IPTAG}" | |||
NOUPDATE=1 | |||
fi | |||
done | |||
if [ ${NOUPDATE} -eq 1 ]; then return; fi | |||
IPMAC=$(echo ${JSON} | jq --raw-output .data.mac) | |||
if [ -z "${IPMAC}" ]; then | |||
echo "[INFO] No mac set for ip" | |||
fi | |||
if [ "${IPMAC}" = "${mac}" ]; then | |||
echo "[INFO] no update required for mac" | |||
return | |||
fi | |||
JSON=$(curl -X PATCH --header "token: ${TOKEN}" ${URL}/${APP}/addresses/${IPID}/ -s --data "mac=${mac}") | |||
if [ "$?" != "0" ]; then | |||
echo "[FAIL] Error updating ip mac on PHPIPAM" 1>&2 | |||
exit 1 | |||
fi | |||
RESULT=$(echo ${JSON} | jq --raw-output .success) | |||
if [ "${RESULT}" != "true" ]; then | |||
echo "[FAIL] API returned error updating ip on PHPIPAM: ${JSON}" | |||
exit 1 | |||
fi | |||
echo "[INFO] Updated id:${IPID} ip:${ip} mac:${mac}" | |||
} | |||
while read a b c d e; do | |||
# ? (192.168.1.10) at a1:b2:c3:d4:e5:f6 [ether] on eth0 | |||
line="${a} ${b} ${c} ${d} ${e}" | |||
ip=$(echo ${b} | sed 's/[^0-9\.]//g') | |||
mac=${d} | |||
if [ "${mac}" = "<incomplete>" ]; then | |||
# we silently skip these | |||
continue | |||
fi | |||
if ! [[ ${mac} =~ ^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$ ]]; then | |||
echo "[INFO] Invalid mac: ${mac}" | |||
continue | |||
fi | |||
echo "[INFO] Found ip:${ip} mac:${mac}" | |||
if [ -z "${ip}" ]; then | |||
echo "[WARN] Unable to parse ip from '${b}': ${line}" 1>&2 | |||
fi | |||
if [ -z "${mac}" ]; then | |||
echo "[WARN] Unable to parse mac from '${d}': ${line}" 1>&2 | |||
fi | |||
_update ${ip} ${mac} | |||
done < <(arp -an -i ${INTERFACE}) | |||
if [ "$?" != "0" ]; then | |||
echo "[FAIL] Error running arp" 1>&2 | |||
exit 1 | |||
fi | |||
# get json output from ip for local interfaces | |||
IPJSON=$(ip -j a show ${INTERFACE}) | |||
if [ "$?" != "0" ]; then | |||
echo "[FAIL] Error running ip a show" 1>&2 | |||
exit 1 | |||
fi | |||
localmac=$(echo ${IPJSON} | jq --raw-output '.[0].address') | |||
if [[ ${localmac} =~ ^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$ ]]; then | |||
LENGTH=$(echo ${IPJSON} | jq --raw-output '.[0].addr_info | length') | |||
for (( i=0; i<${LENGTH}; i++)); do | |||
localip=$(echo ${IPJSON} | jq --raw-output .[0].addr_info[${i}].local) | |||
if [ -z "${localip}" ]; then | |||
echo "[WARN] Unable to parse ip [${i}] from '${IPJSON}'" 1>&2 | |||
continue | |||
fi | |||
echo "[INFO] Found interface:${INTERFACE} ip:${localip} mac:${localmac} index:$((${i} +1))/${LENGTH}" | |||
_update ${localip} ${localmac} | |||
done | |||
else | |||
echo "[INFO] Invalid mac from interface: ${localmac}" | |||
fi | |||
#JSON=$(curl -X DELETE --header "token: ${TOKEN}" ${URL}/${APP}/user/ -s) | |||
#if [ "$?" != "0" ]; then | |||
# echo "[FAIL] Error removing token" 1>&2 | |||
# exit 1 | |||
#fi | |||
#RESULT=$(echo ${JSON} | jq --raw-output .success) | |||
#if [ "${RESULT}" != "true" ]; then | |||
# echo "[FAIL] API returned error when attempting to remove token: ${JSON}" | |||
# exit 1 | |||
#fi | |||
#echo "[INFO] Removed token" | |||
</source> |
Version vom 19. Mai 2025, 08:59 Uhr
Changelog:
- 19.05.2025 erste Version
Vorwort
phpIPAM kann zu den IP-Adressen auch die MAC-Adressen zuordnen:
Dazu wird jedoch ausschließlich SNMP verwendet. Man muss ein Gerät vom Typ Switch einrichten und die Abfrage der MAC-Adress-Tabelle per SNMP einrichten.
Das macht ja durchaus sinn, jedoch sind meine Allnet-Switche zum Beispiel nicht kompatibel damit.
Im Internet fand ich dieses Skript hier:
https://github.com/lazynooblet/scripts/tree/main/bash/phpipam-update-mac-from-arp
welches die ARP-Tabelle auf dem Linux-System nutzt vom welches es aufgerufen wird.
Ich habe das Skript in 2 Punkten abgepasst:
- Im Original wird sich per Benutzername und Passwort angemeldet um sich den API-Key zu holen. Meine Variante nutzt einfach gleich den API Key (und versucht auch nicht diesen am Ende zu löschen)
- Ich lasse vorher einen fping über den Bereich laufen damit der ARP-Cache auch frisch gefüllt ist.
Das geänderte Skript
nano phpipam-update-mac-from-arp_V1.1.sh
#!/bin/bash
# V1.1
# Original by "lazynooblet" => https://github.com/lazynooblet/scripts/tree/main/bash/phpipam-update-mac-from-arp
# Modified 2025-05-19 by Bernhard Linz => https://znil.net/index.php?title=PhpIPAM_MAC-Adressen_per_arp_ermitteln_und_hinzuf%C3%BCgen
# Changes V1.1:
# - Remove USER and PASSWORD Authentification, use TOKEN instead
# - Add fping before checking MAC-Adresses to fill up ARP-Cache
URL='https://phpipam.znil.local/api'
APP='ARP-CronJob'
#USER='user'
#PASS='passwort'
TOKEN='dI4iAJlvuo9z78xlCUt5N4ubmy1FPyoL'
SUBNET='192.168.0.0/22'
INTERFACE='ens33'
INVALIDTAGS=("3" "4")
#echo "[INFO] Fetching token"
#TOKEN=$(curl -X POST --user ${USER}:${PASS} ${URL}/${APP}/user/ -s | jq --raw-output .data.token)
#if [ "$?" != "0" ]; then
# echo "[FAIL] Error fetching token from PHPIPAM" 1>&2
# exit 1
#fi
#if [ -z "${TOKEN}" ]; then
# echo "[FAIL] Didn't receive valid token from PHPIPAM" 1>&2
# exit 1
#fi
#echo "[INFO] Fetching token expiry (token test)"
#EXPIRES=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/user/ -s | jq --raw-output .data.expires)
#if [ "$?" != "0" ]; then
# echo "[FAIL] Error fetching token expiry from PHPIPAM" 1>&2
# exit 1
#fi
#if [ -z "${EXPIRES}" ]; then
# echo "[FAIL] Didn't receive valid token expiry from PHPIPAM" 1>&2
# exit 1
#fi
echo "[INFO] fping subnet"
fping -4 -a -q -g ${SUBNET}
echo "[INFO] Fetching subnet id"
SUBNETID=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/subnets/search/${SUBNET} -s | jq --raw-output .data[0].id)
if [ "$?" != "0" ]; then
echo "[FAIL] Error fetching subnet id from PHPIPAM" 1>&2
exit 1
fi
if [ -z "${SUBNETID}" ]; then
echo "[FAIL] Didn't receive valid subnet id from PHPIPAM" 1>&2
exit 1
fi
_update() {
ip=${1}
mac=${2}
IPID=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/addresses/${ip}/${SUBNETID} -s | jq --raw-output .data.id)
if [ "$?" != "0" ]; then
echo "[FAIL] Error fetching ip id from PHPIPAM" 1>&2
exit 1
fi
if [ -z "${IPID}" ] || [ "${IPID}" = "null" ]; then
echo "[INFO] address not in phpipam database: ${ip}"
return
fi
NOUPDATE=0
JSON=$(curl -X GET --header "token: ${TOKEN}" ${URL}/${APP}/addresses/${IPID}/ -s)
if [ "$?" != "0" ]; then
echo "[FAIL] Error fetching ip data from PHPIPAM" 1>&2
exit 1
fi
IPTAG=$(echo ${JSON} | jq --raw-output .data.tag)
for tag in ${INVALIDTAGS[@]}; do
if [ "${IPTAG}" = "${tag}" ]; then
echo "[INFO] refusing to update ip with tag: ${IPTAG}"
NOUPDATE=1
fi
done
if [ ${NOUPDATE} -eq 1 ]; then return; fi
IPMAC=$(echo ${JSON} | jq --raw-output .data.mac)
if [ -z "${IPMAC}" ]; then
echo "[INFO] No mac set for ip"
fi
if [ "${IPMAC}" = "${mac}" ]; then
echo "[INFO] no update required for mac"
return
fi
JSON=$(curl -X PATCH --header "token: ${TOKEN}" ${URL}/${APP}/addresses/${IPID}/ -s --data "mac=${mac}")
if [ "$?" != "0" ]; then
echo "[FAIL] Error updating ip mac on PHPIPAM" 1>&2
exit 1
fi
RESULT=$(echo ${JSON} | jq --raw-output .success)
if [ "${RESULT}" != "true" ]; then
echo "[FAIL] API returned error updating ip on PHPIPAM: ${JSON}"
exit 1
fi
echo "[INFO] Updated id:${IPID} ip:${ip} mac:${mac}"
}
while read a b c d e; do
# ? (192.168.1.10) at a1:b2:c3:d4:e5:f6 [ether] on eth0
line="${a} ${b} ${c} ${d} ${e}"
ip=$(echo ${b} | sed 's/[^0-9\.]//g')
mac=${d}
if [ "${mac}" = "<incomplete>" ]; then
# we silently skip these
continue
fi
if ! [[ ${mac} =~ ^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$ ]]; then
echo "[INFO] Invalid mac: ${mac}"
continue
fi
echo "[INFO] Found ip:${ip} mac:${mac}"
if [ -z "${ip}" ]; then
echo "[WARN] Unable to parse ip from '${b}': ${line}" 1>&2
fi
if [ -z "${mac}" ]; then
echo "[WARN] Unable to parse mac from '${d}': ${line}" 1>&2
fi
_update ${ip} ${mac}
done < <(arp -an -i ${INTERFACE})
if [ "$?" != "0" ]; then
echo "[FAIL] Error running arp" 1>&2
exit 1
fi
# get json output from ip for local interfaces
IPJSON=$(ip -j a show ${INTERFACE})
if [ "$?" != "0" ]; then
echo "[FAIL] Error running ip a show" 1>&2
exit 1
fi
localmac=$(echo ${IPJSON} | jq --raw-output '.[0].address')
if [[ ${localmac} =~ ^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$ ]]; then
LENGTH=$(echo ${IPJSON} | jq --raw-output '.[0].addr_info | length')
for (( i=0; i<${LENGTH}; i++)); do
localip=$(echo ${IPJSON} | jq --raw-output .[0].addr_info[${i}].local)
if [ -z "${localip}" ]; then
echo "[WARN] Unable to parse ip [${i}] from '${IPJSON}'" 1>&2
continue
fi
echo "[INFO] Found interface:${INTERFACE} ip:${localip} mac:${localmac} index:$((${i} +1))/${LENGTH}"
_update ${localip} ${localmac}
done
else
echo "[INFO] Invalid mac from interface: ${localmac}"
fi
#JSON=$(curl -X DELETE --header "token: ${TOKEN}" ${URL}/${APP}/user/ -s)
#if [ "$?" != "0" ]; then
# echo "[FAIL] Error removing token" 1>&2
# exit 1
#fi
#RESULT=$(echo ${JSON} | jq --raw-output .success)
#if [ "${RESULT}" != "true" ]; then
# echo "[FAIL] API returned error when attempting to remove token: ${JSON}"
# exit 1
#fi
#echo "[INFO] Removed token"