CDN Cache: - Migrate from nginx to Squid proxy for better caching - Add aggressive caching rules for Windows Update, Linux repos, Steam, Apple - Proper firewall integration via UCI (transparent proxy) - Real-time stats from Squid access logs Network Modes: - Complete UI rework with MirrorBox dark theme - 9 network modes with emojis and descriptions - Dynamic CSS animations and modern styling Fixes: - Fix jshn boolean handling in secubox-recovery (1/0 vs true/false) - Fix nDPId RPCD to use netifyd as fallback DPI provider - Update media-flow and security-threats dashboards Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
768 lines
18 KiB
Bash
Executable File
768 lines
18 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: MIT
|
|
# SecuBox nDPId - RPCD Backend
|
|
# Complete interface for nDPId DPI daemon
|
|
# Copyright (C) 2025 CyberMind.fr
|
|
|
|
. /lib/functions.sh
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
# Paths
|
|
CONFIG_FILE="/etc/config/ndpid"
|
|
STATUS_FILE="/var/run/netifyd/status.json"
|
|
DISTRIBUTOR_SOCK="/var/run/ndpid/distributor.sock"
|
|
COLLECTOR_SOCK="/var/run/ndpid/collector.sock"
|
|
FLOWS_CACHE="/tmp/ndpid-flows.json"
|
|
APPS_CACHE="/tmp/ndpid-apps.json"
|
|
STATS_CACHE="/tmp/ndpid-stats.json"
|
|
LOG_FILE="/var/log/ndpid.log"
|
|
|
|
# Logging
|
|
log_msg() {
|
|
local level="$1"
|
|
shift
|
|
logger -t luci.ndpid "[$level] $*"
|
|
}
|
|
|
|
# Check if nDPId is running
|
|
check_ndpid_running() {
|
|
pidof ndpid >/dev/null 2>&1
|
|
}
|
|
|
|
# Check if nDPIsrvd is running
|
|
check_ndpisrvd_running() {
|
|
pidof ndpisrvd >/dev/null 2>&1
|
|
}
|
|
|
|
# Check if netifyd is running
|
|
check_netifyd_running() {
|
|
pidof netifyd >/dev/null 2>&1
|
|
}
|
|
|
|
# Get service status
|
|
get_service_status() {
|
|
json_init
|
|
|
|
local running=0
|
|
local distributor_running=0
|
|
local pid=""
|
|
local uptime=0
|
|
local version=""
|
|
local netifyd_running=0
|
|
local netifyd_pid=""
|
|
local netifyd_uptime=0
|
|
local netifyd_version=""
|
|
local flow_count=0
|
|
|
|
# Check nDPId
|
|
if check_ndpid_running; then
|
|
running=1
|
|
pid=$(pidof ndpid | awk '{print $1}')
|
|
|
|
# Get uptime from /proc
|
|
if [ -n "$pid" ] && [ -d "/proc/$pid" ]; then
|
|
local start_time=$(stat -c %Y /proc/$pid 2>/dev/null)
|
|
local now=$(date +%s)
|
|
[ -n "$start_time" ] && uptime=$((now - start_time))
|
|
fi
|
|
|
|
# Get version
|
|
version=$(ndpid -v 2>&1 | head -1 | grep -oE '[0-9]+\.[0-9]+' || echo "1.7")
|
|
fi
|
|
|
|
check_ndpisrvd_running && distributor_running=1
|
|
|
|
# Check netifyd (fallback DPI)
|
|
if check_netifyd_running; then
|
|
netifyd_running=1
|
|
netifyd_pid=$(pidof netifyd | awk '{print $1}')
|
|
|
|
# Get uptime from status file
|
|
if [ -f "$STATUS_FILE" ]; then
|
|
netifyd_uptime=$(cat "$STATUS_FILE" 2>/dev/null | jsonfilter -e '@.uptime' 2>/dev/null || echo 0)
|
|
flow_count=$(cat "$STATUS_FILE" 2>/dev/null | jsonfilter -e '@.flow_count' 2>/dev/null || echo 0)
|
|
fi
|
|
|
|
# Get version
|
|
netifyd_version=$(netifyd -v 2>&1 | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "4.4.7")
|
|
fi
|
|
|
|
json_add_boolean "running" "$running"
|
|
json_add_boolean "distributor_running" "$distributor_running"
|
|
json_add_string "pid" "$pid"
|
|
json_add_int "uptime" "$uptime"
|
|
json_add_string "version" "$version"
|
|
json_add_string "collector_socket" "$COLLECTOR_SOCK"
|
|
json_add_string "distributor_socket" "$DISTRIBUTOR_SOCK"
|
|
|
|
# Netifyd status
|
|
json_add_boolean "netifyd_running" "$netifyd_running"
|
|
json_add_string "netifyd_pid" "$netifyd_pid"
|
|
json_add_int "netifyd_uptime" "$netifyd_uptime"
|
|
json_add_string "netifyd_version" "$netifyd_version"
|
|
json_add_int "flow_count" "$flow_count"
|
|
|
|
# Check if compat layer is running
|
|
local compat_running=0
|
|
pidof ndpid-compat >/dev/null 2>&1 && compat_running=1
|
|
json_add_boolean "compat_running" "$compat_running"
|
|
|
|
# DPI available if either ndpid or netifyd is running
|
|
local dpi_available=0
|
|
[ "$running" = "1" ] || [ "$netifyd_running" = "1" ] && dpi_available=1
|
|
json_add_boolean "dpi_available" "$dpi_available"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get real-time flow statistics from status file
|
|
get_realtime_flows() {
|
|
json_init
|
|
|
|
if [ -f "$STATUS_FILE" ]; then
|
|
local status_json=$(cat "$STATUS_FILE" 2>/dev/null)
|
|
if [ -n "$status_json" ]; then
|
|
# Parse values
|
|
local flow_count=$(echo "$status_json" | jsonfilter -e '@.flow_count' 2>/dev/null || echo 0)
|
|
local flows_active=$(echo "$status_json" | jsonfilter -e '@.flows_active' 2>/dev/null || echo 0)
|
|
local uptime=$(echo "$status_json" | jsonfilter -e '@.uptime' 2>/dev/null || echo 0)
|
|
|
|
json_add_int "flow_count" "$flow_count"
|
|
json_add_int "flows_active" "$flows_active"
|
|
json_add_int "uptime" "$uptime"
|
|
json_add_boolean "available" 1
|
|
else
|
|
json_add_boolean "available" 0
|
|
fi
|
|
else
|
|
json_add_boolean "available" 0
|
|
json_add_int "flow_count" 0
|
|
json_add_int "flows_active" 0
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get interface statistics
|
|
get_interface_stats() {
|
|
json_init
|
|
json_add_array "interfaces"
|
|
|
|
if [ -f "$STATUS_FILE" ]; then
|
|
local stats=$(cat "$STATUS_FILE" | jsonfilter -e '@.stats' 2>/dev/null)
|
|
if [ -n "$stats" ] && command -v jq >/dev/null 2>&1; then
|
|
# Parse each interface
|
|
for iface in $(echo "$stats" | jq -r 'keys[]' 2>/dev/null); do
|
|
json_add_object
|
|
json_add_string "name" "$iface"
|
|
|
|
local ip_bytes=$(echo "$stats" | jq -r ".\"$iface\".ip_bytes // 0")
|
|
local wire_bytes=$(echo "$stats" | jq -r ".\"$iface\".wire_bytes // 0")
|
|
local tcp=$(echo "$stats" | jq -r ".\"$iface\".tcp // 0")
|
|
local udp=$(echo "$stats" | jq -r ".\"$iface\".udp // 0")
|
|
local icmp=$(echo "$stats" | jq -r ".\"$iface\".icmp // 0")
|
|
|
|
json_add_int "ip_bytes" "$ip_bytes"
|
|
json_add_int "wire_bytes" "$wire_bytes"
|
|
json_add_int "tcp" "$tcp"
|
|
json_add_int "udp" "$udp"
|
|
json_add_int "icmp" "$icmp"
|
|
|
|
json_close_object
|
|
done
|
|
fi
|
|
fi
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get top applications (from aggregated apps file)
|
|
get_top_applications() {
|
|
json_init
|
|
json_add_array "applications"
|
|
|
|
local app_data=""
|
|
|
|
# Try apps cache first (pre-aggregated by ndpid-compat)
|
|
if [ -f "$APPS_CACHE" ] && command -v jq >/dev/null 2>&1; then
|
|
app_data=$(jq -r '.[0:15][] | "\(.name // "Unknown")|\(.category // "Unknown")|\(.flows // 0)|\(.bytes // 0)"' \
|
|
"$APPS_CACHE" 2>/dev/null)
|
|
# Fallback to flows cache
|
|
elif [ -f "$FLOWS_CACHE" ] && command -v jq >/dev/null 2>&1; then
|
|
app_data=$(jq -r '
|
|
group_by(.app) |
|
|
map({
|
|
name: (.[0].app // "Unknown"),
|
|
category: (.[0].category // "Unknown"),
|
|
flows: length,
|
|
bytes: ([.[].bytes_rx, .[].bytes_tx] | add // 0)
|
|
}) |
|
|
sort_by(-.bytes) |
|
|
.[0:15][] |
|
|
"\(.name)|\(.category)|\(.flows)|\(.bytes)"
|
|
' "$FLOWS_CACHE" 2>/dev/null)
|
|
fi
|
|
|
|
if [ -n "$app_data" ]; then
|
|
while IFS='|' read -r name category flows bytes; do
|
|
[ -z "$name" ] && continue
|
|
json_add_object
|
|
json_add_string "name" "${name:-Unknown}"
|
|
json_add_string "category" "${category:-Unknown}"
|
|
json_add_int "flows" "${flows:-0}"
|
|
json_add_int "bytes" "${bytes:-0}"
|
|
json_close_object
|
|
done <<EOF
|
|
$app_data
|
|
EOF
|
|
fi
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get detailed flows with detection info
|
|
get_detailed_flows() {
|
|
json_init
|
|
json_add_array "flows"
|
|
|
|
if [ -f "$FLOWS_CACHE" ] && command -v jq >/dev/null 2>&1; then
|
|
# Get recent active flows sorted by bytes - use heredoc to avoid subshell
|
|
local flow_data
|
|
flow_data=$(jq -r '
|
|
sort_by(-(.bytes_rx + .bytes_tx)) |
|
|
.[0:100][] |
|
|
"\(.id // 0)|\(.src_ip // "")|\(.src_port // 0)|\(.dst_ip // "")|\(.dst_port // 0)|\(.proto // "")|\(.app // "Unknown")|\(.category // "Unknown")|\(.hostname // "")|\(.confidence // "")|\(.bytes_rx // 0)|\(.bytes_tx // 0)|\(.packets // 0)|\(.state // "unknown")|\(.iface // "")"
|
|
' "$FLOWS_CACHE" 2>/dev/null)
|
|
|
|
while IFS='|' read -r id src_ip src_port dst_ip dst_port proto app category hostname confidence bytes_rx bytes_tx packets state iface; do
|
|
[ -z "$id" ] && continue
|
|
json_add_object
|
|
json_add_int "id" "${id:-0}"
|
|
json_add_string "src_ip" "${src_ip}"
|
|
json_add_int "src_port" "${src_port:-0}"
|
|
json_add_string "dst_ip" "${dst_ip}"
|
|
json_add_int "dst_port" "${dst_port:-0}"
|
|
json_add_string "proto" "${proto}"
|
|
json_add_string "app" "${app:-Unknown}"
|
|
json_add_string "category" "${category:-Unknown}"
|
|
json_add_string "hostname" "${hostname}"
|
|
json_add_string "confidence" "${confidence}"
|
|
json_add_int "bytes_rx" "${bytes_rx:-0}"
|
|
json_add_int "bytes_tx" "${bytes_tx:-0}"
|
|
json_add_int "packets" "${packets:-0}"
|
|
json_add_string "state" "${state:-unknown}"
|
|
json_add_string "iface" "${iface}"
|
|
json_close_object
|
|
done <<EOF
|
|
$flow_data
|
|
EOF
|
|
fi
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get category breakdown
|
|
get_categories() {
|
|
json_init
|
|
json_add_array "categories"
|
|
|
|
if [ -f "$APPS_CACHE" ] && command -v jq >/dev/null 2>&1; then
|
|
local cat_data
|
|
cat_data=$(jq -r '
|
|
group_by(.category) |
|
|
map({
|
|
name: (.[0].category // "Unknown"),
|
|
apps: length,
|
|
flows: ([.[].flows] | add),
|
|
bytes: ([.[].bytes] | add)
|
|
}) |
|
|
sort_by(-.bytes) |
|
|
.[] |
|
|
"\(.name)|\(.apps)|\(.flows)|\(.bytes)"
|
|
' "$APPS_CACHE" 2>/dev/null)
|
|
|
|
while IFS='|' read -r name apps flows bytes; do
|
|
[ -z "$name" ] && continue
|
|
json_add_object
|
|
json_add_string "name" "${name:-Unknown}"
|
|
json_add_int "apps" "${apps:-0}"
|
|
json_add_int "flows" "${flows:-0}"
|
|
json_add_int "bytes" "${bytes:-0}"
|
|
json_close_object
|
|
done <<EOF
|
|
$cat_data
|
|
EOF
|
|
fi
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get top protocols
|
|
get_top_protocols() {
|
|
json_init
|
|
json_add_array "protocols"
|
|
|
|
if [ -f "$STATUS_FILE" ]; then
|
|
local stats=$(cat "$STATUS_FILE" | jsonfilter -e '@.stats' 2>/dev/null)
|
|
if [ -n "$stats" ] && command -v jq >/dev/null 2>&1; then
|
|
# Aggregate protocol counts across interfaces
|
|
local tcp=$(echo "$stats" | jq '[.[].tcp] | add // 0')
|
|
local udp=$(echo "$stats" | jq '[.[].udp] | add // 0')
|
|
local icmp=$(echo "$stats" | jq '[.[].icmp] | add // 0')
|
|
|
|
json_add_object
|
|
json_add_string "name" "TCP"
|
|
json_add_int "count" "$tcp"
|
|
json_close_object
|
|
|
|
json_add_object
|
|
json_add_string "name" "UDP"
|
|
json_add_int "count" "$udp"
|
|
json_close_object
|
|
|
|
json_add_object
|
|
json_add_string "name" "ICMP"
|
|
json_add_int "count" "$icmp"
|
|
json_close_object
|
|
fi
|
|
fi
|
|
|
|
json_close_array
|
|
json_dump
|
|
}
|
|
|
|
# Get configuration
|
|
get_config() {
|
|
json_init
|
|
|
|
config_load ndpid
|
|
|
|
# Main settings
|
|
local enabled interfaces collector_socket max_flows
|
|
config_get_bool enabled main enabled 0
|
|
config_get interfaces main interface ""
|
|
config_get collector_socket main collector_socket "/var/run/ndpid/collector.sock"
|
|
config_get max_flows main max_flows 100000
|
|
|
|
json_add_boolean "enabled" "$enabled"
|
|
json_add_string "interfaces" "$interfaces"
|
|
json_add_string "collector_socket" "$collector_socket"
|
|
json_add_int "max_flows" "$max_flows"
|
|
|
|
# Distributor settings
|
|
local dist_enabled tcp_port tcp_address
|
|
config_get_bool dist_enabled distributor enabled 1
|
|
config_get tcp_port distributor tcp_port 7000
|
|
config_get tcp_address distributor tcp_address "127.0.0.1"
|
|
|
|
json_add_object "distributor"
|
|
json_add_boolean "enabled" "$dist_enabled"
|
|
json_add_int "tcp_port" "$tcp_port"
|
|
json_add_string "tcp_address" "$tcp_address"
|
|
json_close_object
|
|
|
|
# Compat settings
|
|
local compat_enabled
|
|
config_get_bool compat_enabled compat enabled 1
|
|
json_add_object "compat"
|
|
json_add_boolean "enabled" "$compat_enabled"
|
|
json_close_object
|
|
|
|
# Actions settings
|
|
local actions_enabled
|
|
config_get_bool actions_enabled actions enabled 0
|
|
json_add_object "actions"
|
|
json_add_boolean "enabled" "$actions_enabled"
|
|
json_close_object
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get dashboard summary
|
|
get_dashboard() {
|
|
json_init
|
|
|
|
# Service status
|
|
json_add_object "service"
|
|
local running=0
|
|
check_ndpid_running && running=1
|
|
json_add_boolean "running" "$running"
|
|
|
|
local distributor_running=0
|
|
check_ndpisrvd_running && distributor_running=1
|
|
json_add_boolean "distributor_running" "$distributor_running"
|
|
|
|
local compat_running=0
|
|
pidof ndpid-compat >/dev/null 2>&1 && compat_running=1
|
|
json_add_boolean "compat_running" "$compat_running"
|
|
|
|
json_add_string "version" "$(ndpid -v 2>&1 | head -1 | grep -oE '[0-9]+\.[0-9]+' || echo '1.7')"
|
|
json_close_object
|
|
|
|
# Flow stats
|
|
json_add_object "flows"
|
|
if [ -f "$STATUS_FILE" ]; then
|
|
local flow_count=$(cat "$STATUS_FILE" | jsonfilter -e '@.flow_count' 2>/dev/null || echo 0)
|
|
local flows_active=$(cat "$STATUS_FILE" | jsonfilter -e '@.flows_active' 2>/dev/null || echo 0)
|
|
json_add_int "total" "$flow_count"
|
|
json_add_int "active" "$flows_active"
|
|
else
|
|
json_add_int "total" 0
|
|
json_add_int "active" 0
|
|
fi
|
|
json_close_object
|
|
|
|
# System stats
|
|
json_add_object "system"
|
|
local pid=$(pidof ndpid | awk '{print $1}')
|
|
if [ -n "$pid" ] && [ -d "/proc/$pid" ]; then
|
|
# Memory usage
|
|
local mem_kb=$(awk '/VmRSS/{print $2}' /proc/$pid/status 2>/dev/null || echo 0)
|
|
json_add_int "memory_kb" "$mem_kb"
|
|
|
|
# CPU (simplified)
|
|
json_add_string "cpu" "0%"
|
|
else
|
|
json_add_int "memory_kb" 0
|
|
json_add_string "cpu" "0%"
|
|
fi
|
|
json_close_object
|
|
|
|
# Interfaces
|
|
json_add_array "interfaces"
|
|
config_load ndpid
|
|
config_get interfaces main interface ""
|
|
for iface in $interfaces; do
|
|
json_add_string "" "$iface"
|
|
done
|
|
json_close_array
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Service control: start
|
|
service_start() {
|
|
json_init
|
|
|
|
/etc/init.d/ndpisrvd start 2>&1
|
|
sleep 1
|
|
/etc/init.d/ndpid start 2>&1
|
|
|
|
# Start compat layer
|
|
local compat_enabled
|
|
config_load ndpid
|
|
config_get_bool compat_enabled compat enabled 1
|
|
if [ "$compat_enabled" -eq 1 ]; then
|
|
/usr/bin/ndpid-compat -d 2>&1
|
|
fi
|
|
|
|
sleep 2
|
|
|
|
if check_ndpid_running; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "nDPId started successfully"
|
|
log_msg "INFO" "Service started"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Failed to start nDPId"
|
|
log_msg "ERROR" "Service failed to start"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Service control: stop
|
|
service_stop() {
|
|
json_init
|
|
|
|
# Stop compat layer
|
|
if [ -f /var/run/ndpid-compat.pid ]; then
|
|
kill $(cat /var/run/ndpid-compat.pid) 2>/dev/null
|
|
rm -f /var/run/ndpid-compat.pid
|
|
fi
|
|
|
|
/etc/init.d/ndpid stop 2>&1
|
|
/etc/init.d/ndpisrvd stop 2>&1
|
|
|
|
sleep 1
|
|
|
|
if ! check_ndpid_running; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "nDPId stopped successfully"
|
|
log_msg "INFO" "Service stopped"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Failed to stop nDPId"
|
|
log_msg "ERROR" "Service failed to stop"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Service control: restart
|
|
service_restart() {
|
|
json_init
|
|
|
|
service_stop >/dev/null 2>&1
|
|
sleep 2
|
|
service_start >/dev/null 2>&1
|
|
|
|
if check_ndpid_running; then
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "nDPId restarted successfully"
|
|
else
|
|
json_add_boolean "success" 0
|
|
json_add_string "message" "Failed to restart nDPId"
|
|
fi
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Service control: enable
|
|
service_enable() {
|
|
json_init
|
|
|
|
uci set ndpid.main.enabled=1
|
|
uci commit ndpid
|
|
|
|
/etc/init.d/ndpid enable
|
|
/etc/init.d/ndpisrvd enable
|
|
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "nDPId enabled"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Service control: disable
|
|
service_disable() {
|
|
json_init
|
|
|
|
uci set ndpid.main.enabled=0
|
|
uci commit ndpid
|
|
|
|
/etc/init.d/ndpid disable
|
|
/etc/init.d/ndpisrvd disable
|
|
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "nDPId disabled"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Update configuration
|
|
update_config() {
|
|
local data="$1"
|
|
json_init
|
|
|
|
if [ -z "$data" ]; then
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "No configuration data provided"
|
|
json_dump
|
|
return
|
|
fi
|
|
|
|
# Parse and apply configuration
|
|
local enabled=$(echo "$data" | jsonfilter -e '@.enabled' 2>/dev/null)
|
|
local interfaces=$(echo "$data" | jsonfilter -e '@.interfaces' 2>/dev/null)
|
|
local max_flows=$(echo "$data" | jsonfilter -e '@.max_flows' 2>/dev/null)
|
|
|
|
[ -n "$enabled" ] && uci set ndpid.main.enabled="$enabled"
|
|
[ -n "$max_flows" ] && uci set ndpid.main.max_flows="$max_flows"
|
|
|
|
# Handle interfaces (clear and re-add)
|
|
if [ -n "$interfaces" ]; then
|
|
uci -q delete ndpid.main.interface
|
|
for iface in $interfaces; do
|
|
uci add_list ndpid.main.interface="$iface"
|
|
done
|
|
fi
|
|
|
|
uci commit ndpid
|
|
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Configuration updated"
|
|
log_msg "INFO" "Configuration updated"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Clear statistics cache
|
|
clear_cache() {
|
|
json_init
|
|
|
|
rm -f "$FLOWS_CACHE" "$STATS_CACHE"
|
|
rm -rf /tmp/ndpid-state
|
|
|
|
json_add_boolean "success" 1
|
|
json_add_string "message" "Cache cleared"
|
|
|
|
json_dump
|
|
}
|
|
|
|
# Get monitored interfaces list
|
|
get_interfaces() {
|
|
json_init
|
|
json_add_array "interfaces"
|
|
|
|
# Get configured interfaces
|
|
config_load ndpid
|
|
config_get interfaces main interface ""
|
|
|
|
for iface in $interfaces; do
|
|
json_add_object
|
|
json_add_string "name" "$iface"
|
|
|
|
# Check if interface exists
|
|
if [ -d "/sys/class/net/$iface" ]; then
|
|
json_add_boolean "exists" 1
|
|
|
|
# Get interface state
|
|
local state=$(cat /sys/class/net/$iface/operstate 2>/dev/null || echo "unknown")
|
|
json_add_string "state" "$state"
|
|
|
|
# Get MAC address
|
|
local mac=$(cat /sys/class/net/$iface/address 2>/dev/null || echo "")
|
|
json_add_string "mac" "$mac"
|
|
else
|
|
json_add_boolean "exists" 0
|
|
fi
|
|
|
|
json_close_object
|
|
done
|
|
|
|
json_close_array
|
|
|
|
# Scan available interfaces from network config and system
|
|
json_add_array "available"
|
|
|
|
# Get bridges and network interfaces from UCI
|
|
local net_ifaces=""
|
|
config_load network
|
|
|
|
# Get all defined interfaces (br-lan, br-wan, etc)
|
|
for iface in $(ls /sys/class/net/ 2>/dev/null); do
|
|
case "$iface" in
|
|
lo|sit*|ip6*|gre*|ifb*|teql*)
|
|
# Skip loopback and virtual tunnel interfaces
|
|
;;
|
|
br-*|eth*|wlan*|lan*|wan*)
|
|
# Include bridges, ethernet, wifi, and named interfaces
|
|
local state=$(cat /sys/class/net/$iface/operstate 2>/dev/null || echo "unknown")
|
|
local type=$(cat /sys/class/net/$iface/type 2>/dev/null || echo "0")
|
|
# Only include if it's a real interface (type 1 = ethernet)
|
|
if [ "$type" = "1" ] || [ -d "/sys/class/net/$iface/bridge" ]; then
|
|
json_add_object
|
|
json_add_string "name" "$iface"
|
|
json_add_string "state" "$state"
|
|
# Check if it's a bridge
|
|
if [ -d "/sys/class/net/$iface/bridge" ]; then
|
|
json_add_string "type" "bridge"
|
|
else
|
|
json_add_string "type" "interface"
|
|
fi
|
|
json_close_object
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
|
|
json_close_array
|
|
|
|
json_dump
|
|
}
|
|
|
|
# RPC method dispatcher
|
|
case "$1" in
|
|
list)
|
|
cat << 'EOF'
|
|
{
|
|
"get_service_status": {},
|
|
"get_realtime_flows": {},
|
|
"get_detailed_flows": {},
|
|
"get_interface_stats": {},
|
|
"get_top_applications": {},
|
|
"get_top_protocols": {},
|
|
"get_categories": {},
|
|
"get_config": {},
|
|
"get_dashboard": {},
|
|
"get_interfaces": {},
|
|
"service_start": {},
|
|
"service_stop": {},
|
|
"service_restart": {},
|
|
"service_enable": {},
|
|
"service_disable": {},
|
|
"update_config": { "data": "object" },
|
|
"clear_cache": {}
|
|
}
|
|
EOF
|
|
;;
|
|
call)
|
|
case "$2" in
|
|
get_service_status)
|
|
get_service_status
|
|
;;
|
|
get_realtime_flows)
|
|
get_realtime_flows
|
|
;;
|
|
get_detailed_flows)
|
|
get_detailed_flows
|
|
;;
|
|
get_interface_stats)
|
|
get_interface_stats
|
|
;;
|
|
get_top_applications)
|
|
get_top_applications
|
|
;;
|
|
get_top_protocols)
|
|
get_top_protocols
|
|
;;
|
|
get_categories)
|
|
get_categories
|
|
;;
|
|
get_config)
|
|
get_config
|
|
;;
|
|
get_dashboard)
|
|
get_dashboard
|
|
;;
|
|
get_interfaces)
|
|
get_interfaces
|
|
;;
|
|
service_start)
|
|
service_start
|
|
;;
|
|
service_stop)
|
|
service_stop
|
|
;;
|
|
service_restart)
|
|
service_restart
|
|
;;
|
|
service_enable)
|
|
service_enable
|
|
;;
|
|
service_disable)
|
|
service_disable
|
|
;;
|
|
update_config)
|
|
read -r input
|
|
data=$(echo "$input" | jsonfilter -e '@.data' 2>/dev/null)
|
|
update_config "$data"
|
|
;;
|
|
clear_cache)
|
|
clear_cache
|
|
;;
|
|
*)
|
|
echo '{"error": "Unknown method"}'
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
echo '{"error": "Invalid action"}'
|
|
;;
|
|
esac
|