#!/bin/sh . /lib/functions.sh . /usr/share/libubox/jshn.sh MG_DBFILE="/var/run/mac-guardian/known.db" MG_LOGFILE="/var/log/mac-guardian.log" case "$1" in list) echo '{"status":{},"get_clients":{},"get_events":{"count":"int"},"scan":{},"start":{},"stop":{},"restart":{},"trust":{"mac":"str"},"block":{"mac":"str"},"dhcp_status":{},"dhcp_cleanup":{}}' ;; call) case "$2" in status) json_init enabled=$(uci -q get mac-guardian.main.enabled) policy=$(uci -q get mac-guardian.enforcement.policy) scan_interval=$(uci -q get mac-guardian.main.scan_interval) detect_random=$(uci -q get mac-guardian.detection.random_mac) detect_spoof=$(uci -q get mac-guardian.detection.spoof_detection) json_add_boolean "enabled" ${enabled:-0} json_add_string "policy" "${policy:-alert}" json_add_int "scan_interval" ${scan_interval:-30} json_add_boolean "detect_random" ${detect_random:-1} json_add_boolean "detect_spoof" ${detect_spoof:-1} # Service running? if pgrep mac-guardian >/dev/null 2>&1; then json_add_string "service_status" "running" else json_add_string "service_status" "stopped" fi # WiFi interfaces json_add_array "interfaces" if command -v iwinfo >/dev/null 2>&1; then iwinfo 2>/dev/null | grep "ESSID" | while read -r line; do iface=$(echo "$line" | awk '{print $1}') essid=$(echo "$line" | sed 's/.*ESSID: "\(.*\)"/\1/') sta_count=$(iwinfo "$iface" assoclist 2>/dev/null | grep -cE '[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}') json_add_object "" json_add_string "name" "$iface" json_add_string "essid" "$essid" json_add_int "stations" ${sta_count:-0} json_close_object done fi json_close_array # DB stats total=0 trusted=0 suspect=0 blocked=0 unknown=0 if [ -f "$MG_DBFILE" ] && [ -s "$MG_DBFILE" ]; then total=$(wc -l < "$MG_DBFILE") trusted=$(grep -c '|trusted$' "$MG_DBFILE" 2>/dev/null || echo 0) suspect=$(grep -c '|suspect$' "$MG_DBFILE" 2>/dev/null || echo 0) blocked=$(grep -c '|blocked$' "$MG_DBFILE" 2>/dev/null || echo 0) unknown=$(grep -c '|unknown$' "$MG_DBFILE" 2>/dev/null || echo 0) fi json_add_object "clients" json_add_int "total" $total json_add_int "trusted" $trusted json_add_int "suspect" $suspect json_add_int "blocked" $blocked json_add_int "unknown" $unknown json_close_object json_dump ;; get_clients) json_init json_add_array "clients" if [ -f "$MG_DBFILE" ] && [ -s "$MG_DBFILE" ]; then while IFS='|' read -r mac oui first_seen last_seen iface hostname status; do [ -z "$mac" ] && continue json_add_object "" json_add_string "mac" "$mac" json_add_string "oui" "$oui" json_add_int "first_seen" ${first_seen:-0} json_add_int "last_seen" ${last_seen:-0} json_add_string "iface" "$iface" json_add_string "hostname" "${hostname:--}" json_add_string "status" "$status" # OUI vendor lookup vendor="" if [ -f /usr/lib/secubox/mac-guardian/oui.tsv ]; then oui_upper=$(echo "$oui" | tr 'a-f' 'A-F') vendor=$(grep -i "^${oui_upper} " /usr/lib/secubox/mac-guardian/oui.tsv 2>/dev/null | cut -f2 | head -1) fi json_add_string "vendor" "${vendor:--}" # Randomized check first_octet=$(echo "$mac" | cut -d: -f1) is_rand=0 [ $((0x$first_octet & 0x02)) -ne 0 ] && is_rand=1 json_add_boolean "randomized" $is_rand json_close_object done < "$MG_DBFILE" fi json_close_array json_dump ;; get_events) read -r input count=$(echo "$input" | jsonfilter -e '@.count' 2>/dev/null) [ -z "$count" ] && count=20 json_init json_add_array "events" if [ -f "$MG_LOGFILE" ] && [ -s "$MG_LOGFILE" ]; then tail -"$count" "$MG_LOGFILE" 2>/dev/null | while read -r line; do json_add_string "" "$line" done fi json_close_array json_dump ;; scan) /usr/sbin/mac-guardian scan >/dev/null 2>&1 json_init json_add_boolean "success" 1 json_dump ;; start) /etc/init.d/mac-guardian start >/dev/null 2>&1 json_init json_add_boolean "success" 1 json_dump ;; stop) /etc/init.d/mac-guardian stop >/dev/null 2>&1 json_init json_add_boolean "success" 1 json_dump ;; restart) /etc/init.d/mac-guardian restart >/dev/null 2>&1 json_init json_add_boolean "success" 1 json_dump ;; trust) read -r input mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null) if [ -n "$mac" ]; then /usr/sbin/mac-guardian trust "$mac" >/dev/null 2>&1 json_init json_add_boolean "success" 1 json_dump else echo '{"success":false,"error":"missing mac"}' fi ;; block) read -r input mac=$(echo "$input" | jsonfilter -e '@.mac' 2>/dev/null) if [ -n "$mac" ]; then /usr/sbin/mac-guardian block "$mac" >/dev/null 2>&1 json_init json_add_boolean "success" 1 json_dump else echo '{"success":false,"error":"missing mac"}' fi ;; dhcp_status) json_init dhcp_enabled=$(uci -q get mac-guardian.dhcp.enabled) json_add_boolean "enabled" ${dhcp_enabled:-1} leases=0 conflicts=0 stale=0 if [ -f /tmp/dhcp.leases ] && [ -s /tmp/dhcp.leases ]; then leases=$(wc -l < /tmp/dhcp.leases) # Count hostname conflicts conflicts=$(awk '{print $4}' /tmp/dhcp.leases | grep -v '^\*$' | sort | uniq -d | wc -l) # Count stale leases now=$(date +%s) stale_timeout=$(uci -q get mac-guardian.dhcp.stale_timeout) stale_timeout=${stale_timeout:-3600} cutoff=$((now - stale_timeout)) stale=$(awk -v cutoff="$cutoff" '$1 < cutoff' /tmp/dhcp.leases | wc -l) fi json_add_int "leases" $leases json_add_int "conflicts" $conflicts json_add_int "stale" $stale json_dump ;; dhcp_cleanup) /usr/sbin/mac-guardian dhcp-cleanup >/dev/null 2>&1 removed=0 json_init json_add_boolean "success" 1 json_add_int "removed" $removed json_dump ;; esac ;; esac exit 0