Merge pull request #6 from gkerma/release/v0.15.0

Release/v0.15.0
This commit is contained in:
CyberMind 2026-01-15 15:41:45 +01:00 committed by GitHub
commit 76b3ff4f93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 391 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))

View File

@ -2060,6 +2060,136 @@ run_firmware_build() {
return 0 return 0
} }
# Build native packages using full OpenWrt toolchain (without firmware)
run_toolchain_build() {
local device="${1:-espressobin-v7}"
local packages=("${@:2}")
print_header "Building Native Packages (Toolchain)"
# Parse device profile for architecture
parse_device_profile "$device" || return 1
# Check dependencies
check_dependencies
# Setup OpenWrt environment
download_openwrt_source || return 1
setup_openwrt_feeds || return 1
copy_secubox_to_openwrt || return 1
# Generate minimal config for package building
print_header "Generating Package Build Configuration"
cd "$OPENWRT_DIR"
# Start with minimal config
cat > .config << EOF
# Target configuration for $FW_TARGET/$FW_SUBTARGET
CONFIG_TARGET_${FW_TARGET}=y
CONFIG_TARGET_${FW_TARGET}_${FW_SUBTARGET}=y
CONFIG_TARGET_MULTI_PROFILE=y
CONFIG_TARGET_ALL_PROFILES=y
# Build packages only (no firmware)
CONFIG_ALL_NONSHARED=n
CONFIG_ALL_KMODS=n
CONFIG_ALL=n
# Enable SecuBox native packages
CONFIG_PACKAGE_secubox-app-cs-firewall-bouncer=m
CONFIG_PACKAGE_secubox-app-crowdsec=m
CONFIG_PACKAGE_secubox-app-ndpid=m
CONFIG_PACKAGE_secubox-app-netifyd=m
CONFIG_PACKAGE_secubox-app-nodogsplash=m
# Required dependencies
CONFIG_PACKAGE_nftables=y
CONFIG_PACKAGE_golang=y
# Disable GDB to speed up build
CONFIG_GDB=n
EOF
# Expand config
make defconfig
# Download sources
print_info "Downloading package sources..."
make download -j$(nproc) V=s 2>&1 | grep -v "^make\[" || true
# Build prerequisite targets first
# This builds tools, toolchain, and target preparation in one step
print_header "Building Prerequisites (Tools + Toolchain)"
print_info "This may take 1-2 hours on first run..."
# Build tools, toolchain, and target preparation (needed for packages)
if ! make tools/install toolchain/install target/compile V=s -j$(nproc) 2>&1 | tee build-prereqs.log; then
print_warning "Prerequisites build had issues, continuing..."
fi
print_success "Prerequisites built"
# Build Go compiler for host (needed for Go packages)
print_header "Building Go Compiler (for Go packages)"
if ! make package/feeds/packages/lang/golang/host/compile V=s -j$(nproc) 2>&1 | tee build-golang.log; then
print_warning "Go compiler build had issues, some packages may fail"
fi
print_success "Go compiler ready"
# Build specific packages or all native SecuBox packages
print_header "Compiling Native Packages"
local native_packages=(
"secubox-app-cs-firewall-bouncer"
"secubox-app-crowdsec"
"secubox-app-ndpid"
"secubox-app-netifyd"
"secubox-app-nodogsplash"
)
if [[ ${#packages[@]} -gt 0 ]]; then
native_packages=("${packages[@]}")
fi
local built=()
local failed=()
for pkg in "${native_packages[@]}"; do
print_info "Building: $pkg"
if make package/$pkg/compile V=s -j$(nproc) 2>&1 | tee -a build-$pkg.log; then
built+=("$pkg")
print_success "Built: $pkg"
else
failed+=("$pkg")
print_error "Failed: $pkg"
fi
done
# Collect built packages
print_header "Collecting Built Packages"
local output_dir="$BUILD_DIR/toolchain-$ARCH"
mkdir -p "$output_dir"
# Find and copy IPK packages
find "$OPENWRT_DIR/bin/packages" -name "*.ipk" -exec cp {} "$output_dir/" \; 2>/dev/null || true
find "$OPENWRT_DIR/bin/targets" -name "*.ipk" -exec cp {} "$output_dir/" \; 2>/dev/null || true
local pkg_count=$(find "$output_dir" -name "*.ipk" 2>/dev/null | wc -l)
cd - > /dev/null
# Summary
print_header "Toolchain Build Summary"
print_success "Built: ${#built[@]} packages: ${built[*]}"
if [[ ${#failed[@]} -gt 0 ]]; then
print_error "Failed: ${#failed[@]} packages: ${failed[*]}"
fi
print_success "Total IPK packages: $pkg_count"
print_success "Location: $output_dir/"
return 0
}
# Show usage # Show usage
show_usage() { show_usage() {
cat << EOF cat << EOF
@ -2074,6 +2204,7 @@ COMMANDS:
build Build all packages for x86_64 build Build all packages for x86_64
build <package> Build single package build <package> Build single package
build --arch <arch> Build for specific architecture build --arch <arch> Build for specific architecture
build-toolchain <device> Build native packages (Go/C++) using full toolchain
build-firmware <device> Build full firmware image for device build-firmware <device> Build full firmware image for device
debug-firmware <device> Debug firmware build (check config without building) debug-firmware <device> Debug firmware build (check config without building)
full Run validation then build full Run validation then build
@ -2221,6 +2352,12 @@ main() {
run_firmware_build "$device" run_firmware_build "$device"
;; ;;
build-toolchain)
local device="${1:-espressobin-v7}"
shift || true
run_toolchain_build "$device" "$@"
;;
debug-firmware) debug-firmware)
local device="$1" local device="$1"
if [[ -z "$device" ]]; then if [[ -z "$device" ]]; then