diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js index fe5ed5a2..fe02153e 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js @@ -145,6 +145,39 @@ var callDeleteBouncer = rpc.declare({ expect: { success: false } }); +// Firewall Bouncer Management +var callFirewallBouncerStatus = rpc.declare({ + object: 'luci.crowdsec-dashboard', + method: 'firewall_bouncer_status', + expect: { } +}); + +var callControlFirewallBouncer = rpc.declare({ + object: 'luci.crowdsec-dashboard', + method: 'control_firewall_bouncer', + params: ['action'], + expect: { success: false } +}); + +var callFirewallBouncerConfig = rpc.declare({ + object: 'luci.crowdsec-dashboard', + method: 'firewall_bouncer_config', + expect: { } +}); + +var callUpdateFirewallBouncerConfig = rpc.declare({ + object: 'luci.crowdsec-dashboard', + method: 'update_firewall_bouncer_config', + params: ['key', 'value'], + expect: { success: false } +}); + +var callNftablesStats = rpc.declare({ + object: 'luci.crowdsec-dashboard', + method: 'nftables_stats', + expect: { } +}); + function formatDuration(seconds) { if (!seconds) return 'N/A'; if (seconds < 60) return seconds + 's'; @@ -188,6 +221,13 @@ return baseclass.extend({ registerBouncer: callRegisterBouncer, deleteBouncer: callDeleteBouncer, + // Firewall Bouncer Management + getFirewallBouncerStatus: callFirewallBouncerStatus, + controlFirewallBouncer: callControlFirewallBouncer, + getFirewallBouncerConfig: callFirewallBouncerConfig, + updateFirewallBouncerConfig: callUpdateFirewallBouncerConfig, + getNftablesStats: callNftablesStats, + formatDuration: formatDuration, formatDate: formatDate, diff --git a/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard b/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard index fdcb9dfe..e85121e4 100755 --- a/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard +++ b/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard @@ -462,10 +462,321 @@ delete_bouncer() { json_dump } +# Get firewall bouncer detailed status +get_firewall_bouncer_status() { + json_init + + # Check if service is running + local running=0 + if pgrep -f "cs-firewall-bouncer" >/dev/null 2>&1; then + running=1 + fi + json_add_boolean "running" "$running" + + # Check if service is enabled + local enabled=0 + if [ -f "/etc/rc.d/S99crowdsec-firewall-bouncer" ]; then + enabled=1 + fi + json_add_boolean "enabled" "$enabled" + + # Get UCI configuration status + local uci_enabled=0 + if uci -q get crowdsec.bouncer.enabled >/dev/null 2>&1; then + local val + val=$(uci -q get crowdsec.bouncer.enabled) + [ "$val" = "1" ] && uci_enabled=1 + fi + json_add_boolean "configured" "$uci_enabled" + + # Get nftables tables status + local nft_ipv4=0 + local nft_ipv6=0 + if command -v nft >/dev/null 2>&1; then + nft list tables 2>/dev/null | grep -q "crowdsec" && nft_ipv4=1 + nft list tables 2>/dev/null | grep -q "crowdsec6" && nft_ipv6=1 + fi + json_add_boolean "nftables_ipv4" "$nft_ipv4" + json_add_boolean "nftables_ipv6" "$nft_ipv6" + + # Get blocked IPs count + local ipv4_count=0 + local ipv6_count=0 + if [ "$nft_ipv4" = "1" ]; then + ipv4_count=$(nft list set ip crowdsec crowdsec-blacklists 2>/dev/null | grep -c "elements = {" || echo "0") + fi + if [ "$nft_ipv6" = "1" ]; then + ipv6_count=$(nft list set ip6 crowdsec6 crowdsec6-blacklists 2>/dev/null | grep -c "elements = {" || echo "0") + fi + json_add_int "blocked_ipv4" "$ipv4_count" + json_add_int "blocked_ipv6" "$ipv6_count" + + json_dump +} + +# Control firewall bouncer service (start/stop/restart/enable/disable) +control_firewall_bouncer() { + local action="$1" + json_init + + if [ -z "$action" ]; then + json_add_boolean "success" 0 + json_add_string "error" "Action required (start|stop|restart|enable|disable)" + json_dump + return + fi + + case "$action" in + start) + if /etc/init.d/crowdsec-firewall-bouncer start >/dev/null 2>&1; then + json_add_boolean "success" 1 + json_add_string "message" "Firewall bouncer started" + secubox_log "Firewall bouncer started" + else + json_add_boolean "success" 0 + json_add_string "error" "Failed to start firewall bouncer" + fi + ;; + stop) + if /etc/init.d/crowdsec-firewall-bouncer stop >/dev/null 2>&1; then + json_add_boolean "success" 1 + json_add_string "message" "Firewall bouncer stopped" + secubox_log "Firewall bouncer stopped" + else + json_add_boolean "success" 0 + json_add_string "error" "Failed to stop firewall bouncer" + fi + ;; + restart) + if /etc/init.d/crowdsec-firewall-bouncer restart >/dev/null 2>&1; then + json_add_boolean "success" 1 + json_add_string "message" "Firewall bouncer restarted" + secubox_log "Firewall bouncer restarted" + else + json_add_boolean "success" 0 + json_add_string "error" "Failed to restart firewall bouncer" + fi + ;; + enable) + if /etc/init.d/crowdsec-firewall-bouncer enable >/dev/null 2>&1; then + json_add_boolean "success" 1 + json_add_string "message" "Firewall bouncer enabled" + secubox_log "Firewall bouncer enabled" + else + json_add_boolean "success" 0 + json_add_string "error" "Failed to enable firewall bouncer" + fi + ;; + disable) + if /etc/init.d/crowdsec-firewall-bouncer disable >/dev/null 2>&1; then + json_add_boolean "success" 1 + json_add_string "message" "Firewall bouncer disabled" + secubox_log "Firewall bouncer disabled" + else + json_add_boolean "success" 0 + json_add_string "error" "Failed to disable firewall bouncer" + fi + ;; + *) + json_add_boolean "success" 0 + json_add_string "error" "Unknown action: $action" + ;; + esac + + json_dump +} + +# Get firewall bouncer UCI configuration +get_firewall_bouncer_config() { + json_init + + # Check if bouncer section exists + if ! uci -q get crowdsec.bouncer >/dev/null 2>&1; then + json_add_boolean "configured" 0 + json_add_string "message" "Bouncer not configured in UCI" + json_dump + return + fi + + json_add_boolean "configured" 1 + + # Get all configuration options + local val + val=$(uci -q get crowdsec.bouncer.enabled || echo "0") + json_add_string "enabled" "$val" + + val=$(uci -q get crowdsec.bouncer.ipv4 || echo "1") + json_add_string "ipv4" "$val" + + val=$(uci -q get crowdsec.bouncer.ipv6 || echo "1") + json_add_string "ipv6" "$val" + + val=$(uci -q get crowdsec.bouncer.api_url || echo "http://127.0.0.1:8080/") + json_add_string "api_url" "$val" + + val=$(uci -q get crowdsec.bouncer.update_frequency || echo "10s") + json_add_string "update_frequency" "$val" + + val=$(uci -q get crowdsec.bouncer.deny_action || echo "drop") + json_add_string "deny_action" "$val" + + val=$(uci -q get crowdsec.bouncer.deny_log || echo "0") + json_add_string "deny_log" "$val" + + val=$(uci -q get crowdsec.bouncer.log_level || echo "info") + json_add_string "log_level" "$val" + + val=$(uci -q get crowdsec.bouncer.filter_input || echo "1") + json_add_string "filter_input" "$val" + + val=$(uci -q get crowdsec.bouncer.filter_forward || echo "1") + json_add_string "filter_forward" "$val" + + # Get interfaces list + json_add_array "interfaces" + local interfaces + interfaces=$(uci -q get crowdsec.bouncer.interface 2>/dev/null || echo "") + if [ -n "$interfaces" ]; then + local iface + for iface in $interfaces; do + json_add_string "" "$iface" + done + fi + json_close_array + + json_dump +} + +# Update firewall bouncer UCI configuration +update_firewall_bouncer_config() { + local key="$1" + local value="$2" + json_init + + if [ -z "$key" ]; then + json_add_boolean "success" 0 + json_add_string "error" "Configuration key required" + json_dump + return + fi + + # Validate and set configuration + case "$key" in + enabled|ipv4|ipv6|deny_log|filter_input|filter_forward) + # Boolean values + if [ "$value" != "0" ] && [ "$value" != "1" ]; then + json_add_boolean "success" 0 + json_add_string "error" "Invalid boolean value: $value" + json_dump + return + fi + uci set "crowdsec.bouncer.$key=$value" + ;; + api_url|update_frequency|deny_action|log_level) + # String values + if [ -z "$value" ]; then + json_add_boolean "success" 0 + json_add_string "error" "Value cannot be empty" + json_dump + return + fi + uci set "crowdsec.bouncer.$key=$value" + ;; + *) + json_add_boolean "success" 0 + json_add_string "error" "Unknown configuration key: $key" + json_dump + return + ;; + esac + + # Commit changes + if uci commit crowdsec 2>/dev/null; then + json_add_boolean "success" 1 + json_add_string "message" "Configuration updated: $key=$value" + secubox_log "Firewall bouncer config updated: $key=$value" + else + json_add_boolean "success" 0 + json_add_string "error" "Failed to commit UCI changes" + fi + + json_dump +} + +# Get nftables statistics +get_nftables_stats() { + json_init + + if ! command -v nft >/dev/null 2>&1; then + json_add_boolean "available" 0 + json_add_string "error" "nftables not available" + json_dump + return + fi + + json_add_boolean "available" 1 + + # Check IPv4 table + local ipv4_exists=0 + if nft list table ip crowdsec >/dev/null 2>&1; then + ipv4_exists=1 + fi + json_add_boolean "ipv4_table_exists" "$ipv4_exists" + + # Check IPv6 table + local ipv6_exists=0 + if nft list table ip6 crowdsec6 >/dev/null 2>&1; then + ipv6_exists=1 + fi + json_add_boolean "ipv6_table_exists" "$ipv6_exists" + + # Get blocked IPs from IPv4 set + json_add_array "ipv4_blocked_ips" + if [ "$ipv4_exists" = "1" ]; then + local ips + ips=$(nft list set ip crowdsec crowdsec-blacklists 2>/dev/null | sed -n '/elements = {/,/}/p' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' || echo "") + if [ -n "$ips" ]; then + local ip + for ip in $ips; do + json_add_string "" "$ip" + done + fi + fi + json_close_array + + # Get blocked IPs from IPv6 set + json_add_array "ipv6_blocked_ips" + if [ "$ipv6_exists" = "1" ]; then + local ips + ips=$(nft list set ip6 crowdsec6 crowdsec6-blacklists 2>/dev/null | sed -n '/elements = {/,/}/p' | grep -oE '([0-9a-fA-F]{0,4}:){7}[0-9a-fA-F]{0,4}' || echo "") + if [ -n "$ips" ]; then + local ip + for ip in $ips; do + json_add_string "" "$ip" + done + fi + fi + json_close_array + + # Get rules count + local ipv4_rules=0 + local ipv6_rules=0 + if [ "$ipv4_exists" = "1" ]; then + ipv4_rules=$(nft list table ip crowdsec 2>/dev/null | grep -c "rule" || echo "0") + fi + if [ "$ipv6_exists" = "1" ]; then + ipv6_rules=$(nft list table ip6 crowdsec6 2>/dev/null | grep -c "rule" || echo "0") + fi + json_add_int "ipv4_rules_count" "$ipv4_rules" + json_add_int "ipv6_rules_count" "$ipv6_rules" + + json_dump +} + # Main dispatcher case "$1" in list) - echo '{"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"seccubox_logs":{},"collect_debug":{},"waf_status":{},"metrics_config":{},"configure_metrics":{"enable":"string"},"collections":{},"install_collection":{"collection":"string"},"remove_collection":{"collection":"string"},"update_hub":{},"register_bouncer":{"bouncer_name":"string"},"delete_bouncer":{"bouncer_name":"string"}}' + echo '{"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"seccubox_logs":{},"collect_debug":{},"waf_status":{},"metrics_config":{},"configure_metrics":{"enable":"string"},"collections":{},"install_collection":{"collection":"string"},"remove_collection":{"collection":"string"},"update_hub":{},"register_bouncer":{"bouncer_name":"string"},"delete_bouncer":{"bouncer_name":"string"},"firewall_bouncer_status":{},"control_firewall_bouncer":{"action":"string"},"firewall_bouncer_config":{},"update_firewall_bouncer_config":{"key":"string","value":"string"},"nftables_stats":{}}' ;; call) case "$2" in @@ -550,6 +861,26 @@ case "$1" in bouncer_name=$(echo "$input" | jsonfilter -e '@.bouncer_name' 2>/dev/null) delete_bouncer "$bouncer_name" ;; + firewall_bouncer_status) + get_firewall_bouncer_status + ;; + control_firewall_bouncer) + read -r input + action=$(echo "$input" | jsonfilter -e '@.action' 2>/dev/null) + control_firewall_bouncer "$action" + ;; + firewall_bouncer_config) + get_firewall_bouncer_config + ;; + update_firewall_bouncer_config) + read -r input + key=$(echo "$input" | jsonfilter -e '@.key' 2>/dev/null) + value=$(echo "$input" | jsonfilter -e '@.value' 2>/dev/null) + update_firewall_bouncer_config "$key" "$value" + ;; + nftables_stats) + get_nftables_stats + ;; *) echo '{"error": "Unknown method"}' ;;