cs-firewall-bouncer icon indicating copy to clipboard operation
cs-firewall-bouncer copied to clipboard

Enhance rules created by the bouncer to respect conntrack

Open ne20002 opened this issue 5 months ago • 3 comments

/kind enhancement

What would you like to be added?

First of all: I like the ability to collect metrics of the bouncer.

For OpenWrt the rules as created by the bouncer in version 0.0.30 are not ideal. Most OpenWrt devices have limited power and based on the use case, that OpwnWrt (in this case) is a routing device, additional definitions for the created rules are neccessary. Until version 0.0.30 the OpenWrt bouncer package created the rules by itself running the bouncer in set-only mode. With the new approach this is still working (thank you) but lacks the features for the metrics.

I will only use ipv4 here but it's the same for ipv6. Now look at this:


root@BPI-R3-eth1:~# nft list table crowdsec
table ip crowdsec {
	set crowdsec-blacklists-CAPI {
		type ipv4_addr
		flags timeout
		elements = { 1.9.78.242 timeout 4d1h45m14s expires 4d1h36m44s280ms, 1.9.101.202 timeout 4d12h45m14s expires 4d12h36m44s340ms,
                 ...

			     223.247.218.77 timeout 2d6h45m13s expires 2d6h36m43s220ms, 223.247.218.112 timeout 5d20h45m13s expires 5d20h36m42s870ms }
	}

	set crowdsec-blacklists-lists-tor-exit-nodes {
		type ipv4_addr
		flags timeout
		elements = { 2.58.95.56 timeout 10h45m17s expires 10h36m46s560ms, 3.108.196.136 timeout 22h45m17s expires 22h36m46s560ms,
                 ...
			     217.170.201.71 timeout 10h45m17s expires 10h36m46s560ms }
	}

	set crowdsec-blacklists-fail2ban {
		type ipv4_addr
		flags timeout
		elements = { 4.246.246.232 timeout 3d6h41m31s expires 3d6h33m560ms, 13.91.180.110 timeout 10d10h16m28s expires 10d10h7m57s560ms,
                 ...
			     216.218.206.66 timeout 3d8h9m36s expires 3d8h1m5s560ms }
	}

	set crowdsec-blacklists-crowdsec {
		type ipv4_addr
		flags timeout
		elements = { 20.191.45.212 timeout 3h12m32s expires 3h4m1s560ms, 45.200.148.16 timeout 1h31m28s expires 1h22m57s560ms,
			     60.13.6.178 timeout 1h19m31s expires 1h11m560ms }
	}

	chain crowdsec-chain-input {
		type filter hook input priority filter + 4; policy accept;
		counter packets 61292 bytes 10732148
		ip saddr @crowdsec-blacklists-CAPI counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-lists-tor-exit-nodes counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-fail2ban counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-crowdsec counter packets 0 bytes 0 drop
	}

	chain crowdsec-chain-forward {
		type filter hook forward priority filter + 4; policy accept;
		counter packets 1521 bytes 96619
		ip saddr @crowdsec-blacklists-CAPI counter packets 2 bytes 84 drop
		ip saddr @crowdsec-blacklists-lists-tor-exit-nodes counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-fail2ban counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-crowdsec counter packets 0 bytes 0 drop
	}
}

This set of rules is suboptimal, because:

  • the chains are created in addition to those of the OpenWrt fw4 (which is ggod).
  • In OpenWrt the chains have a higher priority value to ensure the Crowdsec filtering is done after the fw4 rules are applied and thus are only applied on packets that are accepted by fw4 but still the rules are applied on all packets accepted by fw4.
  • OpenWrt (may) use a lot of interfaces and zones. Most of the traffic is internal, e.g. between LAN and DMZ. It does not make sense to do the filtering aka lookup operations on those connections. The current OpenWrt package ensures that only packets incoming on an external interface (WAN) are checked by the bouncer.
  • OpenWrt's fw4 uses conntrack. There is a fastpath for all accepted,related packets. But this fastpath only applies to the fw4 table. In the Crowdsec table's chain any packet (not dropped earlier in fw4) if checked again. Adding the accepted/related fastpath to the chains is a must.

Even though the set lookup is fast, bypassing it if it is not neccessary is even faster.

As an example I suggest to change the rule creation for

	chain crowdsec-chain-input {
		type filter hook input priority filter + 4; policy accept;
		counter packets 61292 bytes 10732148
		ip saddr @crowdsec-blacklists-CAPI counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-lists-tor-exit-nodes counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-fail2ban counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-crowdsec counter packets 0 bytes 0 drop
	}

to this:

	chain crowdsec-chain-input {
		type filter hook input priority filter + 4; policy accept;
                ct state established,related accept comment "Allow inbound established and related flows"
                iifname not in { wan, wg1 } accept comment "Allow all internal flows"
		counter packets 61292 bytes 10732148
		ip saddr @crowdsec-blacklists-CAPI counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-lists-tor-exit-nodes counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-fail2ban counter packets 0 bytes 0 drop
		ip saddr @crowdsec-blacklists-crowdsec counter packets 0 bytes 0 drop
	}

whereas:

  • the line with check for contrack state shall only be added if conntrack is available (I'm sure this can be tested upon creation of the chains and rules)
  • for the line checking the input interface (here: { wan, wg1 }) there should be a configuration option and in case it is not set this line should be omitted.

Why is this needed?

Needed for proper function of OpenWrt devices.

ne20002 avatar Sep 19 '24 18:09 ne20002