fix(tor-shield,security-threats): Preset persistence and firewall stats
Tor Shield: - Store current_preset in UCI when enabling with preset - Return current_preset in status response - Initialize currentPreset from stored UCI value on page load Security Threats: - Fix get_security_stats() firewall packet counting - Use correct nftables chain names (input_wan, handle_reject) - Fix grep -c exit code issue (returns 1 when no matches) - Improve numeric validation (use tr -cd to strip non-digits) - Add fallbacks for HAProxy socket paths Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
025a1085e9
commit
cf49c7d80b
@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-secubox-security-threats
|
PKG_NAME:=luci-app-secubox-security-threats
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=1.0.0
|
||||||
PKG_RELEASE:=3
|
PKG_RELEASE:=4
|
||||||
PKG_ARCH:=all
|
PKG_ARCH:=all
|
||||||
PKG_LICENSE:=Apache-2.0
|
PKG_LICENSE:=Apache-2.0
|
||||||
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
|
||||||
|
|||||||
@ -279,58 +279,116 @@ get_security_stats() {
|
|||||||
local wan_iface=$(uci -q get network.wan.device || uci -q get network.wan.ifname)
|
local wan_iface=$(uci -q get network.wan.device || uci -q get network.wan.ifname)
|
||||||
[ -z "$wan_iface" ] && wan_iface="eth0"
|
[ -z "$wan_iface" ] && wan_iface="eth0"
|
||||||
|
|
||||||
# WAN dropped packets from nftables (actual firewall drops on input chain)
|
# WAN dropped packets from nftables (use counter on drop rules)
|
||||||
# Count packets dropped/rejected on wan zone input
|
|
||||||
if command -v nft >/dev/null 2>&1; then
|
if command -v nft >/dev/null 2>&1; then
|
||||||
# Get drop counters from firewall input chain for wan
|
# Get all drop/reject counters from input_wan zone
|
||||||
wan_drops=$(nft list chain inet fw4 input 2>/dev/null | grep -E "iifname.*$wan_iface.*drop|iifname.*$wan_iface.*reject" | grep -oE 'packets [0-9]+' | awk '{sum+=$2} END {print sum+0}')
|
# nft format: "counter packets X bytes Y"
|
||||||
# Also count from forward chain drops (wan to lan blocked)
|
wan_drops=$(nft list chain inet fw4 input_wan 2>/dev/null | \
|
||||||
local wan_fwd_drops=$(nft list chain inet fw4 forward 2>/dev/null | grep -E "iifname.*$wan_iface.*drop|iifname.*$wan_iface.*reject" | grep -oE 'packets [0-9]+' | awk '{sum+=$2} END {print sum+0}')
|
grep -E "counter packets" | \
|
||||||
wan_drops=$((${wan_drops:-0} + ${wan_fwd_drops:-0}))
|
grep -oE 'packets [0-9]+' | \
|
||||||
|
awk '{sum+=$2} END {print sum+0}')
|
||||||
|
[ -z "$wan_drops" ] && wan_drops=0
|
||||||
|
|
||||||
|
# Also try reject chain
|
||||||
|
local reject_drops=$(nft list chain inet fw4 reject_from_wan 2>/dev/null | \
|
||||||
|
grep -E "counter packets" | \
|
||||||
|
grep -oE 'packets [0-9]+' | \
|
||||||
|
awk '{sum+=$2} END {print sum+0}')
|
||||||
|
[ -n "$reject_drops" ] && wan_drops=$((wan_drops + reject_drops))
|
||||||
fi
|
fi
|
||||||
wan_drops=${wan_drops:-0}
|
wan_drops=${wan_drops:-0}
|
||||||
|
|
||||||
# Firewall rejects - count from nftables counters (more accurate than logs)
|
# Firewall rejects - count from reject-specific chains
|
||||||
if command -v nft >/dev/null 2>&1; then
|
if command -v nft >/dev/null 2>&1; then
|
||||||
fw_rejects=$(nft list ruleset 2>/dev/null | grep -E "reject|drop" | grep -oE 'packets [0-9]+' | awk '{sum+=$2} END {print sum+0}')
|
# Count from handle_reject chain which has actual reject rules
|
||||||
|
fw_rejects=$(nft list chain inet fw4 handle_reject 2>/dev/null | \
|
||||||
|
grep -E "counter packets" | \
|
||||||
|
grep -oE 'packets [0-9]+' | \
|
||||||
|
awk '{sum+=$2} END {print sum+0}')
|
||||||
|
[ -z "$fw_rejects" ] && fw_rejects=0
|
||||||
|
|
||||||
|
# If no handle_reject, try counting reject rules in all chains
|
||||||
|
if [ "$fw_rejects" = "0" ]; then
|
||||||
|
fw_rejects=$(nft -a list ruleset 2>/dev/null | \
|
||||||
|
grep -E "reject|drop" | grep "counter" | \
|
||||||
|
grep -oE 'packets [0-9]+' | \
|
||||||
|
awk '{sum+=$2} END {print sum+0}')
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
# Fallback to log parsing
|
# Fallback to log parsing
|
||||||
fw_rejects=$(logread 2>/dev/null | grep -c "reject\|DROP\|REJECT" || echo 0)
|
fw_rejects=$(logread 2>/dev/null | grep -c "reject\|DROP\|REJECT" || echo 0)
|
||||||
fi
|
fi
|
||||||
fw_rejects=$(echo "$fw_rejects" | tr -d '\n')
|
|
||||||
fw_rejects=${fw_rejects:-0}
|
fw_rejects=${fw_rejects:-0}
|
||||||
|
|
||||||
# CrowdSec active bans
|
# CrowdSec active bans
|
||||||
if [ -x "$CSCLI" ]; then
|
if [ -x "$CSCLI" ]; then
|
||||||
cs_bans=$($CSCLI decisions list -o json 2>/dev/null | grep -c '"id":' || echo 0)
|
# Use jq for proper JSON parsing if available, fallback to grep
|
||||||
cs_bans=$(echo "$cs_bans" | tr -d '\n')
|
if command -v jq >/dev/null 2>&1; then
|
||||||
|
cs_bans=$($CSCLI decisions list -o json 2>/dev/null | jq 'length' 2>/dev/null)
|
||||||
|
[ -z "$cs_bans" ] && cs_bans=0
|
||||||
|
else
|
||||||
|
# Count JSON array items
|
||||||
|
local cs_json=$($CSCLI decisions list -o json 2>/dev/null)
|
||||||
|
if [ -n "$cs_json" ] && [ "$cs_json" != "null" ] && [ "$cs_json" != "[]" ]; then
|
||||||
|
cs_bans=$(echo "$cs_json" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
cs_bans=${cs_bans:-0}
|
cs_bans=${cs_bans:-0}
|
||||||
|
|
||||||
# CrowdSec alerts in last 24h
|
# CrowdSec alerts in last 24h
|
||||||
cs_alerts_24h=$($CSCLI alerts list -o json --since 24h 2>/dev/null | grep -c '"id":' || echo 0)
|
if command -v jq >/dev/null 2>&1; then
|
||||||
cs_alerts_24h=$(echo "$cs_alerts_24h" | tr -d '\n')
|
cs_alerts_24h=$($CSCLI alerts list -o json --since 24h 2>/dev/null | jq 'length' 2>/dev/null)
|
||||||
|
[ -z "$cs_alerts_24h" ] && cs_alerts_24h=0
|
||||||
|
else
|
||||||
|
local alerts_json=$($CSCLI alerts list -o json --since 24h 2>/dev/null)
|
||||||
|
if [ -n "$alerts_json" ] && [ "$alerts_json" != "null" ] && [ "$alerts_json" != "[]" ]; then
|
||||||
|
cs_alerts_24h=$(echo "$alerts_json" | jsonfilter -e '@[*]' 2>/dev/null | wc -l)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
cs_alerts_24h=${cs_alerts_24h:-0}
|
cs_alerts_24h=${cs_alerts_24h:-0}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Invalid connections (conntrack)
|
# Invalid connections (conntrack) - only count INVALID, not UNREPLIED
|
||||||
if [ -f /proc/net/nf_conntrack ]; then
|
if [ -f /proc/net/nf_conntrack ]; then
|
||||||
invalid_conns=$(grep -c "INVALID\|UNREPLIED" /proc/net/nf_conntrack 2>/dev/null || echo 0)
|
# grep -c returns 1 exit code when no matches, so we can't use || echo 0
|
||||||
|
invalid_conns=$(grep -c "\[INVALID\]" /proc/net/nf_conntrack 2>/dev/null)
|
||||||
|
[ -z "$invalid_conns" ] && invalid_conns=0
|
||||||
fi
|
fi
|
||||||
invalid_conns=$(echo "$invalid_conns" | tr -d '\n')
|
|
||||||
invalid_conns=${invalid_conns:-0}
|
invalid_conns=${invalid_conns:-0}
|
||||||
|
|
||||||
# HAProxy connections (if running in LXC)
|
# HAProxy connections
|
||||||
if lxc-info -n haproxy -s 2>/dev/null | grep -q "RUNNING"; then
|
# Try local haproxy first, then LXC
|
||||||
# Try multiple socket paths (chroot-relative and absolute)
|
if [ -S /var/run/haproxy/admin.sock ]; then
|
||||||
|
haproxy_conns=$(echo "show stat" | socat stdio /var/run/haproxy/admin.sock 2>/dev/null | \
|
||||||
|
tail -n+2 | awk -F, '{sum+=$5} END {print sum+0}')
|
||||||
|
elif [ -S /var/lib/haproxy/stats ]; then
|
||||||
|
haproxy_conns=$(echo "show stat" | socat stdio /var/lib/haproxy/stats 2>/dev/null | \
|
||||||
|
tail -n+2 | awk -F, '{sum+=$5} END {print sum+0}')
|
||||||
|
elif command -v lxc-info >/dev/null 2>&1 && lxc-info -n haproxy -s 2>/dev/null | grep -q "RUNNING"; then
|
||||||
|
# HAProxy in LXC container
|
||||||
haproxy_conns=$(lxc-attach -n haproxy -- sh -c '
|
haproxy_conns=$(lxc-attach -n haproxy -- sh -c '
|
||||||
for sock in /stats /run/haproxy.sock /var/lib/haproxy/stats /var/run/haproxy/admin.sock; do
|
for sock in /stats /run/haproxy.sock /var/lib/haproxy/stats /var/run/haproxy/admin.sock; do
|
||||||
[ -S "$sock" ] && echo "show stat" | socat stdio "$sock" 2>/dev/null && break
|
[ -S "$sock" ] && { echo "show stat" | socat stdio "$sock" 2>/dev/null; break; }
|
||||||
done | tail -n+2 | awk -F, "{sum+=\$5} END {print sum+0}"
|
done' 2>/dev/null | tail -n+2 | awk -F, '{sum+=$5} END {print sum+0}')
|
||||||
' 2>/dev/null || echo 0)
|
|
||||||
fi
|
fi
|
||||||
haproxy_conns=$(echo "$haproxy_conns" | tr -d '\n')
|
|
||||||
haproxy_conns=${haproxy_conns:-0}
|
haproxy_conns=${haproxy_conns:-0}
|
||||||
|
|
||||||
|
# Clean up and ensure numeric values (remove all non-digits)
|
||||||
|
wan_drops=$(printf '%s' "$wan_drops" | tr -cd '0-9')
|
||||||
|
fw_rejects=$(printf '%s' "$fw_rejects" | tr -cd '0-9')
|
||||||
|
cs_bans=$(printf '%s' "$cs_bans" | tr -cd '0-9')
|
||||||
|
cs_alerts_24h=$(printf '%s' "$cs_alerts_24h" | tr -cd '0-9')
|
||||||
|
invalid_conns=$(printf '%s' "$invalid_conns" | tr -cd '0-9')
|
||||||
|
haproxy_conns=$(printf '%s' "$haproxy_conns" | tr -cd '0-9')
|
||||||
|
|
||||||
|
# Default to 0 if empty
|
||||||
|
: ${wan_drops:=0}
|
||||||
|
: ${fw_rejects:=0}
|
||||||
|
: ${cs_bans:=0}
|
||||||
|
: ${cs_alerts_24h:=0}
|
||||||
|
: ${invalid_conns:=0}
|
||||||
|
: ${haproxy_conns:=0}
|
||||||
|
|
||||||
# Output JSON
|
# Output JSON
|
||||||
cat << EOF
|
cat << EOF
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
|||||||
|
|
||||||
PKG_NAME:=luci-app-tor-shield
|
PKG_NAME:=luci-app-tor-shield
|
||||||
PKG_VERSION:=1.0.0
|
PKG_VERSION:=1.0.0
|
||||||
PKG_RELEASE:=9
|
PKG_RELEASE:=10
|
||||||
PKG_ARCH:=all
|
PKG_ARCH:=all
|
||||||
|
|
||||||
PKG_LICENSE:=MIT
|
PKG_LICENSE:=MIT
|
||||||
|
|||||||
@ -285,6 +285,9 @@ return view.extend({
|
|||||||
var presets = data.presets || [];
|
var presets = data.presets || [];
|
||||||
var bandwidth = data.bandwidth || {};
|
var bandwidth = data.bandwidth || {};
|
||||||
|
|
||||||
|
// Initialize currentPreset from stored UCI value
|
||||||
|
this.currentPreset = status.current_preset || 'anonymous';
|
||||||
|
|
||||||
var isActive = status.enabled && status.running;
|
var isActive = status.enabled && status.running;
|
||||||
var isProtected = isActive && status.is_tor;
|
var isProtected = isActive && status.is_tor;
|
||||||
var isConnecting = isActive && status.bootstrap < 100;
|
var isConnecting = isActive && status.bootstrap < 100;
|
||||||
|
|||||||
@ -54,17 +54,19 @@ get_bootstrap() {
|
|||||||
get_status() {
|
get_status() {
|
||||||
json_init
|
json_init
|
||||||
|
|
||||||
local enabled mode dns_over_tor kill_switch
|
local enabled mode dns_over_tor kill_switch current_preset
|
||||||
config_load "$CONFIG"
|
config_load "$CONFIG"
|
||||||
config_get enabled main enabled '0'
|
config_get enabled main enabled '0'
|
||||||
config_get mode main mode 'transparent'
|
config_get mode main mode 'transparent'
|
||||||
config_get dns_over_tor main dns_over_tor '1'
|
config_get dns_over_tor main dns_over_tor '1'
|
||||||
config_get kill_switch main kill_switch '1'
|
config_get kill_switch main kill_switch '1'
|
||||||
|
config_get current_preset main current_preset 'anonymous'
|
||||||
|
|
||||||
json_add_boolean "enabled" "$enabled"
|
json_add_boolean "enabled" "$enabled"
|
||||||
json_add_string "mode" "$mode"
|
json_add_string "mode" "$mode"
|
||||||
json_add_boolean "dns_over_tor" "$dns_over_tor"
|
json_add_boolean "dns_over_tor" "$dns_over_tor"
|
||||||
json_add_boolean "kill_switch" "$kill_switch"
|
json_add_boolean "kill_switch" "$kill_switch"
|
||||||
|
json_add_string "current_preset" "$current_preset"
|
||||||
|
|
||||||
# Running state
|
# Running state
|
||||||
if is_running; then
|
if is_running; then
|
||||||
@ -164,6 +166,7 @@ do_enable() {
|
|||||||
uci set tor-shield.main.mode="$preset_mode"
|
uci set tor-shield.main.mode="$preset_mode"
|
||||||
uci set tor-shield.main.dns_over_tor="$preset_dns"
|
uci set tor-shield.main.dns_over_tor="$preset_dns"
|
||||||
uci set tor-shield.main.kill_switch="$preset_kill"
|
uci set tor-shield.main.kill_switch="$preset_kill"
|
||||||
|
uci set tor-shield.main.current_preset="$preset"
|
||||||
|
|
||||||
if [ "$preset_bridges" = "1" ]; then
|
if [ "$preset_bridges" = "1" ]; then
|
||||||
uci set tor-shield.bridges.enabled='1'
|
uci set tor-shield.bridges.enabled='1'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user