secubox-openwrt/package/secubox/secubox-iot-guard/root/usr/sbin/iot-guardctl
CyberMind-FR 8ef0c70d0f feat(iot-guard): Add IoT device isolation and security monitoring
Backend (secubox-iot-guard):
- OUI-based device classification with 100+ IoT vendor prefixes
- 10 device classes: camera, thermostat, lighting, plug, assistant, etc.
- Risk scoring (0-100) with auto-isolation threshold
- Anomaly detection: bandwidth spikes, port scans, time anomalies
- Integration with Client Guardian, MAC Guardian, Vortex Firewall
- iot-guardctl CLI for status/list/scan/isolate/trust/block
- SQLite database for devices, anomalies, cloud dependencies
- Traffic baseline profiles for common device classes

Frontend (luci-app-iot-guard):
- KISS-style overview dashboard with security score
- Device management with isolate/trust/block actions
- Vendor classification rules editor
- Settings form for UCI configuration
- RPCD handler with 11 methods
- Public ACL for unauthenticated dashboard access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 10:36:04 +01:00

784 lines
24 KiB
Bash

#!/bin/sh
#
# iot-guardctl - IoT Guard Controller
#
# IoT device isolation, classification, and security monitoring.
# Orchestrates existing SecuBox modules for IoT protection.
#
# Usage:
# iot-guardctl status Overview status
# iot-guardctl list [--json] List IoT devices
# iot-guardctl show <mac> Device detail
# iot-guardctl scan Network scan
# iot-guardctl isolate <mac> Move to IoT zone
# iot-guardctl trust <mac> Add to allowlist
# iot-guardctl block <mac> Block device
# iot-guardctl anomalies Show anomalies
# iot-guardctl cloud-map <mac> Show cloud dependencies
#
VERSION="1.0.0"
NAME="iot-guard"
# Directories
VAR_DIR="/var/lib/iot-guard"
CACHE_DIR="/tmp/iot-guard"
DB_FILE="$VAR_DIR/iot-guard.db"
OUI_FILE="/usr/lib/secubox/iot-guard/iot-oui.tsv"
BASELINE_DIR="/usr/share/iot-guard/baseline-profiles"
# Load libraries
. /usr/lib/secubox/iot-guard/functions.sh
[ -f /usr/lib/secubox/iot-guard/classify.sh ] && . /usr/lib/secubox/iot-guard/classify.sh
[ -f /usr/lib/secubox/iot-guard/anomaly.sh ] && . /usr/lib/secubox/iot-guard/anomaly.sh
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
BOLD='\033[1m'
NC='\033[0m'
log() { echo -e "${GREEN}[IOT-GUARD]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
info() { echo -e "${CYAN}[INFO]${NC} $1"; }
# ============================================================================
# Initialization
# ============================================================================
init_dirs() {
mkdir -p "$VAR_DIR" "$CACHE_DIR"
}
init_db() {
if [ ! -f "$DB_FILE" ]; then
log "Initializing IoT Guard database..."
sqlite3 "$DB_FILE" <<'EOF'
CREATE TABLE IF NOT EXISTS devices (
mac TEXT PRIMARY KEY,
ip TEXT,
hostname TEXT,
vendor TEXT,
device_class TEXT DEFAULT 'unknown',
risk_level TEXT DEFAULT 'unknown',
risk_score INTEGER DEFAULT 0,
zone TEXT DEFAULT 'lan',
status TEXT DEFAULT 'active',
first_seen TEXT,
last_seen TEXT,
isolated INTEGER DEFAULT 0,
trusted INTEGER DEFAULT 0,
blocked INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS anomalies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mac TEXT,
timestamp TEXT,
anomaly_type TEXT,
severity TEXT,
description TEXT,
resolved INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS cloud_deps (
id INTEGER PRIMARY KEY AUTOINCREMENT,
mac TEXT,
domain TEXT,
first_seen TEXT,
last_seen TEXT,
query_count INTEGER DEFAULT 1
);
CREATE TABLE IF NOT EXISTS traffic_baseline (
mac TEXT PRIMARY KEY,
avg_bps_in REAL DEFAULT 0,
avg_bps_out REAL DEFAULT 0,
peak_bps_in REAL DEFAULT 0,
peak_bps_out REAL DEFAULT 0,
common_ports TEXT,
sample_count INTEGER DEFAULT 0,
last_update TEXT
);
CREATE INDEX IF NOT EXISTS idx_devices_class ON devices(device_class);
CREATE INDEX IF NOT EXISTS idx_devices_risk ON devices(risk_level);
CREATE INDEX IF NOT EXISTS idx_anomalies_mac ON anomalies(mac);
CREATE INDEX IF NOT EXISTS idx_cloud_mac ON cloud_deps(mac);
EOF
log "Database initialized: $DB_FILE"
fi
}
# ============================================================================
# Network Scanning
# ============================================================================
scan_network() {
init_dirs
init_db
log "Scanning network for IoT devices..."
local now=$(date -Iseconds)
local found=0
local classified=0
# Get devices from ARP table
arp -n 2>/dev/null | grep -v "incomplete" | tail -n +2 | while read -r line; do
local ip=$(echo "$line" | awk '{print $1}')
local mac=$(echo "$line" | awk '{print $3}' | tr '[:lower:]' '[:upper:]')
[ -z "$mac" ] && continue
[ "$mac" = "<INCOMPLETE>" ] && continue
# Get hostname from DHCP leases
local hostname=""
if [ -f /tmp/dhcp.leases ]; then
hostname=$(grep -i "$mac" /tmp/dhcp.leases 2>/dev/null | awk '{print $4}' | head -1)
fi
[ -z "$hostname" ] && hostname="unknown"
# Classify device
local oui=$(echo "$mac" | cut -d':' -f1-3)
local vendor=$(lookup_vendor "$oui")
local class=$(classify_device "$mac" "$vendor")
local risk=$(get_risk_level "$vendor" "$class")
local score=$(calculate_risk_score "$mac" "$vendor" "$class")
# Insert or update device
sqlite3 "$DB_FILE" "INSERT OR REPLACE INTO devices
(mac, ip, hostname, vendor, device_class, risk_level, risk_score, first_seen, last_seen)
VALUES ('$mac', '$ip', '$hostname', '$vendor', '$class', '$risk', $score,
COALESCE((SELECT first_seen FROM devices WHERE mac='$mac'), '$now'), '$now');"
found=$((found + 1))
[ "$class" != "unknown" ] && classified=$((classified + 1))
# Check for auto-isolation
check_auto_isolate "$mac" "$vendor" "$class" "$score"
done
log "Scan complete: $found devices found"
}
lookup_vendor() {
local oui="$1"
# Try IoT-specific OUI database first
if [ -f "$OUI_FILE" ]; then
local result=$(grep -i "^$oui" "$OUI_FILE" 2>/dev/null | cut -f2)
[ -n "$result" ] && { echo "$result"; return; }
fi
# Fallback to system OUI database
if [ -f /usr/share/misc/oui.txt ]; then
local result=$(grep -i "^$oui" /usr/share/misc/oui.txt 2>/dev/null | cut -d' ' -f2)
[ -n "$result" ] && { echo "$result"; return; }
fi
echo "Unknown"
}
classify_device() {
local mac="$1"
local vendor="$2"
# Check UCI vendor rules
local class=""
config_load iot-guard
config_foreach _classify_by_rule vendor_rule "$mac" "$vendor"
[ -n "$IOT_DEVICE_CLASS" ] && { echo "$IOT_DEVICE_CLASS"; return; }
# Keyword-based classification
case "$vendor" in
*Ring*|*Nest*Cam*|*Wyze*|*Eufy*|*Arlo*|*Reolink*)
echo "camera" ;;
*Nest*|*Ecobee*|*Honeywell*|*Tado*)
echo "thermostat" ;;
*Hue*|*LIFX*|*Wiz*|*Sengled*)
echo "lighting" ;;
*Kasa*|*Wemo*|*Gosund*|*Teckin*)
echo "plug" ;;
*Echo*|*Alexa*|*Google*Home*|*Sonos*)
echo "assistant" ;;
*Sonos*|*Bose*|*Samsung*TV*|*LG*TV*|*Roku*|*Chromecast*)
echo "media" ;;
*August*|*Yale*|*Schlage*)
echo "lock" ;;
*Ring*Doorbell*|*Nest*Doorbell*)
echo "doorbell" ;;
*Xiaomi*|*Tuya*|*Espressif*|*ESP*)
echo "mixed" ;;
*)
echo "unknown" ;;
esac
}
_classify_by_rule() {
local section="$1"
local mac="$2"
local vendor="$3"
local pattern oui_prefix device_class
config_get pattern "$section" vendor_pattern
config_get oui_prefix "$section" oui_prefix
config_get device_class "$section" device_class
# Match by OUI prefix
if [ -n "$oui_prefix" ]; then
local mac_prefix=$(echo "$mac" | cut -d':' -f1-3 | tr '[:lower:]' '[:upper:]')
local check_prefix=$(echo "$oui_prefix" | tr '[:lower:]' '[:upper:]')
if [ "$mac_prefix" = "$check_prefix" ]; then
IOT_DEVICE_CLASS="$device_class"
return 0
fi
fi
# Match by vendor pattern
if [ -n "$pattern" ]; then
if echo "$vendor" | grep -qiE "$pattern"; then
IOT_DEVICE_CLASS="$device_class"
return 0
fi
fi
}
get_risk_level() {
local vendor="$1"
local class="$2"
# Check UCI vendor rules for risk level
config_load iot-guard
local risk_level=""
config_foreach _get_risk_by_rule vendor_rule "$vendor"
[ -n "$IOT_RISK_LEVEL" ] && { echo "$IOT_RISK_LEVEL"; return; }
# Default risk by class
case "$class" in
camera|doorbell)
echo "medium" ;;
thermostat|lighting)
echo "low" ;;
plug|assistant)
echo "medium" ;;
lock)
echo "high" ;;
mixed|diy)
echo "high" ;;
*)
echo "unknown" ;;
esac
}
_get_risk_by_rule() {
local section="$1"
local vendor="$2"
local pattern risk_level
config_get pattern "$section" vendor_pattern
config_get risk_level "$section" risk_level
if [ -n "$pattern" ] && echo "$vendor" | grep -qiE "$pattern"; then
IOT_RISK_LEVEL="$risk_level"
return 0
fi
}
calculate_risk_score() {
local mac="$1"
local vendor="$2"
local class="$3"
local score=0
# Base score by risk level
case "$(get_risk_level "$vendor" "$class")" in
low) score=20 ;;
medium) score=50 ;;
high) score=80 ;;
*) score=40 ;;
esac
# Add anomaly penalty
local anomaly_count=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM anomalies WHERE mac='$mac' AND resolved=0;" 2>/dev/null || echo 0)
score=$((score + anomaly_count * 10))
# Add cloud dependency penalty (many cloud deps = higher risk)
local cloud_count=$(sqlite3 "$DB_FILE" "SELECT COUNT(DISTINCT domain) FROM cloud_deps WHERE mac='$mac';" 2>/dev/null || echo 0)
[ "$cloud_count" -gt 10 ] && score=$((score + 10))
[ "$cloud_count" -gt 20 ] && score=$((score + 10))
# Cap at 100
[ "$score" -gt 100 ] && score=100
echo "$score"
}
check_auto_isolate() {
local mac="$1"
local vendor="$2"
local class="$3"
local score="$4"
local auto_isolate threshold
config_get_bool auto_isolate main auto_isolate 0
config_get threshold main auto_isolate_threshold 80
[ "$auto_isolate" -eq 0 ] && return
# Check if already isolated
local is_isolated=$(sqlite3 "$DB_FILE" "SELECT isolated FROM devices WHERE mac='$mac';" 2>/dev/null || echo 0)
[ "$is_isolated" = "1" ] && return
# Check if trusted
local is_trusted=$(sqlite3 "$DB_FILE" "SELECT trusted FROM devices WHERE mac='$mac';" 2>/dev/null || echo 0)
[ "$is_trusted" = "1" ] && return
# Check score threshold
if [ "$score" -ge "$threshold" ]; then
log "Auto-isolating high-risk device: $mac (score: $score)"
isolate_device "$mac"
fi
}
# ============================================================================
# Device Management
# ============================================================================
list_devices() {
local json_mode="$1"
init_db
if [ "$json_mode" = "--json" ]; then
# JSON output
echo '{"devices":['
local first=1
sqlite3 -json "$DB_FILE" "SELECT mac, ip, hostname, vendor, device_class, risk_level, risk_score, zone, isolated, trusted, blocked, last_seen FROM devices ORDER BY risk_score DESC;" 2>/dev/null || echo '[]'
echo ']}'
else
# Human-readable output
echo ""
echo -e "${BOLD}IoT Guard - Device List${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
printf "%-18s %-16s %-12s %-12s %-8s %-6s %s\n" "MAC" "IP" "Class" "Risk" "Score" "Zone" "Vendor"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
sqlite3 -separator '|' "$DB_FILE" "SELECT mac, ip, device_class, risk_level, risk_score, zone, vendor FROM devices ORDER BY risk_score DESC;" 2>/dev/null | while IFS='|' read -r mac ip class risk score zone vendor; do
# Color by risk
local risk_color="$NC"
case "$risk" in
high) risk_color="$RED" ;;
medium) risk_color="$YELLOW" ;;
low) risk_color="$GREEN" ;;
esac
# Truncate vendor
[ ${#vendor} -gt 20 ] && vendor="${vendor:0:17}..."
printf "%-18s %-16s %-12s ${risk_color}%-12s${NC} %-8s %-6s %s\n" "$mac" "$ip" "$class" "$risk" "$score" "$zone" "$vendor"
done
echo ""
fi
}
show_device() {
local mac="$1"
[ -z "$mac" ] && { error "Usage: iot-guardctl show <mac>"; return 1; }
mac=$(echo "$mac" | tr '[:lower:]' '[:upper:]')
init_db
local device=$(sqlite3 -line "$DB_FILE" "SELECT * FROM devices WHERE mac='$mac';")
if [ -z "$device" ]; then
error "Device not found: $mac"
return 1
fi
echo ""
echo -e "${BOLD}IoT Guard - Device Detail${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "$device"
# Show cloud dependencies
echo ""
echo -e "${BOLD}Cloud Dependencies:${NC}"
sqlite3 -column "$DB_FILE" "SELECT domain, query_count, last_seen FROM cloud_deps WHERE mac='$mac' ORDER BY query_count DESC LIMIT 10;"
# Show recent anomalies
echo ""
echo -e "${BOLD}Recent Anomalies:${NC}"
sqlite3 -column "$DB_FILE" "SELECT timestamp, anomaly_type, severity, description FROM anomalies WHERE mac='$mac' ORDER BY timestamp DESC LIMIT 5;"
echo ""
}
isolate_device() {
local mac="$1"
[ -z "$mac" ] && { error "Usage: iot-guardctl isolate <mac>"; return 1; }
mac=$(echo "$mac" | tr '[:lower:]' '[:upper:]')
init_db
log "Isolating device: $mac"
# Update database
local now=$(date -Iseconds)
sqlite3 "$DB_FILE" "UPDATE devices SET isolated=1, zone='iot', last_seen='$now' WHERE mac='$mac';"
# Call Client Guardian to set zone
if [ -x /usr/sbin/client-guardian ]; then
/usr/sbin/client-guardian set-zone "$mac" iot 2>/dev/null
fi
# Notify other modules
if [ -x /usr/sbin/bandwidth-manager ]; then
/usr/sbin/bandwidth-manager set-profile "$mac" iot_limited 2>/dev/null
fi
log "Device isolated: $mac -> IoT zone"
}
trust_device() {
local mac="$1"
[ -z "$mac" ] && { error "Usage: iot-guardctl trust <mac>"; return 1; }
mac=$(echo "$mac" | tr '[:lower:]' '[:upper:]')
init_db
log "Trusting device: $mac"
local now=$(date -Iseconds)
sqlite3 "$DB_FILE" "UPDATE devices SET trusted=1, isolated=0, zone='lan', last_seen='$now' WHERE mac='$mac';"
# Add to UCI allowlist
uci add_list iot-guard.trusted.mac="$mac" 2>/dev/null
uci commit iot-guard
# Call MAC Guardian to trust
if [ -x /usr/sbin/mac-guardian ]; then
/usr/sbin/mac-guardian trust "$mac" 2>/dev/null
fi
log "Device trusted: $mac"
}
block_device() {
local mac="$1"
[ -z "$mac" ] && { error "Usage: iot-guardctl block <mac>"; return 1; }
mac=$(echo "$mac" | tr '[:lower:]' '[:upper:]')
init_db
log "Blocking device: $mac"
local now=$(date -Iseconds)
sqlite3 "$DB_FILE" "UPDATE devices SET blocked=1, status='blocked', last_seen='$now' WHERE mac='$mac';"
# Add to UCI blocklist
uci add_list iot-guard.banned.mac="$mac" 2>/dev/null
uci commit iot-guard
# Call MAC Guardian to block
if [ -x /usr/sbin/mac-guardian ]; then
/usr/sbin/mac-guardian block "$mac" 2>/dev/null
fi
log "Device blocked: $mac"
}
# ============================================================================
# Anomaly Detection
# ============================================================================
show_anomalies() {
init_db
echo ""
echo -e "${BOLD}IoT Guard - Anomaly Events${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
sqlite3 -column -header "$DB_FILE" \
"SELECT a.timestamp, a.mac, d.hostname, a.anomaly_type, a.severity, a.description
FROM anomalies a
LEFT JOIN devices d ON a.mac = d.mac
WHERE a.resolved = 0
ORDER BY a.timestamp DESC
LIMIT 20;"
echo ""
local total=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM anomalies WHERE resolved=0;")
echo -e "Total unresolved anomalies: ${YELLOW}$total${NC}"
echo ""
}
record_anomaly() {
local mac="$1"
local atype="$2"
local severity="$3"
local desc="$4"
init_db
local now=$(date -Iseconds)
sqlite3 "$DB_FILE" "INSERT INTO anomalies (mac, timestamp, anomaly_type, severity, description)
VALUES ('$mac', '$now', '$atype', '$severity', '$desc');"
# Update device risk score
local new_score=$(calculate_risk_score "$mac" "" "")
sqlite3 "$DB_FILE" "UPDATE devices SET risk_score=$new_score WHERE mac='$mac';"
log "Anomaly recorded: $mac - $atype ($severity)"
}
# ============================================================================
# Cloud Dependency Mapping
# ============================================================================
show_cloud_map() {
local mac="$1"
[ -z "$mac" ] && { error "Usage: iot-guardctl cloud-map <mac>"; return 1; }
mac=$(echo "$mac" | tr '[:lower:]' '[:upper:]')
init_db
echo ""
echo -e "${BOLD}IoT Guard - Cloud Dependencies for $mac${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
sqlite3 -column -header "$DB_FILE" \
"SELECT domain, query_count, first_seen, last_seen
FROM cloud_deps
WHERE mac='$mac'
ORDER BY query_count DESC;"
echo ""
local total=$(sqlite3 "$DB_FILE" "SELECT COUNT(DISTINCT domain) FROM cloud_deps WHERE mac='$mac';")
echo -e "Total cloud services: ${CYAN}$total${NC}"
echo ""
}
# ============================================================================
# Status & Dashboard
# ============================================================================
show_status() {
init_dirs
init_db
echo ""
echo -e "${BOLD}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ IoT Guard v$VERSION${NC}"
echo -e "${BOLD}╠══════════════════════════════════════════════════╣${NC}"
# Get counts
local total=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices;" 2>/dev/null || echo 0)
local isolated=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE isolated=1;" 2>/dev/null || echo 0)
local trusted=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE trusted=1;" 2>/dev/null || echo 0)
local blocked=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE blocked=1;" 2>/dev/null || echo 0)
local high_risk=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE risk_level='high';" 2>/dev/null || echo 0)
local anomalies=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM anomalies WHERE resolved=0;" 2>/dev/null || echo 0)
# Calculate security score (inverse of risk)
local avg_risk=$(sqlite3 "$DB_FILE" "SELECT COALESCE(AVG(risk_score), 0) FROM devices;" 2>/dev/null || echo 0)
local security_score=$((100 - ${avg_risk%.*}))
[ "$security_score" -lt 0 ] && security_score=0
echo -e "${BOLD}${NC} IoT Devices: ${CYAN}$total${NC}"
echo -e "${BOLD}${NC} Isolated: ${YELLOW}$isolated${NC}"
echo -e "${BOLD}${NC} Trusted: ${GREEN}$trusted${NC}"
echo -e "${BOLD}${NC} Blocked: ${RED}$blocked${NC}"
echo -e "${BOLD}${NC} High Risk: ${RED}$high_risk${NC}"
echo -e "${BOLD}${NC} Active Anomalies:${YELLOW}$anomalies${NC}"
echo -e "${BOLD}${NC}"
echo -e "${BOLD}${NC} Security Score: ${GREEN}$security_score%${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════════╝${NC}"
echo ""
# Show by class
echo -e "${BOLD}Devices by Class:${NC}"
sqlite3 "$DB_FILE" "SELECT device_class || ': ' || COUNT(*) FROM devices GROUP BY device_class ORDER BY COUNT(*) DESC;" 2>/dev/null
echo ""
}
show_status_json() {
init_db
local total=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices;" 2>/dev/null || echo 0)
local isolated=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE isolated=1;" 2>/dev/null || echo 0)
local trusted=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE trusted=1;" 2>/dev/null || echo 0)
local blocked=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE blocked=1;" 2>/dev/null || echo 0)
local high_risk=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM devices WHERE risk_level='high';" 2>/dev/null || echo 0)
local anomalies=$(sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM anomalies WHERE resolved=0;" 2>/dev/null || echo 0)
local avg_risk=$(sqlite3 "$DB_FILE" "SELECT COALESCE(AVG(risk_score), 0) FROM devices;" 2>/dev/null || echo 0)
local security_score=$((100 - ${avg_risk%.*}))
[ "$security_score" -lt 0 ] && security_score=0
cat <<EOF
{
"total_devices": $total,
"isolated": $isolated,
"trusted": $trusted,
"blocked": $blocked,
"high_risk": $high_risk,
"anomalies": $anomalies,
"security_score": $security_score,
"version": "$VERSION"
}
EOF
}
# ============================================================================
# Daemon Mode
# ============================================================================
daemon_loop() {
log "Starting IoT Guard daemon..."
init_dirs
init_db
local scan_interval
config_load iot-guard
config_get scan_interval main scan_interval 300
while true; do
scan_network
# Run anomaly detection if enabled
local anomaly_detection
config_get_bool anomaly_detection main anomaly_detection 0
if [ "$anomaly_detection" -eq 1 ]; then
detect_anomalies
fi
sleep "$scan_interval"
done
}
detect_anomalies() {
# Placeholder for anomaly detection logic
# Would analyze traffic patterns, DNS queries, etc.
:
}
# ============================================================================
# Usage
# ============================================================================
usage() {
cat <<'EOF'
IoT Guard - Device Isolation & Security
Usage: iot-guardctl <command> [options]
Status & Info:
status Overview dashboard
status --json JSON output
list [--json] List all IoT devices
show <mac> Device detail with cloud map
Actions:
scan Scan network for IoT devices
isolate <mac> Isolate device to IoT zone
trust <mac> Add device to allowlist
block <mac> Block device completely
Monitoring:
anomalies Show anomaly events
cloud-map <mac> Show cloud dependencies
Service:
daemon Run in daemon mode
Examples:
iot-guardctl scan
iot-guardctl list
iot-guardctl isolate AA:BB:CC:DD:EE:FF
iot-guardctl cloud-map AA:BB:CC:DD:EE:FF
EOF
}
# ============================================================================
# Main
# ============================================================================
case "${1:-}" in
status)
shift
case "${1:-}" in
--json) show_status_json ;;
*) show_status ;;
esac
;;
list)
shift
list_devices "$1"
;;
show)
shift
show_device "$1"
;;
scan)
scan_network
;;
isolate)
shift
isolate_device "$1"
;;
trust)
shift
trust_device "$1"
;;
block)
shift
block_device "$1"
;;
anomalies)
show_anomalies
;;
cloud-map)
shift
show_cloud_map "$1"
;;
daemon)
daemon_loop
;;
help|--help|-h)
usage
;;
"")
show_status
;;
*)
error "Unknown command: $1"
usage >&2
exit 1
;;
esac