From 6a1e7b77e7ca4e048c71a0150297f78a2163d51e Mon Sep 17 00:00:00 2001 From: Ruakij Date: Thu, 5 Nov 2026 13:25:48 +0000 Subject: [PATCH] host_firewall: ban firehol level2, bruteforceblocker, vxvault and cybercrime; greensnow is part of level2 --- host_firewall/defaults/main.yml | 22 ++- host_firewall/files/nft-host-firehol | 74 ++++++---- host_firewall/files/nft-host-firehol.service | 2 +- host_firewall/files/nft-host-firehol.timer | 2 +- host_firewall/files/nft-host-greensnow | 129 ------------------ .../files/nft-host-greensnow.service | 8 -- host_firewall/files/nft-host-greensnow.timer | 10 -- host_firewall/tasks/main.yml | 118 +++++++--------- host_firewall/templates/host.nft.j2 | 31 +++-- 9 files changed, 127 insertions(+), 269 deletions(-) delete mode 100755 host_firewall/files/nft-host-greensnow delete mode 100644 host_firewall/files/nft-host-greensnow.service delete mode 100644 host_firewall/files/nft-host-greensnow.timer diff --git a/host_firewall/defaults/main.yml b/host_firewall/defaults/main.yml index 74b4c3f..a901192 100644 --- a/host_firewall/defaults/main.yml +++ b/host_firewall/defaults/main.yml @@ -93,17 +93,20 @@ firewall: # Lets the kernel log the nft log statements of container network # namespaces (LXC guests) into the host kernel log. all_netns: false - # Shared by the Spamhaus (fw-spamhaus-in: , fw-spamhaus-out: ), FireHOL (fw-firehol-in: , fw-firehol-out: ), scanner (fw-scanners-in: ) and - # GreenSnow (fw-greensnow-in: ) chains, one limit each. + # Shared by the Spamhaus (fw-spamhaus-in: , fw-spamhaus-out: ), FireHOL (fw-firehol-in: , fw-firehol-out: ), bruteforceblocker (fw-bruteforceblocker-in: ) and scanner (fw-scanners-in: ) chains, + # one limit each. spamhaus_rate: "6/minute burst 10 packets" # Spamhaus DROP, DROPv6 and ASN-DROP: traffic from the listed networks drops # (input, forward), traffic to them is rejected (output, forward). The sets # are refreshed daily by nft-host-spamhaus. spamhaus: true - # FireHOL level1 (IPv4): treated like the Spamhaus lists, with the prefixes - # fw-firehol-in: and fw-firehol-out: and the same log limit. Entries in - # private or reserved space and ones holding an address of the host are left - # out. Refreshed daily by nft-host-firehol. + # FireHOL lists (IPv4 only, FireHOL has no IPv6 lists), from github.com/firehol/blocklist-ipsets: + # - level1 and level2 (level2 includes GreenSnow) and the malware set (vxvault and cybercrime): treated like the + # Spamhaus lists, with the prefixes fw-firehol-in: and fw-firehol-out: and the same log limit. + # - bruteforceblocker: inbound new connections from the listed hosts drop, outbound traffic is not filtered. Log + # prefix fw-bruteforceblocker-in: with its own limit, which CrowdSec whitelists. + # Entries in private or reserved space and ones holding an address of the host are left out. All sets are refreshed + # daily by nft-host-firehol. firehol: true # Internet-wide scanners (Censys, Shodan, ONYPHE, Shadowserver, ...), IPv4 # and IPv6: the cidr files of github.com/OpenFilters/internet-scanners @@ -115,13 +118,6 @@ firewall: # of any host, and ones holding an address of the host are left out # (/etc/nft-host-scanners.allowlist). Refreshed daily by nft-host-scanners. scanners: true - # GreenSnow (IPv4 single addresses, compromised and dynamic hosts from the - # FireHOL blocklist-ipsets): inbound new connections from the listed hosts - # drop, outbound traffic is not filtered. Log prefix fw-greensnow-in: with its - # own limit, which CrowdSec whitelists. Entries in private or reserved space - # and ones holding an address of the host are left out. Refreshed daily by - # nft-host-greensnow. - greensnow: true # Reject outbound TCP 25; the mail group turns it off. block_smtp_out: true # EU-27 plus CH, NO, GB, IS, LI (ipdeny country codes). Empty leaves the geo diff --git a/host_firewall/files/nft-host-firehol b/host_firewall/files/nft-host-firehol index d56ea0d..1d892b6 100644 --- a/host_firewall/files/nft-host-firehol +++ b/host_firewall/files/nft-host-firehol @@ -1,9 +1,12 @@ #!/usr/bin/python3 # Managed by Ansible (role host_firewall), do not edit. -"""Rebuilds the FireHOL level1 set firehol_v4 of table inet host. +"""Rebuilds the FireHOL sets of table inet host (IPv4 only, FireHOL has no IPv6 lists). -A failed download or sanity check exits non-zero before anything changes, so -the previous set stays in place. +Every set is built from one or more lists of the FireHOL blocklist-ipsets +(single addresses or CIDR networks, comment lines start with #). All sets go +into one file, so one reload replaces them together. A failed download or +sanity check of any list exits non-zero before anything changes, so the +previous sets stay in place. """ import ipaddress import json @@ -16,11 +19,18 @@ import time import urllib.request PERSISTED = "/etc/nftables.d/host-firehol.nft" -URL = "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset" +BASE_URL = "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/" USER_AGENT = "ruekov-host-firewall (nft-host-firehol)" -# Lower bound that catches an empty or truncated answer. -MIN_ENTRIES = 1000 +# set name -> (lists merged into it, lower bound for their entries together that +# catches an empty or truncated answer; the lists hold about 4700 (level1), +# 18700 (level2), 500 (bruteforceblocker) and 70 + 500 (vxvault, cybercrime)). +SETS = { + "firehol_v4": (["firehol_level1.netset"], 1000), + "firehol_level2_v4": (["firehol_level2.netset"], 5000), + "bruteforceblocker_v4": (["bruteforceblocker.ipset"], 100), + "malware_v4": (["vxvault.ipset", "cybercrime.ipset"], 200), +} # A prefix this wide is a parse error, not a bad network. MIN_PREFIXLEN = 8 # Private, CGNAT (NetBird), loopback, link-local and multicast/reserved space: @@ -36,17 +46,18 @@ def fail(message): sys.exit(1) -def fetch(): +def fetch(name): + url = BASE_URL + name error = None for attempt in range(3): try: - request = urllib.request.Request(URL, headers={"User-Agent": USER_AGENT}) + request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT}) with urllib.request.urlopen(request, timeout=120) as response: return response.read().decode("utf-8") except OSError as e: error = e time.sleep(5 * (attempt + 1)) - fail(f"download of {URL} failed: {error}") + fail(f"download of {url} failed: {error}") def own_addresses(): @@ -57,20 +68,20 @@ def own_addresses(): for a in link.get("addr_info", []) if a.get("family") == "inet"] -def main(): +def build_set(lists, minimum, own): networks = [] - for line in fetch().splitlines(): - line = line.strip() - if not line or line.startswith("#"): - continue - try: - networks.append(ipaddress.IPv4Network(line)) - except ValueError: - fail(f"unparsable line: {line!r}") - if len(networks) < MIN_ENTRIES: - fail(f"only {len(networks)} entries") + for name in lists: + for line in fetch(name).splitlines(): + line = line.strip() + if not line or line.startswith("#"): + continue + try: + networks.append(ipaddress.IPv4Network(line)) + except ValueError: + fail(f"unparsable line in {name}: {line!r}") + if len(networks) < minimum: + fail(f"only {len(networks)} entries in {', '.join(lists)}") - own = own_addresses() kept, excluded, own_skipped = [], 0, 0 for network in networks: if any(network.overlaps(e) for e in EXCLUDED): @@ -82,21 +93,28 @@ def main(): fail(f"suspiciously wide prefix {network}") kept.append(network) merged = list(ipaddress.collapse_addresses(kept)) - print(f"firehol_v4: {len(networks)} entries, {excluded} in private or reserved space and " - f"{own_skipped} holding an own address skipped -> {len(merged)} merged") + return networks, excluded, own_skipped, merged - elements = ",\n\t\t".join(str(n) for n in merged) + "," + +def main(): + own = own_addresses() + definitions = [] + for set_name, (lists, minimum) in SETS.items(): + networks, excluded, own_skipped, merged = build_set(lists, minimum, own) + print(f"{set_name}: {len(networks)} entries, {excluded} in private or reserved space and " + f"{own_skipped} holding an own address skipped -> {len(merged)} merged") + elements = ",\n\t\t".join(str(n) for n in merged) + "," + definitions.append(f"\tset {set_name} {{ type ipv4_addr; flags interval; auto-merge; elements = {{\n" + f"\t\t{elements}\n\t}} }}\n") persisted = ("# Generated by nft-host-firehol, do not edit.\n" - "table inet host {\n" - "\tset firehol_v4 { type ipv4_addr; flags interval; auto-merge; elements = {\n" - f"\t\t{elements}\n\t}} }}\n}}\n") + "table inet host {\n" + "".join(definitions) + "}\n") # Checked under another table name: a dry run against the live table # name changes the live sets for its duration and unlisted addresses match. check_rules = persisted.replace("table inet host {", "table inet host_firehol_check {") checked = subprocess.run(["nft", "-c", "-f", "-"], input=check_rules, capture_output=True, text=True) if checked.returncode != 0: - fail(f"nft rejects the set: {checked.stderr.strip()}") + fail(f"nft rejects the sets: {checked.stderr.strip()}") with tempfile.TemporaryDirectory() as tmp: previous = None diff --git a/host_firewall/files/nft-host-firehol.service b/host_firewall/files/nft-host-firehol.service index 2323946..9501acf 100644 --- a/host_firewall/files/nft-host-firehol.service +++ b/host_firewall/files/nft-host-firehol.service @@ -1,5 +1,5 @@ [Unit] -Description=Refresh the FireHOL set of the host firewall +Description=Refresh the FireHOL sets of the host firewall Wants=network-online.target After=network-online.target diff --git a/host_firewall/files/nft-host-firehol.timer b/host_firewall/files/nft-host-firehol.timer index 3e0b6b5..0c935cb 100644 --- a/host_firewall/files/nft-host-firehol.timer +++ b/host_firewall/files/nft-host-firehol.timer @@ -1,5 +1,5 @@ [Unit] -Description=Daily refresh of the host firewall FireHOL set +Description=Daily refresh of the host firewall FireHOL sets [Timer] OnCalendar=daily diff --git a/host_firewall/files/nft-host-greensnow b/host_firewall/files/nft-host-greensnow deleted file mode 100755 index 2b63d04..0000000 --- a/host_firewall/files/nft-host-greensnow +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/python3 -# Managed by Ansible (role host_firewall), do not edit. -"""Rebuilds the GreenSnow set greensnow_v4 of table inet host. - -Source: the GreenSnow list of the FireHOL blocklist-ipsets (single IPv4 -addresses, comment lines start with #). A failed download or sanity check -exits non-zero before anything changes, so the previous set stays in place. -""" -import ipaddress -import json -import os -import shutil -import subprocess -import sys -import tempfile -import time -import urllib.request - -PERSISTED = "/etc/nftables.d/host-greensnow.nft" -URL = "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/greensnow.ipset" -USER_AGENT = "ruekov-host-firewall (nft-host-greensnow)" - -# Lower bound that catches an empty or truncated answer (the list holds about -# 4700 entries). -MIN_ENTRIES = 500 -# A prefix this wide is a parse error, not a bad address. -MIN_PREFIXLEN = 8 -# Private, CGNAT (NetBird), loopback, link-local and multicast/reserved space: -# an entry overlapping one of these never lands in the set, so the own -# infrastructure cannot block itself. -EXCLUDED = [ipaddress.ip_network(n) for n in ( - "0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", - "169.254.0.0/16", "172.16.0.0/12", "192.168.0.0/16", "224.0.0.0/3")] - - -def fail(message): - print(f"nft-host-greensnow: {message}", file=sys.stderr) - sys.exit(1) - - -def fetch(): - error = None - for attempt in range(3): - try: - request = urllib.request.Request(URL, headers={"User-Agent": USER_AGENT}) - with urllib.request.urlopen(request, timeout=120) as response: - return response.read().decode("utf-8") - except OSError as e: - error = e - time.sleep(5 * (attempt + 1)) - fail(f"download of {URL} failed: {error}") - - -def own_addresses(): - result = subprocess.run(["ip", "-j", "-4", "address", "show"], capture_output=True, text=True) - if result.returncode != 0: - fail(f"ip address show failed: {result.stderr.strip()}") - return [ipaddress.ip_address(a["local"]) for link in json.loads(result.stdout) - for a in link.get("addr_info", []) if a.get("family") == "inet"] - - -def main(): - networks = [] - for line in fetch().splitlines(): - line = line.strip() - if not line or line.startswith("#"): - continue - try: - networks.append(ipaddress.IPv4Network(line)) - except ValueError: - fail(f"unparsable line: {line!r}") - if len(networks) < MIN_ENTRIES: - fail(f"only {len(networks)} entries") - - own = own_addresses() - kept, excluded, own_skipped = [], 0, 0 - for network in networks: - if network.prefixlen < MIN_PREFIXLEN: - fail(f"suspiciously wide prefix {network}") - if any(network.overlaps(e) for e in EXCLUDED): - excluded += 1 - elif any(address in network for address in own): - own_skipped += 1 - else: - kept.append(network) - merged = list(ipaddress.collapse_addresses(kept)) - print(f"greensnow_v4: {len(networks)} entries, {excluded} in private or reserved space and " - f"{own_skipped} holding an own address skipped -> {len(merged)} merged") - - elements = ",\n\t\t".join(str(n) for n in merged) + "," - persisted = ("# Generated by nft-host-greensnow, do not edit.\n" - "table inet host {\n" - "\tset greensnow_v4 { type ipv4_addr; flags interval; auto-merge; elements = {\n" - f"\t\t{elements}\n\t}} }}\n}}\n") - - # Checked under another table name: a dry run against the live table - # name changes the live sets for its duration and unlisted addresses match. - check_rules = persisted.replace("table inet host {", "table inet host_greensnow_check {") - checked = subprocess.run(["nft", "-c", "-f", "-"], input=check_rules, capture_output=True, text=True) - if checked.returncode != 0: - fail(f"nft rejects the set: {checked.stderr.strip()}") - - with tempfile.TemporaryDirectory() as tmp: - previous = None - if os.path.exists(PERSISTED): - previous = os.path.join(tmp, "previous.nft") - shutil.copyfile(PERSISTED, previous) - with open(PERSISTED + ".new", "w", encoding="utf-8") as f: - f.write(persisted) - os.chmod(PERSISTED + ".new", 0o644) - os.replace(PERSISTED + ".new", PERSISTED) - - # A reload replaces the whole table, sets included, in one transaction. - active = subprocess.run(["systemctl", "-q", "is-active", "nft-host.service"]).returncode == 0 - if active: - reloaded = subprocess.run(["systemctl", "reload", "nft-host.service"], capture_output=True, text=True) - if reloaded.returncode != 0: - if previous: - shutil.copyfile(previous, PERSISTED) - fail(f"reloading the rule set failed, kept the previous set: {reloaded.stderr.strip()}") - print("reloaded the rule set" if active else "persisted only") - - -try: - main() -except SystemExit: - raise -except Exception as e: # keep the previous set on any surprise - fail(f"{type(e).__name__}: {e}") diff --git a/host_firewall/files/nft-host-greensnow.service b/host_firewall/files/nft-host-greensnow.service deleted file mode 100644 index 5bce4af..0000000 --- a/host_firewall/files/nft-host-greensnow.service +++ /dev/null @@ -1,8 +0,0 @@ -[Unit] -Description=Refresh the GreenSnow set of the host firewall -Wants=network-online.target -After=network-online.target - -[Service] -Type=oneshot -ExecStart=/usr/local/sbin/nft-host-greensnow diff --git a/host_firewall/files/nft-host-greensnow.timer b/host_firewall/files/nft-host-greensnow.timer deleted file mode 100644 index 07ff81e..0000000 --- a/host_firewall/files/nft-host-greensnow.timer +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Daily refresh of the host firewall GreenSnow set - -[Timer] -OnCalendar=daily -RandomizedDelaySec=6h -Persistent=true - -[Install] -WantedBy=timers.target diff --git a/host_firewall/tasks/main.yml b/host_firewall/tasks/main.yml index f207c8b..a66f4ee 100644 --- a/host_firewall/tasks/main.yml +++ b/host_firewall/tasks/main.yml @@ -59,7 +59,7 @@ src: "{{ item }}" dest: "/etc/systemd/system/{{ item }}" mode: "0644" - loop: [nft-host.service, nft-host-geo.service, nft-host-geo.timer, nft-host-spamhaus.service, nft-host-spamhaus.timer, nft-host-firehol.service, nft-host-firehol.timer, nft-host-scanners.service, nft-host-scanners.timer, nft-host-greensnow.service, nft-host-greensnow.timer] + loop: [nft-host.service, nft-host-geo.service, nft-host-geo.timer, nft-host-spamhaus.service, nft-host-spamhaus.timer, nft-host-firehol.service, nft-host-firehol.timer, nft-host-scanners.service, nft-host-scanners.timer] register: firewall_units - name: Install the rollback script @@ -174,7 +174,7 @@ path: /etc/nftables.d/host-spamhaus.nft state: absent -- name: FireHOL set +- name: FireHOL sets when: firewall.firehol block: - name: Install the FireHOL set updater @@ -183,25 +183,31 @@ dest: /usr/local/sbin/nft-host-firehol mode: "0755" - # The rule set includes this file, so a missing one would fail the load at boot. - - name: Build the FireHOL set on first run - ansible.builtin.command: /usr/local/sbin/nft-host-firehol - args: - creates: /etc/nftables.d/host-firehol.nft + # The rule set includes this file and uses all of its sets, so a missing file or set would fail the load at boot. + - name: Look for the FireHOL sets + ansible.builtin.command: grep -cE 'set (firehol_v4|firehol_level2_v4|bruteforceblocker_v4|malware_v4) ' /etc/nftables.d/host-firehol.nft + register: firewall_firehol_sets + changed_when: false + failed_when: false + check_mode: false - - name: Read the FireHOL set file + - name: Build the FireHOL sets when missing + ansible.builtin.command: /usr/local/sbin/nft-host-firehol + when: firewall_firehol_sets.stdout != '4' + + - name: Read the FireHOL sets file ansible.builtin.stat: path: /etc/nftables.d/host-firehol.nft register: firewall_firehol - - name: Require non-empty FireHOL set + - name: Require non-empty FireHOL sets ansible.builtin.assert: that: firewall_firehol.stat.exists and firewall_firehol.stat.size > 0 fail_msg: /etc/nftables.d/host-firehol.nft is missing or empty, refusing to apply the firewall # Check mode neither installs the updater nor builds the sets. when: not ansible_check_mode - - name: Enable the FireHOL set timer + - name: Enable the FireHOL sets timer ansible.builtin.systemd: name: nft-host-firehol.timer enabled: true @@ -210,10 +216,10 @@ # Check mode does not install the unit. ignore_errors: "{{ ansible_check_mode }}" -- name: Stop the FireHOL set refresh +- name: Stop the FireHOL sets refresh when: not firewall.firehol block: - - name: Disable the FireHOL set timer + - name: Disable the FireHOL sets timer ansible.builtin.systemd: name: nft-host-firehol.timer enabled: false @@ -222,7 +228,7 @@ # Check mode does not install the unit. ignore_errors: "{{ ansible_check_mode }}" - - name: Remove the FireHOL set file + - name: Remove the FireHOL sets file ansible.builtin.file: path: /etc/nftables.d/host-firehol.nft state: absent @@ -287,59 +293,6 @@ path: /etc/nftables.d/host-scanners.nft state: absent -- name: GreenSnow set - when: firewall.greensnow - block: - - name: Install the GreenSnow set updater - ansible.builtin.copy: - src: nft-host-greensnow - dest: /usr/local/sbin/nft-host-greensnow - mode: "0755" - - # The rule set includes this file, so a missing one would fail the load at boot. - - name: Build the GreenSnow set on first run - ansible.builtin.command: /usr/local/sbin/nft-host-greensnow - args: - creates: /etc/nftables.d/host-greensnow.nft - - - name: Read the GreenSnow set file - ansible.builtin.stat: - path: /etc/nftables.d/host-greensnow.nft - register: firewall_greensnow - - - name: Require non-empty GreenSnow set - ansible.builtin.assert: - that: firewall_greensnow.stat.exists and firewall_greensnow.stat.size > 0 - fail_msg: /etc/nftables.d/host-greensnow.nft is missing or empty, refusing to apply the firewall - # Check mode neither installs the updater nor builds the set. - when: not ansible_check_mode - - - name: Enable the GreenSnow set timer - ansible.builtin.systemd: - name: nft-host-greensnow.timer - enabled: true - state: started - daemon_reload: "{{ firewall_units is changed }}" - # Check mode does not install the unit. - ignore_errors: "{{ ansible_check_mode }}" - -- name: Stop the GreenSnow set refresh - when: not firewall.greensnow - block: - - name: Disable the GreenSnow set timer - ansible.builtin.systemd: - name: nft-host-greensnow.timer - enabled: false - state: stopped - daemon_reload: "{{ firewall_units is changed }}" - # Check mode does not install the unit. - ignore_errors: "{{ ansible_check_mode }}" - - - name: Remove the GreenSnow set file - ansible.builtin.file: - path: /etc/nftables.d/host-greensnow.nft - state: absent - - name: Render the rule set ansible.builtin.template: src: host.nft.j2 @@ -414,3 +367,36 @@ dest: /etc/nftables.d/host.nft.good remote_src: true mode: "0644" + +# GreenSnow is part of FireHOL level2. The rule file goes last: the last confirmed rule set (host.nft.good) and a +# reload by a refresh service still include it until the new rule set is confirmed. The set itself leaves the live +# table with the reload of the new rule set. +- name: Look for the GreenSnow timer + ansible.builtin.stat: + path: /etc/systemd/system/nft-host-greensnow.timer + register: firewall_greensnow_timer + +- name: Stop the GreenSnow refresh + ansible.builtin.systemd: + name: nft-host-greensnow.timer + enabled: false + state: stopped + when: firewall_greensnow_timer.stat.exists + # Check mode does not stop the timer. + ignore_errors: "{{ ansible_check_mode }}" + +- name: Remove the GreenSnow files + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - /etc/systemd/system/nft-host-greensnow.service + - /etc/systemd/system/nft-host-greensnow.timer + - /usr/local/sbin/nft-host-greensnow + - /etc/nftables.d/host-greensnow.nft + register: firewall_greensnow_files + +- name: Reload systemd after removing the GreenSnow units + ansible.builtin.systemd: + daemon_reload: true + when: firewall_greensnow_files is changed diff --git a/host_firewall/templates/host.nft.j2 b/host_firewall/templates/host.nft.j2 index d6d31c8..125a0ae 100644 --- a/host_firewall/templates/host.nft.j2 +++ b/host_firewall/templates/host.nft.j2 @@ -86,9 +86,6 @@ include "/etc/nftables.d/host-firehol.nft" {% if firewall.scanners %} include "/etc/nftables.d/host-scanners.nft" {% endif %} -{% if firewall.greensnow %} -include "/etc/nftables.d/host-greensnow.nft" -{% endif %} table inet host { {{ addr_set('admin_v4', 'ipv4_addr', firewall.admin.v4) }} @@ -173,6 +170,8 @@ table inet host { {% endif %} {% if firewall.firehol %} ip saddr @firehol_v4 jump firehol_in + ip saddr @firehol_level2_v4 jump firehol_in + ip saddr @malware_v4 jump firehol_in {% endif %} {% endif %} @@ -193,10 +192,10 @@ table inet host { ip6 saddr @scanners_v6 jump scanners_in {% endif %} -{% if firewall.greensnow %} +{% if firewall.firehol %} - # After the established rule: only inbound connections of GreenSnow hosts drop. - ip saddr @greensnow_v4 jump greensnow_in + # After the established rule: only inbound connections of bruteforceblocker hosts drop. + ip saddr @bruteforceblocker_v4 jump bruteforceblocker_in {% endif %} ct state invalid jump drop_log @@ -361,13 +360,13 @@ table inet host { drop } {% endif %} -{% if firewall.greensnow %} +{% if firewall.firehol %} - # Own limit and prefix, so GreenSnow hits use up neither the fw-in-drop budget + # Own limit and prefix, so bruteforceblocker hits use up neither the fw-in-drop budget # nor the one of the blocklists. CrowdSec whitelists the prefix: the listed # hosts are known and need no decision. - chain greensnow_in { - limit rate {{ firewall.log.spamhaus_rate }} log prefix "fw-greensnow-in: " + chain bruteforceblocker_in { + limit rate {{ firewall.log.spamhaus_rate }} log prefix "fw-bruteforceblocker-in: " drop } {% endif %} @@ -385,6 +384,8 @@ table inet host { {% if firewall.firehol %} ip daddr @firehol_v4 jump firehol_out + ip daddr @firehol_level2_v4 jump firehol_out + ip daddr @malware_v4 jump firehol_out {% endif %} {% if firewall.block_smtp_out %} @@ -448,7 +449,7 @@ table inet host { ip6 saddr @geo_v6 accept {% endif %} } -{% if forward_guard or blocklists or firewall.scanners or firewall.greensnow or rl_forward or firewall.block_smtp_out %} +{% if forward_guard or blocklists or firewall.scanners or rl_forward or firewall.block_smtp_out %} chain forward { type filter hook forward priority filter; policy accept; @@ -471,15 +472,19 @@ table inet host { ip saddr @firehol_v4 jump firehol_in ip daddr @firehol_v4 jump firehol_out + ip saddr @firehol_level2_v4 jump firehol_in + ip daddr @firehol_level2_v4 jump firehol_out + ip saddr @malware_v4 jump firehol_in + ip daddr @malware_v4 jump firehol_out {% endif %} {% if firewall.scanners %} ct state new ip saddr @scanners_v4 jump scanners_in ct state new ip6 saddr @scanners_v6 jump scanners_in {% endif %} -{% if firewall.greensnow %} +{% if firewall.firehol %} - ct state new ip saddr @greensnow_v4 jump greensnow_in + ct state new ip saddr @bruteforceblocker_v4 jump bruteforceblocker_in {% endif %} {% for guard in forward_guard %}