EL10: require kernel-modules-extra, fail safe when the state match is unusable, fix csftest probe-rule leak - #13
Conversation
…extra on EL10 EL10-family minimal installs (AlmaLinux/Rocky/RHEL 10+) moved the xt_* netfilter kernel modules to the separate kernel-modules-extra package, which is not installed by default. Without it csf's stateful ruleset cannot be created and enabling the firewall can block all outbound TCP while reporting success. Probe for a working conntrack/state match before dispatching to the panel installers. On EL10-family, attempt to install kernel-modules-extra for the running kernel and abort with clear remediation steps if the match still does not work. On other platforms print a loud warning and continue, preserving existing behaviour.
…lures csftest.pl only deleted its probe rules when a test passed. On iptables-nft an insert can succeed while still printing a warning (for example on EL10 without kernel-modules-extra, where the extension revision probe fails but the rule is translated natively), so a "failed" test could leak its probe rule - e.g. a stray '-A OUTPUT -p tcp --dport 9999 -j ACCEPT' - into the live ruleset. Run the delete unconditionally after every insert attempt. When failures look like missing kernel modules, print an actionable note instead of leaving the user with the cryptic "Extension revision 0 not supported" warnings: on EL10-family systems point directly at 'dnf install kernel-modules-extra-$(uname -r)' + reboot, otherwise a generic missing-xt-modules explanation.
If the kernel cannot use the state/conntrack match (e.g. EL10-family minimal installs without kernel-modules-extra), starting the firewall is destructive in both startup modes: - FASTSTART=1: iptables-nft-restore rejects the atomic batch, csf dies mid-start with the firewall left empty (fails open) - FASTSTART=0: rules apply one-by-one, the ESTABLISHED/RELATED accepts all fail while DROP policies and plain DROP rules succeed, silently blocking all outbound TCP - and csf still exits 0 (fails closed while reporting success) Add a pre-flight check in dostart() that verifies the configured state module actually works before any rules or policies are applied. On failure csf now fails safe through error() - policies reset to ACCEPT, csf.error written, exit 1 - with an actionable message that points at kernel-modules-extra on EL10-family systems. The probe rule is removed even if the insert reports a failure so it can never leak into the ruleset.
|
@zeroth-blip thanks for the PR, there are couple of things that we should address prior to the merge.
|
|
@UptimeEnforcer thanks for the review. Regarding the installer changes, I agree. The Regarding The important point is that resetting to ACCEPT is not new behavior introduced by this PR. It is how CSF currently handles startup errors. The purpose of this check is to detect the problem before CSF starts applying a ruleset that depends on state tracking. Without the check, the same missing-module situation can currently result in one of two outcomes:
With the proposed check, CSF stops before applying any rules, writes So yes, the server would remain on ACCEPT policies, but the failure would be explicit instead of leaving behind either an empty firewall or a partially applied ruleset that appears to have started successfully. If you think CSF should use a fail-closed fallback in this situation, we could consider applying a minimal stateless ruleset that preserves loopback and SSH access. That would be a larger behavioral change from CSF's current error handling, so I think it would be better discussed and implemented separately rather than included implicitly in this fix. I will proceed with moving the installation logic into |
Fixes #12.
Background
On EL10-family systems (AlmaLinux/Rocky/RHEL 10+) the xt_* netfilter kernel modules moved to the separate
kernel-modules-extrapackage, which minimal installs do not include. Verified end-to-end on a fresh AlmaLinux 10.2 minimal + cPanel box: without that package there are two distinct failure modes depending onFASTSTART:FASTSTART = "1"— fails open.iptables-nft-restorerejects the whole atomic batch, csf dies mid-start (-A INVDROPinto a chain that was never created), exit 1, firewall left completely empty with ACCEPT policies. No outage, but zero protection.FASTSTART = "0"— fails closed with exit 0. Rules apply one-by-one: every conntrack ESTABLISHED/RELATED accept fails, while DROP policies, bare DROPs and simple dport rules succeed (~157 partial rules). Result: all outbound TCP dead (replies dropped inbound — no conntrack), while ICMP and DNS to configured resolvers keep working via explicit per-IP bidirectional rules. csf reports success. This is the exact symptom reported in AlmaLinux 10.2: Outbound TCP traffic blocked after enabling CSF (TCP_OUT rules not applied / conntrack rules fail with iptables-nft) #12.Installing
kernel-modules-extrafor the running kernel and rebooting fully resolves it (csftest all-OK, complete ruleset loads, verified by SSH-ing in through the live firewall).What this PR does
1.
install.sh— pre-flight before dispatching to the panel installersProbes for a working
-m conntrack/-m statematch. On EL10-family it attemptsdnf install kernel-modules-extra-$(uname -r)(with an unversioned fallback) and re-probes; if the match still doesn't work it aborts with clear remediation steps instead of completing an install that cannot work. On non-EL10 platforms a failing probe prints a loud warning and the install continues, preserving existing behaviour (also keeps the containerised CI matrix green, where the host kernel provides the modules).2.
csftest.pl— actionable diagnostics + probe-rule leak fixExtension ... not supported) skipped its cleanup and leaked e.g.-A OUTPUT -p tcp --dport 9999 -j ACCEPTinto the live ruleset.dnf install kernel-modules-extra-$(uname -r)+ reboot; elsewhere a generic missing-xt-modules note.3.
csf.pl— never apply a broken ruleset (the real lesson from #12)New
checkstatemodule()pre-flight indostart(), run before any rules or policies are applied: it verifies the configured state module actually works (IPv4, and IPv6 whenIPV6_SPIis enabled), and on failure goes througherror()— policies reset to ACCEPT,/etc/csf/csf.errorwritten, exit 1 — with an actionable message. This turns the silent full outage into a loud refusal on both FASTSTART paths. Skipped whenLF_SPI/IPV6_SPIare disabled (monolithic-kernel VPS setups that legitimately run without the state match). The probe rule is removed even when the insert reports failure, so it cannot leak.Testing
prove -r .github/tests/unit/— 15 files, 83 tests).csftest.plexercised against a shimmed iptables simulating the broken-EL10 output: all 11 probes now get matching deletes (no leak), EL10 note prints onPLATFORM_ID=platform:el10, generic note elsewhere, healthy path unchanged.install.shcheck exercised for all four paths: healthy → silent continue; broken non-EL10 → warn + continue; broken EL10 + remediation fails → abort exit 1; broken EL10 + remediation succeeds → continue.checkstatemodule()exercised in isolation: healthy path passes and cleans up both probes; failure path callserror()with the expected message and still attempts cleanup.