From 79943e03897743b34f65ea22b590b14ca0f26d77 Mon Sep 17 00:00:00 2001 From: Ruakij Date: Fri, 6 Nov 2026 08:33:42 +0000 Subject: [PATCH] host_firewall: no_hairpin_ifaces drops forwarding back out of the interface it came in on --- host_firewall/defaults/main.yml | 4 ++++ host_firewall/templates/host.nft.j2 | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/host_firewall/defaults/main.yml b/host_firewall/defaults/main.yml index ab2bd2d..1423519 100644 --- a/host_firewall/defaults/main.yml +++ b/host_firewall/defaults/main.yml @@ -116,6 +116,10 @@ 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 + # Bridges and uplinks whose forwarded traffic may not leave through the interface it came in on (iifname X oifname X + # drop). The datacenter gateway routes packets for foreign addresses of the subnet to the host; with ip_forward they + # would be forwarded back out and masqueraded with the host address. Not for a bridge that carries guests. + no_hairpin_ifaces: {} # 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/templates/host.nft.j2 b/host_firewall/templates/host.nft.j2 index 4614936..0c0d945 100644 --- a/host_firewall/templates/host.nft.j2 +++ b/host_firewall/templates/host.nft.j2 @@ -441,10 +441,14 @@ table inet host { ip6 saddr @geo_v6 accept {% endif %} } -{% if forward_guard or blocklists or firewall.scanners or rl_forward or firewall.block_smtp_out %} +{% if forward_guard or blocklists or firewall.scanners or rl_forward or firewall.block_smtp_out or firewall.no_hairpin_ifaces %} chain forward { type filter hook forward priority filter; policy accept; +{% for name, iface in firewall.no_hairpin_ifaces.items() %} + + iifname "{{ iface }}" oifname "{{ iface }}" counter drop comment "{{ name }}: no forwarding back out of the uplink" +{% endfor %} {% if rl_forward %} # Docker-published ports and port forwards arrive here after DNAT; pod and guest egress is not DNATed.