refactor(packages): Rename and reorganize SecuBox packages

- Rename crowdsec-firewall-bouncer to secubox-app-cs-firewall-bouncer
- Rename secubox-auth-logger to secubox-app-auth-logger
- Delete secubox-crowdsec-setup (merged into other packages)
- Fix circular dependencies in luci-app-secubox-crowdsec
- Fix dependency chain in secubox-app-crowdsec-bouncer
- Add consolidated get_overview API to crowdsec-dashboard
- Improve crowdsec-dashboard overview performance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-15 10:42:52 +01:00
parent fd7caeb8c3
commit e62919eec7
23 changed files with 254 additions and 1165 deletions

View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-crowdsec-dashboard PKG_NAME:=luci-app-crowdsec-dashboard
PKG_VERSION:=0.7.0 PKG_VERSION:=0.7.0
PKG_RELEASE:=27 PKG_RELEASE:=28
PKG_ARCH:=all PKG_ARCH:=all
PKG_LICENSE:=Apache-2.0 PKG_LICENSE:=Apache-2.0

View File

@ -526,6 +526,7 @@ return view.extend({
]), ]),
E('div', { 'class': 'cs-charts-row' }, [ E('div', { 'class': 'cs-charts-row' }, [
this.renderFirewallHealth(),
this.renderFirewallBlocks() this.renderFirewallBlocks()
]), ]),
@ -871,6 +872,78 @@ return view.extend({
]); ]);
}, },
// Firewall Health Status Card
renderFirewallHealth: function() {
var stats = this.nftablesStats || {};
var health = stats.firewall_health || {};
var status = health.status || 'unknown';
var issues = health.issues || '';
var bouncerRunning = health.bouncer_running;
var uciEnabled = health.uci_enabled;
var apiKeyConfigured = health.api_key_configured;
var inputHooked = health.input_chain_hooked;
var forwardHooked = health.forward_chain_hooked;
var setsHaveTimeout = health.sets_have_timeout;
var decisionsSynced = health.decisions_synced;
var cscliDecisions = health.cscli_decisions_count || 0;
var nftElements = health.nft_elements_count || 0;
var statusColor = status === 'ok' ? '#00d4aa' : (status === 'warning' ? '#ffa500' : '#ff4757');
var statusIcon = status === 'ok' ? '✅' : (status === 'warning' ? '⚠️' : '❌');
var statusText = status === 'ok' ? 'Healthy' : (status === 'warning' ? 'Warning' : 'Error');
var checkItems = [
{ label: 'Bouncer Process', ok: bouncerRunning, detail: bouncerRunning ? 'Running' : 'Not running' },
{ label: 'UCI Enabled', ok: uciEnabled, detail: uciEnabled ? 'Enabled' : 'Disabled' },
{ label: 'API Key', ok: apiKeyConfigured, detail: apiKeyConfigured ? 'Configured' : 'Missing or default' },
{ label: 'Input Chain', ok: inputHooked, detail: inputHooked ? 'Hooked' : 'Not hooked' },
{ label: 'Forward Chain', ok: forwardHooked, detail: forwardHooked ? 'Hooked' : 'Not hooked' },
{ label: 'Set Timeout', ok: setsHaveTimeout, detail: setsHaveTimeout ? 'Enabled' : 'Disabled' },
{ label: 'Decisions Sync', ok: decisionsSynced, detail: decisionsSynced ? (nftElements + ' synced') : 'Out of sync' }
];
var checkRows = checkItems.map(function(item) {
return E('div', { 'style': 'display: flex; align-items: center; justify-content: space-between; padding: 0.4em 0; border-bottom: 1px solid rgba(255,255,255,0.05);' }, [
E('div', { 'style': 'display: flex; align-items: center; gap: 0.5em;' }, [
E('span', { 'style': 'font-size: 1em;' }, item.ok ? '✅' : '❌'),
E('span', { 'style': 'font-size: 0.85em;' }, item.label)
]),
E('span', { 'style': 'font-size: 0.75em; color: ' + (item.ok ? '#00d4aa' : '#ff4757') + ';' }, item.detail)
]);
});
return E('div', { 'class': 'cs-card', 'style': 'flex: 1;' }, [
E('div', { 'class': 'cs-card-header' }, [
E('div', { 'class': 'cs-card-title' }, [
_('Firewall Health'),
E('span', {
'style': 'margin-left: 0.75em; font-size: 0.8em; padding: 0.2em 0.6em; background: ' + statusColor + '; border-radius: 12px;'
}, statusIcon + ' ' + statusText)
])
]),
E('div', { 'class': 'cs-card-body' }, [
// Status summary
issues ? E('div', { 'style': 'background: rgba(255,71,87,0.1); border: 1px solid rgba(255,71,87,0.3); border-radius: 8px; padding: 0.75em; margin-bottom: 1em;' }, [
E('div', { 'style': 'font-size: 0.85em; color: #ff4757;' }, issues)
]) : E('span'),
// Sync stats
E('div', { 'style': 'display: flex; gap: 1em; margin-bottom: 1em;' }, [
E('div', { 'style': 'flex: 1; text-align: center; padding: 0.5em; background: rgba(102,126,234,0.1); border-radius: 8px;' }, [
E('div', { 'style': 'font-size: 1.25em; font-weight: 700; color: #667eea;' }, String(cscliDecisions)),
E('div', { 'style': 'font-size: 0.7em; color: #888;' }, 'Decisions')
]),
E('div', { 'style': 'flex: 1; text-align: center; padding: 0.5em; background: rgba(0,212,170,0.1); border-radius: 8px;' }, [
E('div', { 'style': 'font-size: 1.25em; font-weight: 700; color: #00d4aa;' }, String(nftElements)),
E('div', { 'style': 'font-size: 0.7em; color: #888;' }, 'In Firewall')
])
]),
// Check items
E('div', {}, checkRows)
])
]);
},
// Firewall Blocks - Shows IPs blocked in nftables // Firewall Blocks - Shows IPs blocked in nftables
renderFirewallBlocks: function() { renderFirewallBlocks: function() {
var self = this; var self = this;

View File

@ -947,6 +947,86 @@ get_nftables_stats() {
json_add_int "ipv6_cscli_count" "$ipv6_cscli" json_add_int "ipv6_cscli_count" "$ipv6_cscli"
json_add_int "ipv6_total_count" "$((ipv6_capi + ipv6_cscli))" json_add_int "ipv6_total_count" "$((ipv6_capi + ipv6_cscli))"
# Firewall Health Check
json_add_object "firewall_health"
# Check bouncer process
local bouncer_running=0
if pgrep cs-firewall-bouncer >/dev/null 2>&1; then
bouncer_running=1
fi
json_add_boolean "bouncer_running" "$bouncer_running"
# Check UCI config
local uci_enabled=0
local uci_api_key=""
if uci -q get crowdsec.bouncer.enabled >/dev/null 2>&1; then
[ "$(uci -q get crowdsec.bouncer.enabled)" = "1" ] && uci_enabled=1
fi
uci_api_key=$(uci -q get crowdsec.bouncer.api_key 2>/dev/null)
json_add_boolean "uci_enabled" "$uci_enabled"
json_add_boolean "api_key_configured" "$([ -n "$uci_api_key" ] && [ "$uci_api_key" != "API_KEY" ] && echo 1 || echo 0)"
# Check chains are hooked (input/forward)
local input_hooked=0
local forward_hooked=0
if [ "$ipv4_exists" = "1" ]; then
nft list table ip crowdsec 2>/dev/null | grep -q "hook input" && input_hooked=1
nft list table ip crowdsec 2>/dev/null | grep -q "hook forward" && forward_hooked=1
fi
json_add_boolean "input_chain_hooked" "$input_hooked"
json_add_boolean "forward_chain_hooked" "$forward_hooked"
# Check if sets have timeout flag (required for auto-expiry)
local sets_have_timeout=0
if [ "$ipv4_exists" = "1" ]; then
nft list set ip crowdsec crowdsec-blacklists 2>/dev/null | grep -q "flags timeout" && sets_have_timeout=1
fi
json_add_boolean "sets_have_timeout" "$sets_have_timeout"
# Check decisions sync (compare cscli decisions count vs nftables)
local cscli_decisions=0
local nft_elements=0
local sync_ok=0
if command -v cscli >/dev/null 2>&1; then
cscli_decisions=$(cscli decisions list -o json 2>/dev/null | jsonfilter -e '@[*]' 2>/dev/null | wc -l || echo "0")
fi
nft_elements=$((ipv4_capi + ipv4_cscli + ipv4_other + ipv6_capi + ipv6_cscli))
# Sync is OK if nft has at least some elements when decisions exist
[ "$cscli_decisions" -gt 0 ] && [ "$nft_elements" -gt 0 ] && sync_ok=1
[ "$cscli_decisions" -eq 0 ] && [ "$nft_elements" -eq 0 ] && sync_ok=1
json_add_int "cscli_decisions_count" "$cscli_decisions"
json_add_int "nft_elements_count" "$nft_elements"
json_add_boolean "decisions_synced" "$sync_ok"
# Overall health status
local health_status="ok"
local health_issues=""
if [ "$bouncer_running" != "1" ]; then
health_status="error"
health_issues="Bouncer not running; "
fi
if [ "$uci_enabled" != "1" ]; then
health_status="warning"
health_issues="${health_issues}Bouncer not enabled in UCI; "
fi
if [ "$ipv4_exists" != "1" ]; then
health_status="error"
health_issues="${health_issues}IPv4 table missing; "
fi
if [ "$input_hooked" != "1" ] && [ "$forward_hooked" != "1" ]; then
health_status="error"
health_issues="${health_issues}No chains hooked; "
fi
if [ "$sync_ok" != "1" ]; then
health_status="warning"
health_issues="${health_issues}Decisions not synced to firewall; "
fi
json_add_string "status" "$health_status"
json_add_string "issues" "$health_issues"
json_close_object
json_dump json_dump
} }

View File

@ -11,7 +11,7 @@ PKG_VERSION:=1.0.0
PKG_RELEASE:=1 PKG_RELEASE:=1
LUCI_TITLE:=LuCI SecuBox CrowdSec Dashboard LUCI_TITLE:=LuCI SecuBox CrowdSec Dashboard
LUCI_DEPENDS:=+luci-base +crowdsec +crowdsec-firewall-bouncer LUCI_DEPENDS:=+luci-base +crowdsec +secubox-app-cs-firewall-bouncer
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
PKG_MAINTAINER:=Gerald Kerma <gandalf@gk2.net> PKG_MAINTAINER:=Gerald Kerma <gandalf@gk2.net>

View File

@ -3,7 +3,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-auth-logger PKG_NAME:=secubox-app-auth-logger
PKG_VERSION:=1.2.2 PKG_VERSION:=1.2.2
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_ARCH:=all PKG_ARCH:=all
@ -12,15 +12,16 @@ PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
define Package/secubox-auth-logger define Package/secubox-app-auth-logger
SECTION:=secubox SECTION:=secubox
CATEGORY:=SecuBox CATEGORY:=SecuBox
TITLE:=Authentication Failure Logger for CrowdSec TITLE:=Authentication Failure Logger for CrowdSec
DEPENDS:=+rpcd +uhttpd +libubox-lua DEPENDS:=+rpcd +uhttpd +libubox-lua
PKGARCH:=all PKGARCH:=all
PROVIDES:=secubox-auth-logger
endef endef
define Package/secubox-auth-logger/description define Package/secubox-app-auth-logger/description
Logs authentication failures from LuCI/rpcd and Dropbear SSH Logs authentication failures from LuCI/rpcd and Dropbear SSH
for CrowdSec detection. Includes: for CrowdSec detection. Includes:
- SSH failure monitoring (OpenSSH/Dropbear) - SSH failure monitoring (OpenSSH/Dropbear)
@ -32,14 +33,14 @@ endef
define Build/Compile define Build/Compile
endef endef
define Package/secubox-auth-logger/install define Package/secubox-app-auth-logger/install
# Auth monitor script # Auth monitor script
$(INSTALL_DIR) $(1)/usr/lib/secubox $(INSTALL_DIR) $(1)/usr/lib/secubox
$(INSTALL_BIN) ./files/auth-monitor.sh $(1)/usr/lib/secubox/ $(INSTALL_BIN) ./files/auth-monitor.sh $(1)/usr/lib/secubox/
# Init script # Init script
$(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/secubox-auth-logger.init $(1)/etc/init.d/secubox-auth-logger $(INSTALL_BIN) ./files/secubox-app-auth-logger.init $(1)/etc/init.d/secubox-app-auth-logger
# RPCD plugin for auth logging via ubus # RPCD plugin for auth logging via ubus
$(INSTALL_DIR) $(1)/usr/libexec/rpcd $(INSTALL_DIR) $(1)/usr/libexec/rpcd
@ -61,10 +62,6 @@ define Package/secubox-auth-logger/install
$(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s01-parse $(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s01-parse
$(INSTALL_DATA) ./files/openwrt-luci-auth.yaml $(1)/etc/crowdsec/parsers/s01-parse/ $(INSTALL_DATA) ./files/openwrt-luci-auth.yaml $(1)/etc/crowdsec/parsers/s01-parse/
# CrowdSec whitelist for private IPs (RFC1918)
$(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s02-enrich
$(INSTALL_DATA) ./files/secubox-private-ip-whitelist.yaml $(1)/etc/crowdsec/parsers/s02-enrich/
# CrowdSec scenario # CrowdSec scenario
$(INSTALL_DIR) $(1)/etc/crowdsec/scenarios $(INSTALL_DIR) $(1)/etc/crowdsec/scenarios
$(INSTALL_DATA) ./files/openwrt-luci-bf.yaml $(1)/etc/crowdsec/scenarios/ $(INSTALL_DATA) ./files/openwrt-luci-bf.yaml $(1)/etc/crowdsec/scenarios/
@ -75,28 +72,28 @@ define Package/secubox-auth-logger/install
# UCI defaults for first boot setup # UCI defaults for first boot setup
$(INSTALL_DIR) $(1)/etc/uci-defaults $(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/99-secubox-auth-logger $(1)/etc/uci-defaults/ $(INSTALL_BIN) ./files/99-secubox-app-auth-logger $(1)/etc/uci-defaults/
endef endef
define Package/secubox-auth-logger/postinst define Package/secubox-app-auth-logger/postinst
#!/bin/sh #!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || { [ -n "$${IPKG_INSTROOT}" ] || {
# Restart rpcd to load new plugin # Restart rpcd to load new plugin
/etc/init.d/rpcd restart 2>/dev/null /etc/init.d/rpcd restart 2>/dev/null
# Enable and start auth monitor # Enable and start auth monitor
/etc/init.d/secubox-auth-logger enable /etc/init.d/secubox-app-auth-logger enable
/etc/init.d/secubox-auth-logger start /etc/init.d/secubox-app-auth-logger start
# Run uci-defaults to inject JS hook # Run uci-defaults to inject JS hook
/etc/uci-defaults/99-secubox-auth-logger 2>/dev/null || true /etc/uci-defaults/99-secubox-app-auth-logger 2>/dev/null || true
echo "SecuBox Auth Logger installed - LuCI login failures now logged for CrowdSec" echo "SecuBox Auth Logger installed - LuCI login failures now logged for CrowdSec"
} }
exit 0 exit 0
endef endef
define Package/secubox-auth-logger/postrm define Package/secubox-app-auth-logger/postrm
#!/bin/sh #!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || { [ -n "$${IPKG_INSTROOT}" ] || {
# Restore dispatcher from backup # Restore dispatcher from backup
@ -127,4 +124,4 @@ define Package/secubox-auth-logger/postrm
exit 0 exit 0
endef endef
$(eval $(call BuildPackage,secubox-auth-logger)) $(eval $(call BuildPackage,secubox-app-auth-logger))

View File

@ -15,7 +15,7 @@ define Package/secubox-app-crowdsec-bouncer
PKGARCH:=all PKGARCH:=all
SUBMENU:=SecuBox Apps SUBMENU:=SecuBox Apps
TITLE:=SecuBox CrowdSec Firewall Bouncer wrapper TITLE:=SecuBox CrowdSec Firewall Bouncer wrapper
DEPENDS:=+uci +libuci +crowdsec-firewall-bouncer +crowdsec +nftables DEPENDS:=+uci +libuci +secubox-app-cs-firewall-bouncer +crowdsec +nftables
endef endef
define Package/secubox-app-crowdsec-bouncer/description define Package/secubox-app-crowdsec-bouncer/description

View File

@ -3,18 +3,20 @@
# Copyright (C) 2021-2022 Gerald Kerma <gandalf@gk2.net> # Copyright (C) 2021-2022 Gerald Kerma <gandalf@gk2.net>
# Copyright (C) 2024-2025 CyberMind.fr (SecuBox adaptation) # Copyright (C) 2024-2025 CyberMind.fr (SecuBox adaptation)
# #
# CrowdSec Firewall Bouncer - nftables integration # SecuBox CrowdSec Firewall Bouncer - nftables integration
# #
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=crowdsec-firewall-bouncer PKG_NAME:=secubox-app-cs-firewall-bouncer
PKG_VERSION:=0.0.34 PKG_VERSION:=0.0.31
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz # Source from upstream CrowdSec
# Note: v0.0.31 is the last version compatible with Go 1.23 (OpenWrt 24.10 SDK)
PKG_SOURCE:=crowdsec-firewall-bouncer-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/crowdsecurity/cs-firewall-bouncer/tar.gz/v$(PKG_VERSION)? PKG_SOURCE_URL:=https://codeload.github.com/crowdsecurity/cs-firewall-bouncer/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=5c58f5cb9a8afc94520f62a39be290e8eea4c1a5bbacc5fea78ccfad9c8da232 PKG_HASH:=c34963f0680ae296ae974d8f6444a2d1e2dd7617e7b05d4ad85c320529eec5f5
PKG_BUILD_DIR:=$(BUILD_DIR)/cs-firewall-bouncer-$(PKG_VERSION) PKG_BUILD_DIR:=$(BUILD_DIR)/cs-firewall-bouncer-$(PKG_VERSION)
@ -30,27 +32,30 @@ GO_PKG:=github.com/crowdsecurity/cs-firewall-bouncer
# Build version information # Build version information
GO_PKG_LDFLAGS_X:= \ GO_PKG_LDFLAGS_X:= \
github.com/crowdsecurity/go-cs-lib/version.Tag=v$(PKG_VERSION)-openwrt \ github.com/crowdsecurity/go-cs-lib/version.Tag=v$(PKG_VERSION)-secubox \
github.com/crowdsecurity/go-cs-lib/version.Timestamp=$(SOURCE_DATE_EPOCH) \ github.com/crowdsecurity/go-cs-lib/version.Timestamp=$(SOURCE_DATE_EPOCH) \
github.com/crowdsecurity/go-cs-lib/version.GoVersion=$(shell $(GO_STAGING_DIR)/bin/go version | cut -d" " -f3) github.com/crowdsecurity/go-cs-lib/version.GoVersion=$(shell $(GO_STAGING_DIR)/bin/go version | cut -d" " -f3)
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
define Package/crowdsec-firewall-bouncer/Default define Package/secubox-app-cs-firewall-bouncer/Default
SECTION:=net SECTION:=net
CATEGORY:=Network CATEGORY:=Network
TITLE:=CrowdSec Firewall Bouncer SUBMENU:=SecuBox
TITLE:=SecuBox CrowdSec Firewall Bouncer
URL:=https://github.com/crowdsecurity/cs-firewall-bouncer URL:=https://github.com/crowdsecurity/cs-firewall-bouncer
endef endef
define Package/crowdsec-firewall-bouncer define Package/secubox-app-cs-firewall-bouncer
$(call Package/crowdsec-firewall-bouncer/Default) $(call Package/secubox-app-cs-firewall-bouncer/Default)
DEPENDS:=$(GO_ARCH_DEPENDS) +nftables DEPENDS:=$(GO_ARCH_DEPENDS) +nftables
PROVIDES:=crowdsec-firewall-bouncer
CONFLICTS:=crowdsec-firewall-bouncer
endef endef
define Package/crowdsec-firewall-bouncer/description define Package/secubox-app-cs-firewall-bouncer/description
CrowdSec Firewall Bouncer for OpenWrt/SecuBox. SecuBox CrowdSec Firewall Bouncer for OpenWrt.
Fetches decisions from CrowdSec Local API and enforces them Fetches decisions from CrowdSec Local API and enforces them
using nftables. Supports both IPv4 and IPv6 blocking with using nftables. Supports both IPv4 and IPv6 blocking with
@ -61,15 +66,15 @@ define Package/crowdsec-firewall-bouncer/description
- IPv4 and IPv6 support - IPv4 and IPv6 support
- Input and forward chain filtering - Input and forward chain filtering
- Interface-based filtering - Interface-based filtering
- Automatic cleanup on stop - Automatic restart on firewall reload
- procd service management - procd service management
endef endef
define Package/crowdsec-firewall-bouncer/conffiles define Package/secubox-app-cs-firewall-bouncer/conffiles
/etc/config/crowdsec /etc/config/crowdsec
endef endef
define Package/crowdsec-firewall-bouncer/install define Package/secubox-app-cs-firewall-bouncer/install
$(call GoPackage/Package/Install/Bin,$(1)) $(call GoPackage/Package/Install/Bin,$(1))
$(INSTALL_DIR) $(1)/etc/config $(INSTALL_DIR) $(1)/etc/config
@ -77,7 +82,11 @@ define Package/crowdsec-firewall-bouncer/install
$(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/crowdsec-firewall-bouncer.initd $(1)/etc/init.d/crowdsec-firewall-bouncer $(INSTALL_BIN) ./files/crowdsec-firewall-bouncer.initd $(1)/etc/init.d/crowdsec-firewall-bouncer
# Hotplug script to restart bouncer when firewall reloads
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_DATA) ./files/hotplug.d/99-crowdsec-bouncer $(1)/etc/hotplug.d/iface/99-crowdsec-bouncer
endef endef
$(eval $(call GoBinPackage,crowdsec-firewall-bouncer)) $(eval $(call GoBinPackage,secubox-app-cs-firewall-bouncer))
$(eval $(call BuildPackage,crowdsec-firewall-bouncer)) $(eval $(call BuildPackage,secubox-app-cs-firewall-bouncer))

View File

@ -7,6 +7,7 @@
USE_PROCD=1 USE_PROCD=1
START=99 START=99
STOP=10
NAME=crowdsec-firewall-bouncer NAME=crowdsec-firewall-bouncer
PROG=/usr/bin/cs-firewall-bouncer PROG=/usr/bin/cs-firewall-bouncer
@ -21,6 +22,8 @@ TABLE6="crowdsec6"
service_triggers() { service_triggers() {
procd_add_reload_trigger crowdsec-firewall-bouncer procd_add_reload_trigger crowdsec-firewall-bouncer
procd_add_config_trigger "config.change" "crowdsec" /etc/init.d/crowdsec-firewall-bouncer reload procd_add_config_trigger "config.change" "crowdsec" /etc/init.d/crowdsec-firewall-bouncer reload
# Restart bouncer when firewall reloads to re-apply nftables rules
procd_add_reload_trigger firewall
} }
init_yaml() { init_yaml() {
@ -235,19 +238,37 @@ run_bouncer() {
procd_set_param stderr 1 procd_set_param stderr 1
procd_set_param nice 10 procd_set_param nice 10
# Use ujail if available for security isolation # Note: ujail disabled - bouncer needs direct nftables access
if [ -x "/sbin/ujail" ]; then # to add/remove IPs from sets which requires CAP_NET_ADMIN
procd_add_jail cs-bouncer log # if [ -x "/sbin/ujail" ]; then
procd_add_jail_mount $VARCONFIG # procd_add_jail cs-bouncer log
procd_add_jail_mount_rw /var/log/ # procd_add_jail_mount $VARCONFIG
procd_set_param no_new_privs 1 # procd_add_jail_mount_rw /var/log/
fi # procd_set_param no_new_privs 1
# fi
procd_close_instance procd_close_instance
fi fi
} }
wait_for_firewall() {
# Wait for fw4/nftables to be ready (max 30 seconds)
local i=0
while [ $i -lt 30 ]; do
if nft list tables >/dev/null 2>&1; then
return 0
fi
sleep 1
i=$((i + 1))
done
logger -t crowdsec-bouncer "Warning: nftables not ready after 30s, starting anyway"
return 1
}
start_service() { start_service() {
# Wait for firewall/nftables to be ready
wait_for_firewall
config_load "${CONFIGURATION}" config_load "${CONFIGURATION}"
config_foreach run_bouncer bouncer config_foreach run_bouncer bouncer
} }

View File

@ -0,0 +1,31 @@
#!/bin/sh
# CrowdSec Firewall Bouncer - Interface/Firewall hotplug handler
# Ensures bouncer's nftables rules are applied after network/firewall changes
# Only act on interface up events for WAN
[ "$ACTION" = "ifup" ] || exit 0
[ "$INTERFACE" = "wan" ] || [ "$INTERFACE" = "wan6" ] || exit 0
# Check if bouncer is enabled
. /lib/functions.sh
config_load crowdsec
is_enabled() {
local section="$1"
local enabled
config_get_bool enabled "$section" enabled 0
[ "$enabled" -eq 1 ] && return 0
return 1
}
bouncer_enabled=0
config_foreach is_enabled bouncer && bouncer_enabled=1
[ "$bouncer_enabled" -eq 1 ] || exit 0
# Check if crowdsec tables exist - if not, bouncer needs restart
if ! nft list table ip crowdsec >/dev/null 2>&1; then
logger -t crowdsec-bouncer "WAN up but crowdsec nftables missing, restarting bouncer"
sleep 2
/etc/init.d/crowdsec-firewall-bouncer restart
fi

View File

@ -1,17 +0,0 @@
# CrowdSec Whitelist for Private IP Ranges
# Prevents blocking of internal network addresses (RFC1918)
# These IPs should never be banned as they are local network devices
name: secubox/private-ip-whitelist
description: "Whitelist private/internal IP ranges to prevent self-blocking"
whitelist:
reason: "Private IP addresses (RFC1918) - local network devices"
ip:
- "127.0.0.0/8" # Localhost
- "10.0.0.0/8" # Class A private
- "172.16.0.0/12" # Class B private
- "192.168.0.0/16" # Class C private
- "169.254.0.0/16" # Link-local
- "::1/128" # IPv6 localhost
- "fe80::/10" # IPv6 link-local
- "fc00::/7" # IPv6 unique local

View File

@ -1,53 +0,0 @@
# SPDX-License-Identifier: MIT
#
# SecuBox CrowdSec Setup Package
# Copyright (C) 2025 CyberMind.fr - Gandalf <gandalf@gk2.net>
#
include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-crowdsec-setup
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_MAINTAINER:=Gerald Kerma <gandalf@gk2.net>
PKG_LICENSE:=MIT
include $(INCLUDE_DIR)/package.mk
define Package/secubox-crowdsec-setup
SECTION:=secubox
CATEGORY:=SecuBox
SUBMENU:=Security
TITLE:=SecuBox CrowdSec Setup Utility
DEPENDS:=+crowdsec +crowdsec-firewall-bouncer +syslog-ng
PKGARCH:=all
endef
define Package/secubox-crowdsec-setup/description
Script d'installation automatisee de CrowdSec pour SecuBox.
Configure syslog-ng pour le forwarding des logs vers CrowdSec,
installe les collections de securite, et configure le bouncer
nftables pour fw4.
endef
define Build/Compile
endef
define Package/secubox-crowdsec-setup/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) ./files/usr/sbin/secubox-crowdsec-setup $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/etc/secubox/backups/crowdsec
endef
define Package/secubox-crowdsec-setup/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
echo "SecuBox CrowdSec Setup installe."
echo "Executez 'secubox-crowdsec-setup' pour configurer CrowdSec."
}
exit 0
endef
$(eval $(call BuildPackage,secubox-crowdsec-setup))