host_firewall: FireHOL level1 as its own set firehol_v4 next to Spamhaus, daily updater and firewall.firehol opt-out

This commit is contained in:
2026-10-24 17:31:45 +00:00
parent 312be161b9
commit c55a96c0ea
6 changed files with 238 additions and 5 deletions
+33 -3
View File
@@ -20,6 +20,7 @@ set {{ name }} {
{% set masquerade = firewall.masquerade | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %}
{% set scrapers = firewall.scrapers | default({}, true) %}
{% set forward_guard = firewall.forward_guard | default({}, true) | dict2items | rejectattr('value', 'none') | list %}
{% set blocklists = firewall.spamhaus or firewall.firehol %}
# Declare-then-delete makes every load one atomic transaction that replaces
# only these tables; Cilium, Docker, NetBird and CrowdSec tables stay untouched.
@@ -34,6 +35,9 @@ include "/etc/nftables.d/host-geo.nft"
{% if firewall.spamhaus %}
include "/etc/nftables.d/host-spamhaus.nft"
{% endif %}
{% if firewall.firehol %}
include "/etc/nftables.d/host-firehol.nft"
{% endif %}
table inet host {
{{ addr_set('admin_v4', 'ipv4_addr', firewall.admin.v4) }}
@@ -51,12 +55,17 @@ table inet host {
chain input {
type filter hook input priority filter; policy drop;
{% if firewall.spamhaus %}
{% if blocklists %}
# Before the established rule: outbound is blocked too, so listed
# addresses have no legitimate replies.
{% if firewall.spamhaus %}
ip saddr @spamhaus_v4 jump spamhaus_in
ip6 saddr @spamhaus_v6 jump spamhaus_in
{% endif %}
{% if firewall.firehol %}
ip saddr @firehol_v4 jump firehol_in
{% endif %}
{% endif %}
ct state established,related accept
@@ -122,7 +131,19 @@ table inet host {
reject
}
{% endif %}
{% if firewall.block_smtp_out or firewall.spamhaus %}
{% if firewall.firehol %}
chain firehol_in {
limit rate {{ firewall.log.spamhaus_rate }} log prefix "fw-firehol-in: "
drop
}
chain firehol_out {
limit rate {{ firewall.log.spamhaus_rate }} log prefix "fw-firehol-out: "
reject
}
{% endif %}
{% if firewall.block_smtp_out or blocklists %}
# Outbound mail goes through the mail host only. Loopback stays open for a
# local MTA; the log lines carry OUT=, which CrowdSec does not count as a scan.
@@ -133,6 +154,10 @@ table inet host {
ip daddr @spamhaus_v4 jump spamhaus_out
ip6 daddr @spamhaus_v6 jump spamhaus_out
{% endif %}
{% if firewall.firehol %}
ip daddr @firehol_v4 jump firehol_out
{% endif %}
{% if firewall.block_smtp_out %}
oifname != "lo" tcp dport 25 limit rate {{ firewall.log.out_rate }} log prefix "fw-out-reject: "
@@ -195,7 +220,7 @@ table inet host {
ip6 saddr @geo_v6 accept
{% endif %}
}
{% if forward_guard or firewall.spamhaus %}
{% if forward_guard or blocklists %}
chain forward {
type filter hook forward priority filter; policy accept;
@@ -206,6 +231,11 @@ table inet host {
ip daddr @spamhaus_v4 jump spamhaus_out
ip6 daddr @spamhaus_v6 jump spamhaus_out
{% endif %}
{% if firewall.firehol %}
ip saddr @firehol_v4 jump firehol_in
ip daddr @firehol_v4 jump firehol_out
{% endif %}
{% for guard in forward_guard %}
# {{ guard.key }}