secubox-openwrt/package/secubox/luci-app-dpi-dual/root/usr/libexec/rpcd/luci.dpi-dual
CyberMind-FR 76754df467 fix(dpi): Detect mitmproxy-in specifically for WAF status
- Changed pgrep to detect mitmproxy-in container only
- mitmproxy-out removed from deployment (not needed for WAF)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-15 15:00:19 +01:00

466 lines
16 KiB
Bash

#!/bin/sh
# RPCD handler for DPI Dual-Stream dashboard
# Part of luci-app-dpi-dual
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
STATS_DIR="/tmp/secubox"
FLOW_DIR="/tmp/dpi-flows"
BUFFER_FILE="$STATS_DIR/dpi-buffer.json"
FLOWS_FILE="$STATS_DIR/dpi-flows.json"
THREATS_FILE="$STATS_DIR/correlated-threats.json"
ALERTS_FILE="$STATS_DIR/waf-alerts.json"
read_json_file() {
file="$1"
if [ -f "$file" ]; then
cat "$file"
else
echo '{}'
fi
}
case "$1" in
list)
cat << 'EOF'
{
"status": {},
"get_flows": {},
"get_buffer": {"limit": 100},
"get_threats": {"limit": 50},
"get_correlation": {"limit": 20},
"get_correlation_stats": {},
"get_ip_context": {"ip": "string"},
"get_ip_reputation": {"ip": "string"},
"get_timeline": {"limit": 50},
"get_mirror_status": {},
"search_correlations": {"ip": "string", "limit": 50},
"start": {},
"stop": {},
"restart": {},
"replay_request": {"req_hash": "string"},
"correlate_ip": {"ip": "string"},
"ban_ip": {"ip": "string", "duration": "string"},
"set_auto_ban": {"enabled": true},
"get_lan_status": {},
"get_lan_clients": {},
"get_lan_destinations": {"limit": 100},
"get_lan_protocols": {}
}
EOF
;;
call)
case "$2" in
status)
# Get unified status of both streams
config_load dpi-dual
enabled=""
mode=""
correlation=""
config_get enabled settings enabled "0"
config_get mode settings mode "dual"
config_get correlation settings correlation "0"
# Check processes (use partial match for truncated process names)
mitm_running=0
tap_running=0
collector_running=0
correlator_running=0
lan_collector_running=0
pgrep -f mitmproxy-in >/dev/null 2>&1 && mitm_running=1
pgrep netifyd >/dev/null 2>&1 && tap_running=1
pgrep -f dpi-flow-collect >/dev/null 2>&1 && collector_running=1
pgrep -f dpi-correlator >/dev/null 2>&1 && correlator_running=1
pgrep -f dpi-lan-collect >/dev/null 2>&1 && lan_collector_running=1
# Get TAP interface status
tap_if=""
tap_up=0
tap_rx=0
tap_tx=0
config_get tap_if tap interface "tap0"
if ip link show "$tap_if" >/dev/null 2>&1; then
tap_up=1
tap_rx=$(cat "/sys/class/net/$tap_if/statistics/rx_bytes" 2>/dev/null || echo 0)
tap_tx=$(cat "/sys/class/net/$tap_if/statistics/tx_bytes" 2>/dev/null || echo 0)
fi
# Get buffer stats
buffer_entries=0 buffer_threats=0 buffer_blocked=0
if [ -f "$BUFFER_FILE" ]; then
buffer_entries=$(jsonfilter -i "$BUFFER_FILE" -e '@.entries' 2>/dev/null || echo 0)
buffer_threats=$(jsonfilter -i "$BUFFER_FILE" -e '@.threats_detected' 2>/dev/null || echo 0)
buffer_blocked=$(jsonfilter -i "$BUFFER_FILE" -e '@.blocked_count' 2>/dev/null || echo 0)
fi
# Get flow stats
flows_1min=0
if [ -f "$FLOWS_FILE" ]; then
flows_1min=$(jsonfilter -i "$FLOWS_FILE" -e '@.flows_1min' 2>/dev/null || echo 0)
fi
# Get correlation stats
correlated_threats=0
if [ -f "$THREATS_FILE" ]; then
correlated_threats=$(wc -l < "$THREATS_FILE" 2>/dev/null || echo 0)
fi
# Get LAN passive analysis stats
lan_enabled=""
lan_if=""
config_get lan_enabled lan enabled "0"
config_get lan_if lan interface "br-lan"
lan_clients=0 lan_dests=0 lan_protos=0
lan_file="$STATS_DIR/lan-flows.json"
if [ -f "$lan_file" ]; then
lan_clients=$(jsonfilter -i "$lan_file" -e '@.active_clients' 2>/dev/null || echo 0)
lan_dests=$(jsonfilter -i "$lan_file" -e '@.unique_destinations' 2>/dev/null || echo 0)
lan_protos=$(jsonfilter -i "$lan_file" -e '@.detected_protocols' 2>/dev/null || echo 0)
fi
cat << EOF
{
"enabled": $enabled,
"mode": "$mode",
"correlation_enabled": $correlation,
"mitm_stream": {
"running": $mitm_running,
"buffer_entries": $buffer_entries,
"threats_detected": $buffer_threats,
"blocked_count": $buffer_blocked
},
"tap_stream": {
"running": $tap_running,
"interface": "$tap_if",
"interface_up": $tap_up,
"rx_bytes": $tap_rx,
"tx_bytes": $tap_tx,
"flows_1min": $flows_1min,
"collector_running": $collector_running
},
"correlation": {
"running": $correlator_running,
"threats_correlated": $correlated_threats
},
"lan_passive": {
"enabled": $lan_enabled,
"running": $lan_collector_running,
"interface": "$lan_if",
"active_clients": $lan_clients,
"unique_destinations": $lan_dests,
"detected_protocols": $lan_protos
}
}
EOF
;;
get_flows)
read_json_file "$FLOWS_FILE"
;;
get_buffer)
read "$3"
json_load "$REPLY"
json_get_var limit limit 100
if [ -f "$BUFFER_FILE" ]; then
cat "$BUFFER_FILE"
else
echo '{"entries": 0, "requests": []}'
fi
;;
get_threats)
read "$3"
json_load "$REPLY"
json_get_var limit limit 50
if [ -f "$ALERTS_FILE" ]; then
# Return last N alerts
total=$(jsonfilter -i "$ALERTS_FILE" -e '@[*]' 2>/dev/null | wc -l)
cat << EOF
{
"total": $total,
"alerts": $(tail -c 50000 "$ALERTS_FILE" 2>/dev/null || echo '[]')
}
EOF
else
echo '{"total": 0, "alerts": []}'
fi
;;
get_correlation)
read "$3"
json_load "$REPLY"
json_get_var limit limit 20
if [ -f "$THREATS_FILE" ]; then
total=$(wc -l < "$THREATS_FILE" 2>/dev/null || echo 0)
cat << EOF
{
"total": $total,
"correlated": $(tail -"$limit" "$THREATS_FILE" 2>/dev/null | tr '\n' ',' | sed 's/,$//' | awk '{print "["$0"]"}')
}
EOF
else
echo '{"total": 0, "correlated": []}'
fi
;;
get_mirror_status)
/usr/lib/dpi-dual/mirror-setup.sh status 2>&1 | \
awk 'BEGIN{print "{"}
/TAP Interface/ {tap=1}
/not found/ {up=0}
/UP/ {up=1}
/RX:/ {rx=$2}
/TX:/ {tx=$2}
/ingress/ {ing=1}
END{
printf "\"tap_found\": %s, \"tap_up\": %s, \"ingress_configured\": %s",
(tap?1:0), (up?1:0), (ing?1:0);
print "}"
}'
;;
start)
/usr/sbin/dpi-dualctl start >/dev/null 2>&1
echo '{"success": true}'
;;
stop)
/usr/sbin/dpi-dualctl stop >/dev/null 2>&1
echo '{"success": true}'
;;
restart)
/usr/sbin/dpi-dualctl restart >/dev/null 2>&1
echo '{"success": true}'
;;
replay_request)
read "$3"
json_load "$REPLY"
json_get_var req_hash req_hash ""
if [ -z "$req_hash" ]; then
echo '{"success": false, "error": "req_hash required"}'
else
# Add to replay queue (read by mitmproxy addon)
queue_file="/tmp/dpi-buffer/replay-queue.json"
mkdir -p /tmp/dpi-buffer
if [ ! -f "$queue_file" ]; then
echo "[]" > "$queue_file"
fi
entry="{\"req_hash\":\"$req_hash\",\"queued_at\":\"$(date -Iseconds)\",\"status\":\"pending\"}"
# Append to queue (keep last 100)
(cat "$queue_file" | jsonfilter -e '@[*]' 2>/dev/null; echo "$entry") | \
tail -100 | \
awk 'BEGIN{print "["} {if(NR>1)print ","; print} END{print "]"}' > "$queue_file.tmp"
mv "$queue_file.tmp" "$queue_file"
echo '{"success": true, "message": "Request queued for replay"}'
fi
;;
correlate_ip)
read "$3"
json_load "$REPLY"
json_get_var ip ip ""
if [ -z "$ip" ]; then
echo '{"success": false, "error": "IP required"}'
else
/usr/sbin/dpi-correlator correlate "$ip" "manual_request" >/dev/null 2>&1
echo '{"success": true, "message": "Correlation triggered for '"$ip"'"}'
fi
;;
get_correlation_stats)
/usr/sbin/dpi-correlator stats 2>/dev/null || echo '{"total_correlations": 0}'
;;
get_ip_context)
read "$3"
json_load "$REPLY"
json_get_var ip ip ""
if [ -z "$ip" ]; then
echo '{"error": "IP required"}'
else
/usr/sbin/dpi-correlator context "$ip" 2>/dev/null || echo '{"error": "Context not available"}'
fi
;;
get_ip_reputation)
read "$3"
json_load "$REPLY"
json_get_var ip ip ""
if [ -z "$ip" ]; then
echo '{"error": "IP required"}'
else
. /usr/lib/dpi-dual/correlation-lib.sh
init_reputation_db
score=$(get_ip_reputation "$ip")
echo "{\"ip\": \"$ip\", \"reputation_score\": $score}"
fi
;;
get_timeline)
read "$3"
json_load "$REPLY"
json_get_var limit limit 50
log_file="/tmp/secubox/correlated-threats.json"
if [ -f "$log_file" ]; then
total=$(wc -l < "$log_file" 2>/dev/null || echo 0)
# Get last N entries as JSON array
entries=$(tail -"$limit" "$log_file" 2>/dev/null | \
awk 'BEGIN { printf "[" }
{ if (NR > 1) printf ","; print }
END { printf "]" }')
cat << EOF
{
"total": $total,
"limit": $limit,
"entries": $entries
}
EOF
else
echo '{"total": 0, "limit": '$limit', "entries": []}'
fi
;;
search_correlations)
read "$3"
json_load "$REPLY"
json_get_var ip ip ""
json_get_var limit limit 50
results=$(/usr/sbin/dpi-correlator search "$ip" "$limit" 2>/dev/null | \
awk 'BEGIN { printf "[" }
{ if (NR > 1) printf ","; print }
END { printf "]" }')
echo "{\"results\": $results}"
;;
ban_ip)
read "$3"
json_load "$REPLY"
json_get_var ip ip ""
json_get_var duration duration "4h"
if [ -z "$ip" ]; then
echo '{"success": false, "error": "IP required"}'
else
if command -v cscli >/dev/null 2>&1; then
cscli decisions add -i "$ip" -d "$duration" -r "dpi-dual-manual" -t ban >/dev/null 2>&1
echo '{"success": true, "message": "IP '"$ip"' banned for '"$duration"'"}'
else
echo '{"success": false, "error": "CrowdSec not available"}'
fi
fi
;;
set_auto_ban)
read "$3"
json_load "$REPLY"
json_get_var enabled enabled "0"
val="0"
[ "$enabled" = "true" ] && val="1"
uci set dpi-dual.correlation.auto_ban="$val"
uci commit dpi-dual
echo '{"success": true, "auto_ban": '$val'}'
;;
get_lan_status)
# LAN passive flow analysis status
config_load dpi-dual
lan_enabled=""
lan_if=""
config_get lan_enabled lan enabled "0"
config_get lan_if lan interface "br-lan"
collector_running=0
pgrep -f dpi-lan-collect >/dev/null 2>&1 && collector_running=1
lan_file="$STATS_DIR/lan-flows.json"
active_clients=0 unique_dests=0 detected_protos=0
rx_bytes=0 tx_bytes=0
if [ -f "$lan_file" ]; then
active_clients=$(jsonfilter -i "$lan_file" -e '@.active_clients' 2>/dev/null || echo 0)
unique_dests=$(jsonfilter -i "$lan_file" -e '@.unique_destinations' 2>/dev/null || echo 0)
detected_protos=$(jsonfilter -i "$lan_file" -e '@.detected_protocols' 2>/dev/null || echo 0)
rx_bytes=$(jsonfilter -i "$lan_file" -e '@.rx_bytes' 2>/dev/null || echo 0)
tx_bytes=$(jsonfilter -i "$lan_file" -e '@.tx_bytes' 2>/dev/null || echo 0)
fi
cat << EOF
{
"enabled": $lan_enabled,
"interface": "$lan_if",
"collector_running": $collector_running,
"active_clients": $active_clients,
"unique_destinations": $unique_dests,
"detected_protocols": $detected_protos,
"rx_bytes": $rx_bytes,
"tx_bytes": $tx_bytes
}
EOF
;;
get_lan_clients)
clients_file="$STATS_DIR/lan-clients.json"
if [ -f "$clients_file" ]; then
cat "$clients_file"
else
echo '{"timestamp":"","clients":[]}'
fi
;;
get_lan_destinations)
read "$3"
json_load "$REPLY"
json_get_var limit limit 100
dests_file="$STATS_DIR/lan-destinations.json"
if [ -f "$dests_file" ]; then
cat "$dests_file"
else
echo '{"timestamp":"","destinations":[]}'
fi
;;
get_lan_protocols)
protos_file="$STATS_DIR/lan-protocols.json"
if [ -f "$protos_file" ]; then
cat "$protos_file"
else
echo '{"timestamp":"","protocols":[]}'
fi
;;
*)
echo '{"error": "Unknown method"}'
;;
esac
;;
esac