46 lines
1.5 KiB
Bash
Executable File
46 lines
1.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Runs on the CT122 host (not in a container) via the homelab-monitor-discover
|
|
# systemd timer. Real ARP entries live in the host's network namespace, not an
|
|
# isolated Docker bridge network, so this has to run here rather than inside
|
|
# the api container — see docs/device-discovery.md.
|
|
#
|
|
# Pings every address in the subnet (ICMP only, no port scanning) to populate
|
|
# the ARP cache, then dumps ip+mac+state pairs as JSON. The API service reads
|
|
# this file and does known/unknown labeling using config/hosts.yaml.
|
|
set -euo pipefail
|
|
|
|
SUBNET_PREFIX="${SUBNET_PREFIX:-192.168.1}"
|
|
OUTPUT_FILE="${OUTPUT_FILE:-/opt/homelab-monitor/data/devices-raw.json}"
|
|
IFACE="${IFACE:-eth0}"
|
|
|
|
mkdir -p "$(dirname "$OUTPUT_FILE")"
|
|
|
|
for i in $(seq 1 254); do
|
|
ping -c 1 -W 1 "${SUBNET_PREFIX}.${i}" >/dev/null 2>&1 &
|
|
# cap concurrency so we don't fork 254 pings at once
|
|
if (( i % 32 == 0 )); then wait; fi
|
|
done
|
|
wait
|
|
|
|
TMP_FILE="$(mktemp)"
|
|
{
|
|
echo "["
|
|
first=1
|
|
# `ip neigh show dev <iface>` output: "<ip> lladdr <mac> <state> [router]"
|
|
while read -r ip _ mac state _; do
|
|
[[ "$ip" == *:* ]] && continue # skip IPv6 (link-local neighbor entries)
|
|
[[ -z "$mac" ]] && continue
|
|
case "$state" in
|
|
REACHABLE|STALE|DELAY|PERMANENT) ;;
|
|
*) continue ;;
|
|
esac
|
|
[[ $first -eq 0 ]] && echo ","
|
|
first=0
|
|
printf '{"ip":"%s","mac":"%s","state":"%s"}' "$ip" "$mac" "$state"
|
|
done < <(ip neigh show dev "$IFACE")
|
|
echo
|
|
echo "]"
|
|
} > "$TMP_FILE"
|
|
|
|
mv "$TMP_FILE" "$OUTPUT_FILE"
|