#!/bin/sh
# Record what a device said about itself when it asked for an address.
#
# dnsmasq's dhcp-script (the panel's dnsmasq.conf names it, 1.91.8), run as
# the dnsmasq account on every lease event:
#
#	panel-dhcp-device add|old|del <mac> <ip> [hostname]
#
# with the request's details in the environment. Measured on dnsmasq 2.91:
# DNSMASQ_REQUESTED_OPTIONS (option 55, in the client's order),
# DNSMASQ_VENDOR_CLASS (option 60) and DNSMASQ_SUPPLIED_HOSTNAME (option 12)
# are set when a device actually asked; a "del", or an "old" replayed when
# dnsmasq starts, has no request behind it and sets none of them. Only a
# real request is written down, so a restart never erases what a device
# said with nothing.
#
# One small file per MAC in $DIR, read by the panel's DHCP and network
# modules (internal/devid) to show "Android phone or tablet" under a name.
#
# EVERY VALUE HERE WAS CHOSEN BY THE DEVICE. It is treated as data only:
# never evaluated, control characters removed so it cannot add lines to the
# record, cut to a length, and the MAC -- which names the file -- must be
# exactly a MAC. Nothing here can fail a lease: dnsmasq ignores the exit
# status of a lease script, and this exits 0 regardless.
DIR=/var/lib/misc/panel-devices

case "${1:-}" in
add|old) ;;
*) exit 0 ;;
esac
[ -n "${DNSMASQ_REQUESTED_OPTIONS:-}" ] || exit 0
[ -d "$DIR" ] || exit 0

mac=${2:-}
case "$mac" in
*[!0-9a-f:]*|"") exit 0 ;;
esac
[ "${#mac}" -eq 17 ] || exit 0

clean() {
	printf '%s' "$1" | tr -d '\000-\037\177' | cut -c1-100
}

file="$DIR/$(printf '%s' "$mac" | tr ':' '-')"
tmp="$DIR/.new.$$"
{
	printf 'options=%s\n' "$(clean "$DNSMASQ_REQUESTED_OPTIONS")"
	printf 'vendor=%s\n' "$(clean "${DNSMASQ_VENDOR_CLASS:-}")"
	printf 'hostname=%s\n' "$(clean "${DNSMASQ_SUPPLIED_HOSTNAME:-${4:-}}")"
	printf 'seen=%s\n' "$(date +%s)"
} > "$tmp" 2>/dev/null && mv -f "$tmp" "$file" 2>/dev/null
rm -f "$tmp" 2>/dev/null

# Randomised addresses make new files over time; a record nobody has
# renewed in 90 days is a device that is gone.
find "$DIR" -maxdepth 1 -type f -mtime +90 -delete 2>/dev/null
exit 0
