From e1ee84b3eb399891a3f38b87e497209cbe104e02 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Sun, 15 Mar 2026 17:15:13 +0100 Subject: [PATCH] fix(dashboards): WAF bans cache and DPI LAN flow display WAF Dashboard: - Use cached bans from cron (waf-stats-update) instead of slow cscli - Fixes "Failed to load bans" timeout issue DPI Dual-Stream: - Add LAN Flow Analysis card showing active clients, destinations, protocols - LAN passive flow analysis was working but not displayed Co-Authored-By: Claude Opus 4.5 --- .../resources/view/dpi-dual/overview.js | 15 +++++++++- .../root/usr/libexec/rpcd/luci.mitmproxy | 29 ++++--------------- .../files/usr/sbin/waf-stats-update | 13 ++++++++- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/package/secubox/luci-app-dpi-dual/htdocs/luci-static/resources/view/dpi-dual/overview.js b/package/secubox/luci-app-dpi-dual/htdocs/luci-static/resources/view/dpi-dual/overview.js index 8594db66..8fcfdee3 100644 --- a/package/secubox/luci-app-dpi-dual/htdocs/luci-static/resources/view/dpi-dual/overview.js +++ b/package/secubox/luci-app-dpi-dual/htdocs/luci-static/resources/view/dpi-dual/overview.js @@ -157,6 +157,7 @@ return view.extend({ var mitm = status.mitm_stream || {}; var tap = status.tap_stream || {}; var corr = status.correlation || {}; + var lan = status.lan_passive || {}; var view = E('div', { 'class': 'cbi-map', 'style': 'background:#0a0a12;min-height:100vh;' }, [ // Header @@ -249,7 +250,19 @@ return view.extend({ }) }, 'Correlate') ]) - ]), corr.running ? '#00d4aa' : '#808090') + ]), corr.running ? '#00d4aa' : '#808090'), + + // LAN Passive Flow Card + lan.enabled ? createCard('LAN Flow Analysis', '🌐', E('div', {}, [ + E('div', { 'style': 'margin-bottom:0.8rem;' }, createStatusLED(lan.running)), + E('div', { 'style': 'display:flex;flex-wrap:wrap;gap:8px;' }, [ + createMetric('Clients', lan.active_clients || 0, '#00d4aa'), + createMetric('Destinations', lan.unique_destinations || 0, '#00a0ff'), + createMetric('Protocols', lan.detected_protocols || 0, '#ffa500') + ]), + E('div', { 'style': 'margin-top:8px;color:#808090;font-size:0.8rem;' }, + 'Interface: ' + (lan.interface || 'br-lan')) + ]), lan.running ? '#00d4aa' : '#808090') : E('div') ]), // Threats Table diff --git a/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy b/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy index f301e619..48dddc9c 100755 --- a/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy +++ b/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy @@ -650,30 +650,13 @@ sync_routes() { } get_bans() { - # Get CrowdSec decisions as JSON - limit to avoid timeout - # CAPI blocklists can have thousands of entries, so we only show local decisions - local bans_json="[]" - local total=0 - local autoban=0 - local crowdsec_count=0 - - if command -v cscli >/dev/null 2>&1; then - # Get local decisions only (WAF auto-bans) - these are what users care about - # Using --limit to prevent huge output from CAPI blocklists - bans_json=$(cscli decisions list -o json --limit 100 2>/dev/null) - if [ -z "$bans_json" ] || [ "$bans_json" = "null" ]; then - bans_json="[]" - else - # Count using grep on the raw JSON - total=$(echo "$bans_json" | grep -c '"id":' 2>/dev/null) || total=0 - autoban=$(echo "$bans_json" | grep -c '"origin":.*"cscli"' 2>/dev/null) || autoban=0 - crowdsec_count=$(echo "$bans_json" | grep -c '"origin":.*"crowdsec"' 2>/dev/null) || crowdsec_count=0 - fi + # Read cached bans (updated every minute by cron) + local cache_file="/tmp/secubox/waf-bans.json" + if [ -f "$cache_file" ]; then + cat "$cache_file" + else + echo '{"success":true,"total":0,"mitmproxy_autoban":0,"crowdsec":0,"bans":[]}' fi - - # Build response with embedded bans array - printf '{"success":true,"total":%d,"mitmproxy_autoban":%d,"crowdsec":%d,"bans":%s}\n' \ - "$total" "$autoban" "$crowdsec_count" "$bans_json" } unban_ip() { diff --git a/package/secubox/secubox-app-mitmproxy/files/usr/sbin/waf-stats-update b/package/secubox/secubox-app-mitmproxy/files/usr/sbin/waf-stats-update index e414efa5..2d788694 100644 --- a/package/secubox/secubox-app-mitmproxy/files/usr/sbin/waf-stats-update +++ b/package/secubox/secubox-app-mitmproxy/files/usr/sbin/waf-stats-update @@ -1,9 +1,10 @@ #!/bin/sh -# WAF Stats Updater - writes to /tmp/secubox/waf-stats.json +# WAF Stats Updater - writes to /tmp/secubox/waf-stats.json and waf-bans.json # Run via cron every minute: * * * * * /usr/sbin/waf-stats-update CACHE_DIR="/tmp/secubox" CACHE_FILE="$CACHE_DIR/waf-stats.json" +BANS_CACHE="$CACHE_DIR/waf-bans.json" WAF_DATA="/srv/mitmproxy-in" mkdir -p "$CACHE_DIR" @@ -58,3 +59,13 @@ cat > "$CACHE_FILE" << EOF "updated": "$(date -Iseconds)" } EOF + +# Cache CrowdSec bans for fast dashboard loading +if command -v cscli >/dev/null 2>&1; then + bans_json=$(cscli decisions list -o json --limit 20 2>/dev/null) + [ -z "$bans_json" ] || [ "$bans_json" = "null" ] && bans_json="[]" + total=$(echo "$bans_json" | grep -c '"id":' 2>/dev/null) || total=0 + printf '{"success":true,"total":%d,"bans":%s}\n' "$total" "$bans_json" > "$BANS_CACHE" +else + echo '{"success":true,"total":0,"bans":[]}' > "$BANS_CACHE" +fi