diff --git a/package/secubox/secubox-app-device-intel/files/usr/lib/secubox/device-intel/functions.sh b/package/secubox/secubox-app-device-intel/files/usr/lib/secubox/device-intel/functions.sh index 33f4a8a2..b118e877 100644 --- a/package/secubox/secubox-app-device-intel/files/usr/lib/secubox/device-intel/functions.sh +++ b/package/secubox/secubox-app-device-intel/files/usr/lib/secubox/device-intel/functions.sh @@ -65,24 +65,33 @@ di_collect_mac_guardian() { } # Collect client-guardian data via UCI -# Format: cg|mac|ip|hostname|zone|status|rx_bytes|tx_bytes|risk_score +# Format: cg|mac|name|zone|status|first_seen|last_seen di_collect_client_guardian() { local idx=0 while uci -q get client-guardian.@client[$idx] >/dev/null 2>&1; do local mac=$(uci -q get client-guardian.@client[$idx].mac) - local ip=$(uci -q get client-guardian.@client[$idx].ip) - local hostname=$(uci -q get client-guardian.@client[$idx].hostname) + local name=$(uci -q get client-guardian.@client[$idx].name) local zone=$(uci -q get client-guardian.@client[$idx].zone) local status=$(uci -q get client-guardian.@client[$idx].status) - local rx=$(uci -q get client-guardian.@client[$idx].rx_bytes) - local tx=$(uci -q get client-guardian.@client[$idx].tx_bytes) - local risk=$(uci -q get client-guardian.@client[$idx].risk_score) + local first_seen=$(uci -q get client-guardian.@client[$idx].first_seen) + local last_seen=$(uci -q get client-guardian.@client[$idx].last_seen) - [ -n "$mac" ] && echo "cg|${mac}|${ip}|${hostname}|${zone}|${status}|${rx:-0}|${tx:-0}|${risk:-0}" + [ -n "$mac" ] && echo "cg|${mac}|${name}|${zone}|${status}|${first_seen}|${last_seen}" idx=$((idx + 1)) done } +# Collect ARP table for IP-to-MAC resolution and online detection +# Format: arp|mac|ip|iface +di_collect_arp() { + while read -r ip hw flags mac mask iface; do + [ "$ip" = "IP" ] && continue # skip header + [ "$mac" = "00:00:00:00:00:00" ] && continue + [ "$flags" = "0x0" ] && continue # incomplete entry + echo "arp|${mac}|${ip}|${iface}" + done < /proc/net/arp +} + # Collect DHCP lease data # Format: dhcp|mac|ip|hostname|expires di_collect_dhcp() { @@ -120,7 +129,7 @@ di_collect_exposure() { while read -r sl local_addr rem_addr st rest; do [ "$st" != "0A" ] && continue # 0A = LISTEN local hex_port=$(echo "$local_addr" | cut -d: -f2) - local port=$((16#$hex_port)) + local port=$(printf "%d" "0x${hex_port}" 2>/dev/null) local hex_ip=$(echo "$local_addr" | cut -d: -f1) # Determine bind address @@ -161,6 +170,7 @@ di_aggregate_devices() { di_collect_mac_guardian > "${tmp_dir}/mg.dat" 2>/dev/null di_collect_client_guardian > "${tmp_dir}/cg.dat" 2>/dev/null di_collect_dhcp > "${tmp_dir}/dhcp.dat" 2>/dev/null + di_collect_arp > "${tmp_dir}/arp.dat" 2>/dev/null di_collect_p2p_peers > "${tmp_dir}/p2p.dat" 2>/dev/null di_collect_exposure > "${tmp_dir}/exp.dat" 2>/dev/null di_collect_emulators > "${tmp_dir}/emu.dat" 2>/dev/null @@ -183,8 +193,8 @@ di_aggregate_devices() { local ip="" hostname="" vendor="" iface="" online="false" local mg_status="" cg_zone="" cg_status="" randomized="false" local first_seen="" last_seen="" label="" device_type="" - local device_type_source="" emulator_source="" rx=0 tx=0 risk=0 - local services="" source_node="local" + local device_type_source="" emulator_source="" + local source_node="local" # Mac-Guardian data local mg=$(grep "^mg|${mac}|" "${tmp_dir}/mg.dat" 2>/dev/null | head -1) @@ -199,18 +209,27 @@ di_aggregate_devices() { last_seen=$(echo "$mg" | cut -d'|' -f9) fi - # Client-Guardian data - local cg=$(grep "^cg|${mac}|" "${tmp_dir}/cg.dat" 2>/dev/null | head -1) + # Client-Guardian data (format: cg|mac|name|zone|status|first_seen|last_seen) + local cg=$(grep -i "^cg|${mac}|" "${tmp_dir}/cg.dat" 2>/dev/null | head -1) if [ -n "$cg" ]; then - local cg_ip=$(echo "$cg" | cut -d'|' -f3) - [ -n "$cg_ip" ] && ip="$cg_ip" - local cg_host=$(echo "$cg" | cut -d'|' -f4) - [ -n "$cg_host" ] && [ -z "$hostname" ] && hostname="$cg_host" - cg_zone=$(echo "$cg" | cut -d'|' -f5) - cg_status=$(echo "$cg" | cut -d'|' -f6) - rx=$(echo "$cg" | cut -d'|' -f7) - tx=$(echo "$cg" | cut -d'|' -f8) - risk=$(echo "$cg" | cut -d'|' -f9) + local cg_name=$(echo "$cg" | cut -d'|' -f3) + [ -n "$cg_name" ] && [ -z "$hostname" ] && hostname="$cg_name" + cg_zone=$(echo "$cg" | cut -d'|' -f4) + cg_status=$(echo "$cg" | cut -d'|' -f5) + local cg_first=$(echo "$cg" | cut -d'|' -f6) + local cg_last=$(echo "$cg" | cut -d'|' -f7) + [ -n "$cg_first" ] && [ -z "$first_seen" ] && first_seen="$cg_first" + [ -n "$cg_last" ] && [ -z "$last_seen" ] && last_seen="$cg_last" + fi + + # ARP data — provides IP and online detection + local arp=$(grep -i "|${mac}|" "${tmp_dir}/arp.dat" 2>/dev/null | head -1) + if [ -n "$arp" ]; then + local arp_ip=$(echo "$arp" | cut -d'|' -f3) + [ -n "$arp_ip" ] && [ -z "$ip" ] && ip="$arp_ip" + local arp_iface=$(echo "$arp" | cut -d'|' -f4) + [ -n "$arp_iface" ] && [ -z "$iface" ] && iface="$arp_iface" + online="true" # present in ARP = reachable fi # DHCP data @@ -272,12 +291,9 @@ di_aggregate_devices() { [ -n "$device_type" ] && printf ',"device_type":"%s"' "$device_type" [ -n "$device_type_source" ] && printf ',"device_type_source":"%s"' "$device_type_source" [ -n "$emulator_source" ] && printf ',"emulator_source":"%s"' "$emulator_source" - printf ',"rx_bytes":%s' "${rx:-0}" - printf ',"tx_bytes":%s' "${tx:-0}" - printf ',"risk_score":%s' "${risk:-0}" printf ',"source_node":"%s"' "$source_node" - [ -n "$first_seen" ] && printf ',"first_seen":%s' "$first_seen" - [ -n "$last_seen" ] && printf ',"last_seen":%s' "$last_seen" + [ -n "$first_seen" ] && printf ',"first_seen":"%s"' "$first_seen" + [ -n "$last_seen" ] && printf ',"last_seen":"%s"' "$last_seen" printf '}' done @@ -339,12 +355,11 @@ di_get_devices() { di_get_summary() { local devices=$(di_get_devices) - local total=0 online=0 mesh=0 iot=0 storage=0 compute=0 + local total=0 online=0 mesh=0 - # Count using jsonfilter total=$(echo "$devices" | jsonfilter -e '@[*].mac' 2>/dev/null | wc -l) - online=$(echo "$devices" | jsonfilter -e '@[*]' 2>/dev/null | grep '"online":true' | wc -l) - mesh=$(echo "$devices" | jsonfilter -e '@[*]' 2>/dev/null | grep '"device_type":"mesh_peer"' | wc -l) + online=$(echo "$devices" | jsonfilter -e '@[*].online' 2>/dev/null | grep -c "true") + mesh=$(echo "$devices" | jsonfilter -e '@[*].device_type' 2>/dev/null | grep -c "mesh_peer") printf '{"total":%d,"online":%d,"mesh_peers":%d}' \ "$total" "$online" "$mesh" diff --git a/package/secubox/secubox-app-device-intel/files/usr/sbin/device-intelctl b/package/secubox/secubox-app-device-intel/files/usr/sbin/device-intelctl index b5b0909c..c728bf16 100644 --- a/package/secubox/secubox-app-device-intel/files/usr/sbin/device-intelctl +++ b/package/secubox/secubox-app-device-intel/files/usr/sbin/device-intelctl @@ -17,7 +17,7 @@ log() { echo -e "${GREEN}[INTEL]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; } -uci_get() { uci -q get ${CONFIG}.$1; } +di_ctl_get() { uci -q get ${CONFIG}.$1; } # Load libraries . "${LIB_DIR}/functions.sh" @@ -101,9 +101,8 @@ cmd_show() { local dtype=$(echo "$device" | jsonfilter -e '@.device_type' 2>/dev/null) local dsrc=$(echo "$device" | jsonfilter -e '@.device_type_source' 2>/dev/null) local emu=$(echo "$device" | jsonfilter -e '@.emulator_source' 2>/dev/null) - local rx=$(echo "$device" | jsonfilter -e '@.rx_bytes' 2>/dev/null) - local tx=$(echo "$device" | jsonfilter -e '@.tx_bytes' 2>/dev/null) - local risk=$(echo "$device" | jsonfilter -e '@.risk_score' 2>/dev/null) + local first_seen=$(echo "$device" | jsonfilter -e '@.first_seen' 2>/dev/null) + local last_seen=$(echo "$device" | jsonfilter -e '@.last_seen' 2>/dev/null) echo " IP: ${ip:--}" echo " Hostname: ${hostname:--}" @@ -117,16 +116,15 @@ cmd_show() { echo " MAC Status: ${mg_status:--}" echo " NAC Zone: ${cg_zone:--}" echo " NAC Status: ${cg_status:--}" - echo " Risk Score: ${risk:-0}" echo "" echo " ── Classification ──" echo " Device Type: ${dtype:--}" echo " Source: ${dsrc:--}" [ -n "$emu" ] && echo " Emulator: $emu" echo "" - echo " ── Traffic ──" - echo " RX: ${rx:-0} bytes" - echo " TX: ${tx:-0} bytes" + echo " ── Timeline ──" + echo " First Seen: ${first_seen:--}" + echo " Last Seen: ${last_seen:--}" echo "" } @@ -214,7 +212,7 @@ cmd_summary() { # Emulator status echo " ── Emulators ──" for emu in usb mqtt zigbee; do - local enabled=$(uci_get "${emu}.enabled") + local enabled=$(di_ctl_get "${emu}.enabled") if [ "$enabled" = "1" ]; then echo -e " ${emu}: ${GREEN}enabled${NC}" else @@ -246,7 +244,7 @@ cmd_emulators() { echo "" for emu in usb mqtt zigbee; do - local enabled=$(uci_get "${emu}.enabled") + local enabled=$(di_ctl_get "${emu}.enabled") echo -e " ${CYAN}${emu}${NC}:" echo -e " Enabled: $([ "$enabled" = "1" ] && echo "${GREEN}Yes${NC}" || echo "${RED}No${NC}")" @@ -257,16 +255,16 @@ cmd_emulators() { echo " Devices: $count USB device(s)" ;; mqtt) - local host=$(uci_get mqtt.broker_host) - local port=$(uci_get mqtt.broker_port) + local host=$(di_ctl_get mqtt.broker_host) + local port=$(di_ctl_get mqtt.broker_port) echo " Broker: ${host:-127.0.0.1}:${port:-1883}" pgrep mosquitto >/dev/null 2>&1 && \ echo -e " Status: ${GREEN}broker running${NC}" || \ echo -e " Status: ${RED}broker not found${NC}" ;; zigbee) - local adapter=$(uci_get zigbee.adapter) - local coord=$(uci_get zigbee.coordinator) + local adapter=$(di_ctl_get zigbee.adapter) + local coord=$(di_ctl_get zigbee.coordinator) echo " Adapter: ${adapter:-zigbee2mqtt}" echo " Dongle: ${coord:-/dev/ttyUSB0}" [ -c "${coord:-/dev/ttyUSB0}" ] 2>/dev/null && \