Summary
If crowdsec-firewall-bouncer uses mode=nftables and set-only=true, metrics collection floods crowdsec-firewall-bouncer.log with lines like this every 10 seconds:
$ tail /var/log/crowdsec-firewall-bouncer.log
time="28-05-2023 13:36:43" level=error msg="can't collect dropped packets for ipv4 from nft: while running /usr/sbin/nft -j list chain ip filter crowdsec-chain-input: exit status 1"
time="28-05-2023 13:36:53" level=error msg="can't collect dropped packets for ipv4 from nft: while running /usr/sbin/nft -j list chain ip filter crowdsec-chain-input: exit status 1"
time="28-05-2023 13:37:03" level=error msg="can't collect dropped packets for ipv4 from nft: while running /usr/sbin/nft -j list chain ip filter crowdsec-chain-input: exit status 1"
time="28-05-2023 13:37:13" level=error msg="can't collect dropped packets for ipv4 from nft: while running /usr/sbin/nft -j list chain ip filter crowdsec-chain-input: exit status 1"
time="28-05-2023 13:37:23" level=error msg="can't collect dropped packets for ipv4 from nft: while running /usr/sbin/nft -j list chain ip filter crowdsec-chain-input: exit status 1"
set-only mode is intended for more complex firewall setups (e.g. in routers) where Crowdsec's the automated firewall rules cannot be used (e.g. there are multiple interfaces and crowdsec should control only some of those).
Root cause
This bug was probably introduced in #231 since the PR seemed to consider only "auto-mode" (set-only=false).
nftables.metrics.CollectMetrics() (line 118) does not handle set-only mode since it assumes there is a nftables chain with name chain-hook (where hook is prerouting, input, output, forward or ingress) to query from. In set-only mode crowdsec manages only blocked IPs in a named nftables set and the chain param is not used.
Workaround
It is not possible to disable metrics collection. Therefore, as a workaround an admin has to create/rename a chain according to an undocumented naming convention $nftables.ipv4.chain-$nftables_hooks.hook (referring to bouncer config file yaml fields here).
For example, if nftables config in bouncer config looks like this:
# /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
...
nftables:
ipv4:
enabled: true
set-only: true
table: filter
chain: existing-chain-without-its-input-postfix
nftables_hooks:
- input
Then there needs to be a nftables chain in the right table with name : existing-chain-without-its-input-postfix-input.
Solution options
I could come up with couple of options how to solve this issue.
- Add
disable_metrics option
- Disable metrics collection in
set-only mode automatically
- Add support for metrics collection in
set-only mode
Technical considerations
1. Add disable_metrics bouncer config option
This would require admin to manually fix the issue.
Commit 9619b01 introduced this functionality, but in the same PR #282 the commit was later reversed (d17dafa). Maybe @mmetc knows why the change was reversed.
2. Disable metrics collection in set-only mode
This can be done by editing one line in collectDropped() in nftables/metrics.go.
func (c *nftContext) collectDropped(path string, hooks []string) (int, int, int) {
if c.conn == nil || c.setOnly { // "|| c.setOnly" added
return 0, 0, 0
}
...
3. Add support for metrics collection in set-only mode
This should not be a big change.
- Modify
collectDroppedPackets() in metrics.go to take chain name directly instead of doing string concatenation magic within the function.
- Modify
collectDropped() in metrics.go to handle set-only=true mode:
set-only=false: create chain name here with the string concatenation magic
set-only=true: use chain name directly from bouncer config
Drawback
A drawback of this implementation is that it would collect metrics only from one chain.
Collecting metrics from all chains / hooks in set-only mode would require a way to tell the bouncer what chains are being used. If nftables_hooks config option could be changed to contain actual chain names and the string concatenation could be scrapped, then the nftables_hooks config option could be used also in set-only mode to configure metrics collection right.
Disclaimer: I am the author of set-only mode
Summary
If
crowdsec-firewall-bouncerusesmode=nftablesandset-only=true, metrics collection floodscrowdsec-firewall-bouncer.logwith lines like this every 10 seconds:set-onlymode is intended for more complex firewall setups (e.g. in routers) where Crowdsec's the automated firewall rules cannot be used (e.g. there are multiple interfaces andcrowdsecshould control only some of those).Root cause
This bug was probably introduced in #231 since the PR seemed to consider only "auto-mode" (
set-only=false).nftables.metrics.CollectMetrics()(line 118) does not handleset-onlymode since it assumes there is anftableschain with namechain-hook(wherehookisprerouting,input,output,forwardoringress) to query from. Inset-onlymodecrowdsecmanages only blocked IPs in a namednftablessetand thechainparam is not used.Workaround
It is not possible to disable metrics collection. Therefore, as a workaround an admin has to create/rename a chain according to an undocumented naming convention
$nftables.ipv4.chain-$nftables_hooks.hook(referring to bouncer config file yaml fields here).For example, if
nftablesconfig in bouncer config looks like this:Then there needs to be a
nftableschain in the right table with name :existing-chain-without-its-input-postfix-input.Solution options
I could come up with couple of options how to solve this issue.
disable_metricsoptionset-onlymode automaticallyset-onlymodeTechnical considerations
1. Add
disable_metricsbouncer config optionThis would require admin to manually fix the issue.
Commit 9619b01 introduced this functionality, but in the same PR #282 the commit was later reversed (d17dafa). Maybe @mmetc knows why the change was reversed.
2. Disable metrics collection in
set-onlymodeThis can be done by editing one line in
collectDropped()innftables/metrics.go.3. Add support for metrics collection in
set-onlymodeThis should not be a big change.
collectDroppedPackets()inmetrics.goto take chain name directly instead of doing string concatenation magic within the function.collectDropped()inmetrics.goto handleset-only=truemode:set-only=false: create chain name here with the string concatenation magicset-only=true: use chain name directly from bouncer configDrawback
A drawback of this implementation is that it would collect metrics only from one chain.
Collecting metrics from all chains / hooks in
set-onlymode would require a way to tell the bouncer what chains are being used. Ifnftables_hooksconfig option could be changed to contain actual chain names and the string concatenation could be scrapped, then thenftables_hooksconfig option could be used also inset-onlymode to configure metrics collection right.Disclaimer: I am the author of
set-onlymode