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: {}
|
ifaces: {}
|
||||||
v4: {}
|
v4: {}
|
||||||
v6: {}
|
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"
|
ssh_rate_limit: "10/minute burst 5 packets"
|
||||||
# EU-27 plus CH, NO, GB, IS, LI (ipdeny country codes). Empty leaves the geo
|
# 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.
|
# 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]
|
[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,
|
# 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.
|
# reload and stop would wipe this table, so load after it and follow all three.
|
||||||
DefaultDependencies=no
|
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 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_ifaces = firewall.guest_ifaces | default({}, true) | dict2items | rejectattr('value', 'none') | map(attribute='value') | unique | list %}
|
||||||
{% set guest_match = 'iifname { "' ~ (guest_ifaces | join('", "')) ~ '" }' %}
|
{% 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
|
# 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 {}
|
table inet host {}
|
||||||
delete table inet host
|
delete table inet host
|
||||||
|
table ip host_nat {}
|
||||||
|
delete table ip host_nat
|
||||||
|
|
||||||
{% if firewall.geo_countries %}
|
{% if firewall.geo_countries %}
|
||||||
include "/etc/nftables.d/host-geo.nft"
|
include "/etc/nftables.d/host-geo.nft"
|
||||||
@@ -116,3 +120,23 @@ table inet host {
|
|||||||
{% endif %}
|
{% 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