Add IPv4 port forwards and masquerade to host_firewall in an ip host_nat table
This commit is contained in:
@@ -26,6 +26,11 @@ firewall:
|
||||
ifaces: {}
|
||||
v4: {}
|
||||
v6: {}
|
||||
# IPv4 port forwards: name -> {daddr, to, tcp: ports, udp: ports}, ports as in
|
||||
# the maps above. Forwarded traffic passes the forward hook, not input.
|
||||
dnat: {}
|
||||
# IPv4 source NAT: name -> nft match, e.g. 'oifname "vmbr0"'.
|
||||
masquerade: {}
|
||||
ssh_rate_limit: "10/minute burst 5 packets"
|
||||
# EU-27 plus CH, NO, GB, IS, LI (ipdeny country codes). Empty leaves the geo
|
||||
# ports to the admin set; a load peaks at about 60 MB of kernel memory, too much for a 1 GB host.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=Host input firewall (nftables table inet host)
|
||||
Description=Host input firewall and NAT (nftables tables inet host and ip host_nat)
|
||||
# Same early-boot placement as nftables.service. Its "flush ruleset" on start,
|
||||
# reload and stop would wipe this table, so load after it and follow all three.
|
||||
DefaultDependencies=no
|
||||
|
||||
@@ -16,11 +16,15 @@ set {{ name }} {
|
||||
{% set internal_ifaces = firewall.internal_ifaces | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %}
|
||||
{% set guest_ifaces = firewall.guest_ifaces | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %}
|
||||
{% set guest_match = 'iifname { "' ~ (guest_ifaces | join('", "')) ~ '" }' %}
|
||||
{% set dnat = firewall.dnat | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | list %}
|
||||
{% set masquerade = firewall.masquerade | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %}
|
||||
|
||||
# Declare-then-delete makes every load one atomic transaction that replaces
|
||||
# only this table; Cilium, Docker, NetBird and CrowdSec tables stay untouched.
|
||||
# only these tables; Cilium, Docker, NetBird and CrowdSec tables stay untouched.
|
||||
table inet host {}
|
||||
delete table inet host
|
||||
table ip host_nat {}
|
||||
delete table ip host_nat
|
||||
|
||||
{% if firewall.geo_countries %}
|
||||
include "/etc/nftables.d/host-geo.nft"
|
||||
@@ -116,3 +120,23 @@ table inet host {
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
{% if dnat or masquerade %}
|
||||
|
||||
table ip host_nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
{% for fwd in dnat %}
|
||||
{% for proto in ['tcp', 'udp'] if list(fwd[proto]) %}
|
||||
ip daddr {{ fwd.daddr }} {{ proto }} dport { {{ list(fwd[proto]) }} } dnat to {{ fwd.to }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
{% for match in masquerade %}
|
||||
{{ match }} masquerade
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user