- Fix wrong mac-guardian DB path (clients.db -> known.db) in 3 files - Add standalone OUI vendor fallback for ARP/DHCP-only devices - Expand oui.tsv from ~30 to 100+ entries (GL.iNet, Bosch, Samsung, Docker, etc.) - Add vendorDisplay() with emoji prefixes for MAC types: container, virtual, randomized, IoT, mesh peer Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
253 lines
7.2 KiB
Bash
253 lines
7.2 KiB
Bash
#!/bin/sh
|
|
#
|
|
# RPCD backend for SecuBox Device Intelligence
|
|
#
|
|
|
|
. /usr/share/libubox/jshn.sh
|
|
. /lib/functions.sh
|
|
|
|
DI_LIB="/usr/lib/secubox/device-intel"
|
|
DI_CACHE="/tmp/device-intel"
|
|
CONFIG="device-intel"
|
|
|
|
case "$1" in
|
|
list)
|
|
json_init
|
|
json_add_object "get_devices"
|
|
json_close_object
|
|
json_add_object "get_device"
|
|
json_add_string "mac" "string"
|
|
json_close_object
|
|
json_add_object "get_summary"
|
|
json_close_object
|
|
json_add_object "get_mesh_devices"
|
|
json_close_object
|
|
json_add_object "get_emulators"
|
|
json_close_object
|
|
json_add_object "get_device_types"
|
|
json_close_object
|
|
json_add_object "classify_device"
|
|
json_add_string "mac" "string"
|
|
json_close_object
|
|
json_add_object "set_device_meta"
|
|
json_add_string "mac" "string"
|
|
json_add_string "type" "string"
|
|
json_add_string "label" "string"
|
|
json_close_object
|
|
json_add_object "refresh"
|
|
json_close_object
|
|
json_dump
|
|
;;
|
|
|
|
call)
|
|
handle_call() {
|
|
case "$1" in
|
|
get_devices)
|
|
. "${DI_LIB}/functions.sh"
|
|
local devices=$(di_get_devices)
|
|
|
|
# Stream directly — devices is already JSON array
|
|
printf '{"success":true,"devices":%s}' "$devices"
|
|
;;
|
|
|
|
get_device)
|
|
read -r input
|
|
local mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null)
|
|
|
|
if [ -z "$mac" ]; then
|
|
echo '{"success":false,"error":"mac is required"}'
|
|
exit 0
|
|
fi
|
|
|
|
. "${DI_LIB}/functions.sh"
|
|
local devices=$(di_get_devices)
|
|
local mac_lower=$(echo "$mac" | tr 'A-F' 'a-f')
|
|
|
|
# Extract single device from array
|
|
local device=$(echo "$devices" | jsonfilter -e "@[@.mac='${mac_lower}']" 2>/dev/null)
|
|
|
|
if [ -n "$device" ]; then
|
|
printf '{"success":true,"device":%s}' "$device"
|
|
else
|
|
echo '{"success":false,"error":"Device not found"}'
|
|
fi
|
|
;;
|
|
|
|
get_summary)
|
|
. "${DI_LIB}/functions.sh"
|
|
local summary=$(di_get_summary)
|
|
|
|
# Add emulator counts
|
|
local usb_enabled=$(uci -q get ${CONFIG}.usb.enabled)
|
|
local mqtt_enabled=$(uci -q get ${CONFIG}.mqtt.enabled)
|
|
local zigbee_enabled=$(uci -q get ${CONFIG}.zigbee.enabled)
|
|
|
|
# Count data sources
|
|
local mg_available=0
|
|
[ -f /var/run/mac-guardian/known.db ] && mg_available=1
|
|
local cg_available=0
|
|
uci -q get client-guardian.@client[0] >/dev/null 2>&1 && cg_available=1
|
|
local dhcp_available=0
|
|
[ -f /tmp/dhcp.leases ] && dhcp_available=1
|
|
local p2p_running=0
|
|
pgrep -f secubox-p2p >/dev/null 2>&1 && p2p_running=1
|
|
|
|
# Build response
|
|
local total=$(echo "$summary" | jsonfilter -e '@.total' 2>/dev/null)
|
|
local online=$(echo "$summary" | jsonfilter -e '@.online' 2>/dev/null)
|
|
local mesh=$(echo "$summary" | jsonfilter -e '@.mesh_peers' 2>/dev/null)
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_int "total" "${total:-0}"
|
|
json_add_int "online" "${online:-0}"
|
|
json_add_int "mesh_peers" "${mesh:-0}"
|
|
|
|
json_add_object "emulators"
|
|
json_add_boolean "usb" "$([ "$usb_enabled" = "1" ] && echo 1 || echo 0)"
|
|
json_add_boolean "mqtt" "$([ "$mqtt_enabled" = "1" ] && echo 1 || echo 0)"
|
|
json_add_boolean "zigbee" "$([ "$zigbee_enabled" = "1" ] && echo 1 || echo 0)"
|
|
json_close_object
|
|
|
|
json_add_object "sources"
|
|
json_add_boolean "mac_guardian" "$mg_available"
|
|
json_add_boolean "client_guardian" "$cg_available"
|
|
json_add_boolean "dhcp" "$dhcp_available"
|
|
json_add_boolean "p2p" "$p2p_running"
|
|
json_close_object
|
|
|
|
json_dump
|
|
;;
|
|
|
|
get_mesh_devices)
|
|
. "${DI_LIB}/functions.sh"
|
|
local devices=$(di_get_devices)
|
|
|
|
# Filter mesh devices
|
|
printf '{"success":true,"devices":['
|
|
local first=1
|
|
echo "$devices" | jsonfilter -e '@[*]' 2>/dev/null | while read -r dev; do
|
|
local src=$(echo "$dev" | jsonfilter -e '@.source_node' 2>/dev/null)
|
|
local dtype=$(echo "$dev" | jsonfilter -e '@.device_type' 2>/dev/null)
|
|
if [ "$src" = "mesh" ] || [ "$dtype" = "mesh_peer" ]; then
|
|
[ $first -eq 1 ] && first=0 || printf ','
|
|
echo "$dev"
|
|
fi
|
|
done
|
|
printf ']}'
|
|
;;
|
|
|
|
get_emulators)
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
|
|
# USB
|
|
json_add_object "usb"
|
|
json_add_boolean "enabled" "$([ "$(uci -q get ${CONFIG}.usb.enabled)" = "1" ] && echo 1 || echo 0)"
|
|
json_add_int "scan_interval" "$(uci -q get ${CONFIG}.usb.scan_interval || echo 120)"
|
|
local usb_count=$(ls -d /sys/bus/usb/devices/[0-9]* 2>/dev/null | grep -v ':' | wc -l)
|
|
json_add_int "device_count" "$usb_count"
|
|
json_close_object
|
|
|
|
# MQTT
|
|
json_add_object "mqtt"
|
|
json_add_boolean "enabled" "$([ "$(uci -q get ${CONFIG}.mqtt.enabled)" = "1" ] && echo 1 || echo 0)"
|
|
json_add_string "broker_host" "$(uci -q get ${CONFIG}.mqtt.broker_host)"
|
|
json_add_int "broker_port" "$(uci -q get ${CONFIG}.mqtt.broker_port || echo 1883)"
|
|
local mqtt_running=0
|
|
pgrep mosquitto >/dev/null 2>&1 && mqtt_running=1
|
|
json_add_boolean "broker_running" "$mqtt_running"
|
|
json_close_object
|
|
|
|
# Zigbee
|
|
json_add_object "zigbee"
|
|
json_add_boolean "enabled" "$([ "$(uci -q get ${CONFIG}.zigbee.enabled)" = "1" ] && echo 1 || echo 0)"
|
|
json_add_string "adapter" "$(uci -q get ${CONFIG}.zigbee.adapter)"
|
|
json_add_string "coordinator" "$(uci -q get ${CONFIG}.zigbee.coordinator)"
|
|
local dongle_present=0
|
|
local coord=$(uci -q get ${CONFIG}.zigbee.coordinator)
|
|
[ -c "${coord:-/dev/ttyUSB0}" ] 2>/dev/null && dongle_present=1
|
|
json_add_boolean "dongle_present" "$dongle_present"
|
|
json_close_object
|
|
|
|
json_dump
|
|
;;
|
|
|
|
get_device_types)
|
|
. "${DI_LIB}/functions.sh"
|
|
local types=$(di_get_device_types)
|
|
printf '{"success":true,"types":%s}' "$types"
|
|
;;
|
|
|
|
classify_device)
|
|
read -r input
|
|
local mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null)
|
|
|
|
. "${DI_LIB}/functions.sh"
|
|
. "${DI_LIB}/classify.sh"
|
|
|
|
if [ -n "$mac" ]; then
|
|
local output=$(/usr/sbin/device-intelctl classify "$mac" 2>&1)
|
|
else
|
|
local output=$(/usr/sbin/device-intelctl classify 2>&1)
|
|
fi
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "output" "$output"
|
|
json_dump
|
|
;;
|
|
|
|
set_device_meta)
|
|
read -r input
|
|
local mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null)
|
|
local dtype=$(echo "$input" | jsonfilter -e '@.type' 2>/dev/null)
|
|
local label=$(echo "$input" | jsonfilter -e '@.label' 2>/dev/null)
|
|
|
|
if [ -z "$mac" ]; then
|
|
echo '{"success":false,"error":"mac is required"}'
|
|
exit 0
|
|
fi
|
|
|
|
local mac_lower=$(echo "$mac" | tr 'A-F' 'a-f')
|
|
local mac_clean=$(echo "$mac_lower" | tr -d ':')
|
|
|
|
# Create/update UCI section
|
|
uci set ${CONFIG}.${mac_clean}=device
|
|
uci set ${CONFIG}.${mac_clean}.mac="$mac_lower"
|
|
[ -n "$dtype" ] && uci set ${CONFIG}.${mac_clean}.type="$dtype"
|
|
[ -n "$label" ] && uci set ${CONFIG}.${mac_clean}.label="$label"
|
|
uci commit "$CONFIG"
|
|
|
|
# Invalidate cache
|
|
rm -f "${DI_CACHE}"/cache*.json 2>/dev/null
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Device metadata updated"
|
|
json_dump
|
|
;;
|
|
|
|
refresh)
|
|
rm -f "${DI_CACHE}"/cache*.json 2>/dev/null
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Cache invalidated"
|
|
json_dump
|
|
;;
|
|
|
|
*)
|
|
json_init
|
|
json_add_boolean "error" 1
|
|
json_add_string "message" "Unknown method: $1"
|
|
json_dump
|
|
;;
|
|
esac
|
|
}
|
|
handle_call "$2"
|
|
;;
|
|
esac
|
|
|
|
exit 0
|