summaryrefslogtreecommitdiff
path: root/data/templates/firewall
diff options
context:
space:
mode:
authorkumvijaya <kumvijaya@gmail.com>2024-05-21 16:41:14 +0530
committerkumvijaya <kumvijaya@gmail.com>2024-05-21 16:41:14 +0530
commitcc86483fdf7a6bd988f485c06402fd07368dd26e (patch)
tree9d892a9715106cc67bf1e57b15b999aa7e564057 /data/templates/firewall
parent704ca2322d0bebcb923f5136f0f69fb23651a484 (diff)
downloadvyos-workflow-test-temp-cc86483fdf7a6bd988f485c06402fd07368dd26e.tar.gz
vyos-workflow-test-temp-cc86483fdf7a6bd988f485c06402fd07368dd26e.zip
T6357: create test repository to validate setup
Diffstat (limited to 'data/templates/firewall')
-rw-r--r--data/templates/firewall/nftables-bridge.j235
-rw-r--r--data/templates/firewall/nftables-cgnat.j247
-rw-r--r--data/templates/firewall/nftables-defines.j2123
-rw-r--r--data/templates/firewall/nftables-geoip-update.j233
-rw-r--r--data/templates/firewall/nftables-nat.j246
-rw-r--r--data/templates/firewall/nftables-nat66.j240
-rw-r--r--data/templates/firewall/nftables-offload.j29
-rw-r--r--data/templates/firewall/nftables-policy.j271
-rw-r--r--data/templates/firewall/nftables-static-nat.j233
-rw-r--r--data/templates/firewall/nftables-zone.j277
-rw-r--r--data/templates/firewall/nftables.j2327
11 files changed, 841 insertions, 0 deletions
diff --git a/data/templates/firewall/nftables-bridge.j2 b/data/templates/firewall/nftables-bridge.j2
new file mode 100644
index 0000000..dec027b
--- /dev/null
+++ b/data/templates/firewall/nftables-bridge.j2
@@ -0,0 +1,35 @@
+{% macro bridge(bridge) %}
+{% set ns = namespace(sets=[]) %}
+{% if bridge.forward is vyos_defined %}
+{% for prior, conf in bridge.forward.items() %}
+ chain VYOS_FORWARD_{{ prior }} {
+ type filter hook forward priority {{ prior }}; policy accept;
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('FWD', prior, rule_id, 'bri') }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['FWD_' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('FWD-filter', 'bri') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% if bridge.name is vyos_defined %}
+{% for name_text, conf in bridge.name.items() %}
+ chain NAME_{{ name_text }} {
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('NAM', name_text, rule_id, 'bri') }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['NAM_' + name_text + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule(name_text, 'bri') }}
+ }
+{% endfor %}
+{% endif %}
+{% endmacro %}
diff --git a/data/templates/firewall/nftables-cgnat.j2 b/data/templates/firewall/nftables-cgnat.j2
new file mode 100644
index 0000000..79a8e3d
--- /dev/null
+++ b/data/templates/firewall/nftables-cgnat.j2
@@ -0,0 +1,47 @@
+#!/usr/sbin/nft -f
+
+add table ip cgnat
+flush table ip cgnat
+
+add map ip cgnat tcp_nat_map { type ipv4_addr: interval ipv4_addr . inet_service ; flags interval ;}
+add map ip cgnat udp_nat_map { type ipv4_addr: interval ipv4_addr . inet_service ; flags interval ;}
+add map ip cgnat icmp_nat_map { type ipv4_addr: interval ipv4_addr . inet_service ; flags interval ;}
+add map ip cgnat other_nat_map { type ipv4_addr: interval ipv4_addr ; flags interval ;}
+flush map ip cgnat tcp_nat_map
+flush map ip cgnat udp_nat_map
+flush map ip cgnat icmp_nat_map
+flush map ip cgnat other_nat_map
+
+table ip cgnat {
+ map tcp_nat_map {
+ type ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { {{ proto_map_elements }} }
+ }
+
+ map udp_nat_map {
+ type ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { {{ proto_map_elements }} }
+ }
+
+ map icmp_nat_map {
+ type ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { {{ proto_map_elements }} }
+ }
+
+ map other_nat_map {
+ type ipv4_addr : interval ipv4_addr
+ flags interval
+ elements = { {{ other_map_elements }} }
+ }
+
+ chain POSTROUTING {
+ type nat hook postrouting priority srcnat; policy accept;
+ ip protocol tcp counter snat ip to ip saddr map @tcp_nat_map
+ ip protocol udp counter snat ip to ip saddr map @udp_nat_map
+ ip protocol icmp counter snat ip to ip saddr map @icmp_nat_map
+ counter snat ip to ip saddr map @other_nat_map
+ }
+}
diff --git a/data/templates/firewall/nftables-defines.j2 b/data/templates/firewall/nftables-defines.j2
new file mode 100644
index 0000000..8a75ab2
--- /dev/null
+++ b/data/templates/firewall/nftables-defines.j2
@@ -0,0 +1,123 @@
+{% macro groups(group, is_ipv6, is_l3) %}
+{% if group is vyos_defined %}
+{% set ip_type = 'ipv6_addr' if is_ipv6 else 'ipv4_addr' %}
+{% if group.address_group is vyos_defined and not is_ipv6 and is_l3 %}
+{% for group_name, group_conf in group.address_group.items() %}
+{% set includes = group_conf.include if group_conf.include is vyos_defined else [] %}
+ set A_{{ group_name }} {
+ type {{ ip_type }}
+ flags interval
+ auto-merge
+{% if group_conf.address is vyos_defined or includes %}
+ elements = { {{ group_conf.address | nft_nested_group(includes, group.address_group, 'address') | join(",") }} }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+{% if group.ipv6_address_group is vyos_defined and is_ipv6 and is_l3 %}
+{% for group_name, group_conf in group.ipv6_address_group.items() %}
+{% set includes = group_conf.include if group_conf.include is vyos_defined else [] %}
+ set A6_{{ group_name }} {
+ type {{ ip_type }}
+ flags interval
+ auto-merge
+{% if group_conf.address is vyos_defined or includes %}
+ elements = { {{ group_conf.address | nft_nested_group(includes, group.ipv6_address_group, 'address') | join(",") }} }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+{% if group.domain_group is vyos_defined and is_l3 %}
+{% for name, name_config in group.domain_group.items() %}
+ set D_{{ name }} {
+ type {{ ip_type }}
+ flags interval
+ }
+{% endfor %}
+{% endif %}
+{% if group.mac_group is vyos_defined %}
+{% for group_name, group_conf in group.mac_group.items() %}
+{% set includes = group_conf.include if group_conf.include is vyos_defined else [] %}
+ set M_{{ group_name }} {
+ type ether_addr
+{% if group_conf.mac_address is vyos_defined or includes %}
+ elements = { {{ group_conf.mac_address | nft_nested_group(includes, group.mac_group, 'mac_address') | join(",") }} }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+{% if group.network_group is vyos_defined and not is_ipv6 and is_l3 %}
+{% for group_name, group_conf in group.network_group.items() %}
+{% set includes = group_conf.include if group_conf.include is vyos_defined else [] %}
+ set N_{{ group_name }} {
+ type {{ ip_type }}
+ flags interval
+ auto-merge
+{% if group_conf.network is vyos_defined or includes %}
+ elements = { {{ group_conf.network | nft_nested_group(includes, group.network_group, 'network') | join(",") }} }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+{% if group.ipv6_network_group is vyos_defined and is_ipv6 and is_l3 %}
+{% for group_name, group_conf in group.ipv6_network_group.items() %}
+{% set includes = group_conf.include if group_conf.include is vyos_defined else [] %}
+ set N6_{{ group_name }} {
+ type {{ ip_type }}
+ flags interval
+ auto-merge
+{% if group_conf.network is vyos_defined or includes %}
+ elements = { {{ group_conf.network | nft_nested_group(includes, group.ipv6_network_group, 'network') | join(",") }} }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+{% if group.port_group is vyos_defined and is_l3 %}
+{% for group_name, group_conf in group.port_group.items() %}
+{% set includes = group_conf.include if group_conf.include is vyos_defined else [] %}
+ set P_{{ group_name }} {
+ type inet_service
+ flags interval
+ auto-merge
+{% if group_conf.port is vyos_defined or includes %}
+ elements = { {{ group_conf.port | nft_nested_group(includes, group.port_group, 'port') | join(",") }} }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+{% if group.interface_group is vyos_defined %}
+{% for group_name, group_conf in group.interface_group.items() %}
+{% set includes = group_conf.include if group_conf.include is vyos_defined else [] %}
+ set I_{{ group_name }} {
+ type ifname
+ flags interval
+ auto-merge
+{% if group_conf.interface is vyos_defined or includes %}
+ elements = { {{ group_conf.interface | nft_nested_group(includes, group.interface_group, 'interface') | join(",") }} }
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+
+{% if group.dynamic_group is vyos_defined %}
+{% if group.dynamic_group.address_group is vyos_defined and not is_ipv6 and is_l3 %}
+{% for group_name, group_conf in group.dynamic_group.address_group.items() %}
+ set DA_{{ group_name }} {
+ type {{ ip_type }}
+ flags dynamic, timeout
+ }
+{% endfor %}
+{% endif %}
+
+{% if group.dynamic_group.ipv6_address_group is vyos_defined and is_ipv6 and is_l3 %}
+{% for group_name, group_conf in group.dynamic_group.ipv6_address_group.items() %}
+ set DA6_{{ group_name }} {
+ type {{ ip_type }}
+ flags dynamic, timeout
+ }
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% endif %}
+{% endmacro %}
diff --git a/data/templates/firewall/nftables-geoip-update.j2 b/data/templates/firewall/nftables-geoip-update.j2
new file mode 100644
index 0000000..832ccc3
--- /dev/null
+++ b/data/templates/firewall/nftables-geoip-update.j2
@@ -0,0 +1,33 @@
+#!/usr/sbin/nft -f
+
+{% if ipv4_sets is vyos_defined %}
+{% for setname, ip_list in ipv4_sets.items() %}
+flush set ip vyos_filter {{ setname }}
+{% endfor %}
+
+table ip vyos_filter {
+{% for setname, ip_list in ipv4_sets.items() %}
+ set {{ setname }} {
+ type ipv4_addr
+ flags interval
+ elements = { {{ ','.join(ip_list) }} }
+ }
+{% endfor %}
+}
+{% endif %}
+
+{% if ipv6_sets is vyos_defined %}
+{% for setname, ip_list in ipv6_sets.items() %}
+flush set ip6 vyos_filter {{ setname }}
+{% endfor %}
+
+table ip6 vyos_filter {
+{% for setname, ip_list in ipv6_sets.items() %}
+ set {{ setname }} {
+ type ipv6_addr
+ flags interval
+ elements = { {{ ','.join(ip_list) }} }
+ }
+{% endfor %}
+}
+{% endif %}
diff --git a/data/templates/firewall/nftables-nat.j2 b/data/templates/firewall/nftables-nat.j2
new file mode 100644
index 0000000..4254f6a
--- /dev/null
+++ b/data/templates/firewall/nftables-nat.j2
@@ -0,0 +1,46 @@
+#!/usr/sbin/nft -f
+
+{% import 'firewall/nftables-defines.j2' as group_tmpl %}
+
+{% if first_install is not vyos_defined %}
+delete table ip vyos_nat
+{% endif %}
+{% if deleted is not vyos_defined %}
+table ip vyos_nat {
+ #
+ # Destination NAT rules build up here
+ #
+ chain PREROUTING {
+ type nat hook prerouting priority -100; policy accept;
+ counter jump VYOS_PRE_DNAT_HOOK
+{% if destination.rule is vyos_defined %}
+{% for rule, config in destination.rule.items() if config.disable is not vyos_defined %}
+ {{ config | nat_rule(rule, 'destination') }}
+{% endfor %}
+{% endif %}
+ }
+
+ #
+ # Source NAT rules build up here
+ #
+ chain POSTROUTING {
+ type nat hook postrouting priority 100; policy accept;
+ counter jump VYOS_PRE_SNAT_HOOK
+{% if source.rule is vyos_defined %}
+{% for rule, config in source.rule.items() if config.disable is not vyos_defined %}
+ {{ config | nat_rule(rule, 'source') }}
+{% endfor %}
+{% endif %}
+ }
+
+ chain VYOS_PRE_DNAT_HOOK {
+ return
+ }
+
+ chain VYOS_PRE_SNAT_HOOK {
+ return
+ }
+
+{{ group_tmpl.groups(firewall_group, False, True) }}
+}
+{% endif %}
diff --git a/data/templates/firewall/nftables-nat66.j2 b/data/templates/firewall/nftables-nat66.j2
new file mode 100644
index 0000000..67eb2c1
--- /dev/null
+++ b/data/templates/firewall/nftables-nat66.j2
@@ -0,0 +1,40 @@
+#!/usr/sbin/nft -f
+
+{% if first_install is not vyos_defined %}
+delete table ip6 vyos_nat
+{% endif %}
+table ip6 vyos_nat {
+ #
+ # Destination NAT66 rules build up here
+ #
+ chain PREROUTING {
+ type nat hook prerouting priority -100; policy accept;
+ counter jump VYOS_DNPT_HOOK
+{% if destination.rule is vyos_defined %}
+{% for rule, config in destination.rule.items() if config.disable is not vyos_defined %}
+ {{ config | nat_rule(rule, 'destination', ipv6=True) }}
+{% endfor %}
+{% endif %}
+ }
+
+ #
+ # Source NAT66 rules build up here
+ #
+ chain POSTROUTING {
+ type nat hook postrouting priority 100; policy accept;
+ counter jump VYOS_SNPT_HOOK
+{% if source.rule is vyos_defined %}
+{% for rule, config in source.rule.items() if config.disable is not vyos_defined %}
+ {{ config | nat_rule(rule, 'source', ipv6=True) }}
+{% endfor %}
+{% endif %}
+ }
+
+ chain VYOS_DNPT_HOOK {
+ return
+ }
+
+ chain VYOS_SNPT_HOOK {
+ return
+ }
+}
diff --git a/data/templates/firewall/nftables-offload.j2 b/data/templates/firewall/nftables-offload.j2
new file mode 100644
index 0000000..a893e05
--- /dev/null
+++ b/data/templates/firewall/nftables-offload.j2
@@ -0,0 +1,9 @@
+{% macro flowtable(name, config) %}
+ flowtable VYOS_FLOWTABLE_{{ name }} {
+ hook ingress priority 0; devices = { {{ config.interface | join(', ') }} };
+{% if config.offload is vyos_defined('hardware') %}
+ flags offload;
+{% endif %}
+ counter
+ }
+{% endmacro %}
diff --git a/data/templates/firewall/nftables-policy.j2 b/data/templates/firewall/nftables-policy.j2
new file mode 100644
index 0000000..9e28899
--- /dev/null
+++ b/data/templates/firewall/nftables-policy.j2
@@ -0,0 +1,71 @@
+#!/usr/sbin/nft -f
+
+{% import 'firewall/nftables-defines.j2' as group_tmpl %}
+
+{% if first_install is not vyos_defined %}
+delete table ip vyos_mangle
+delete table ip6 vyos_mangle
+{% endif %}
+table ip vyos_mangle {
+ chain VYOS_PBR_PREROUTING {
+ type filter hook prerouting priority -150; policy accept;
+{% if route is vyos_defined %}
+{% for route_text, conf in route.items() if conf.interface is vyos_defined %}
+ iifname { {{ conf.interface | join(",") }} } counter jump VYOS_PBR_UD_{{ route_text }}
+{% endfor %}
+{% endif %}
+ }
+
+ chain VYOS_PBR_POSTROUTING {
+ type filter hook postrouting priority -150; policy accept;
+ }
+
+{% if route is vyos_defined %}
+{% for route_text, conf in route.items() %}
+ chain VYOS_PBR_UD_{{ route_text }} {
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('route', route_text, rule_id, 'ip') }}
+{% endfor %}
+{% endif %}
+{% if conf.default_log is vyos_defined %}
+ counter log prefix "[ipv4-{{ (route_text)[:19] }}-default]"
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+
+{{ group_tmpl.groups(firewall_group, False, True) }}
+}
+
+table ip6 vyos_mangle {
+ chain VYOS_PBR6_PREROUTING {
+ type filter hook prerouting priority -150; policy accept;
+{% if route6 is vyos_defined %}
+{% for route_text, conf in route6.items() if conf.interface is vyos_defined %}
+ iifname { {{ ",".join(conf.interface) }} } counter jump VYOS_PBR6_UD_{{ route_text }}
+{% endfor %}
+{% endif %}
+ }
+
+ chain VYOS_PBR6_POSTROUTING {
+ type filter hook postrouting priority -150; policy accept;
+ }
+
+{% if route6 is vyos_defined %}
+{% for route_text, conf in route6.items() %}
+ chain VYOS_PBR6_UD_{{ route_text }} {
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('route6', route_text, rule_id, 'ip6') }}
+{% endfor %}
+{% endif %}
+{% if conf.default_log is vyos_defined %}
+ counter log prefix "[ipv6-{{ (route_text)[:19] }}-default]"
+{% endif %}
+ }
+{% endfor %}
+{% endif %}
+
+{{ group_tmpl.groups(firewall_group, True, True) }}
+}
diff --git a/data/templates/firewall/nftables-static-nat.j2 b/data/templates/firewall/nftables-static-nat.j2
new file mode 100644
index 0000000..e5e3da8
--- /dev/null
+++ b/data/templates/firewall/nftables-static-nat.j2
@@ -0,0 +1,33 @@
+#!/usr/sbin/nft -f
+
+{% if first_install is not vyos_defined %}
+delete table ip vyos_static_nat
+{% endif %}
+{% if deleted is not vyos_defined %}
+table ip vyos_static_nat {
+ #
+ # Destination NAT rules build up here
+ #
+
+ chain PREROUTING {
+ type nat hook prerouting priority -100; policy accept;
+{% if static.rule is vyos_defined %}
+{% for rule, config in static.rule.items() if config.disable is not vyos_defined %}
+ {{ config | nat_static_rule(rule, 'destination') }}
+{% endfor %}
+{% endif %}
+ }
+
+ #
+ # Source NAT rules build up here
+ #
+ chain POSTROUTING {
+ type nat hook postrouting priority 100; policy accept;
+{% if static.rule is vyos_defined %}
+{% for rule, config in static.rule.items() if config.disable is not vyos_defined %}
+ {{ config | nat_static_rule(rule, 'source') }}
+{% endfor %}
+{% endif %}
+ }
+}
+{% endif %}
diff --git a/data/templates/firewall/nftables-zone.j2 b/data/templates/firewall/nftables-zone.j2
new file mode 100644
index 0000000..e787250
--- /dev/null
+++ b/data/templates/firewall/nftables-zone.j2
@@ -0,0 +1,77 @@
+{% macro zone_chains(zone, ipv6=False, state_policy=False) %}
+{% set fw_name = 'ipv6_name' if ipv6 else 'name' %}
+{% set suffix = '6' if ipv6 else '' %}
+ chain VYOS_ZONE_FORWARD {
+ type filter hook forward priority 1; policy accept;
+{% if state_policy %}
+ jump VYOS_STATE_POLICY{{ suffix }}
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if 'local_zone' not in zone_conf %}
+ oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
+{% endif %}
+{% endfor %}
+ }
+ chain VYOS_ZONE_LOCAL {
+ type filter hook input priority 1; policy accept;
+{% if state_policy %}
+ jump VYOS_STATE_POLICY{{ suffix }}
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if 'local_zone' in zone_conf %}
+ counter jump VZONE_{{ zone_name }}_IN
+{% endif %}
+{% endfor %}
+ }
+ chain VYOS_ZONE_OUTPUT {
+ type filter hook output priority 1; policy accept;
+{% if state_policy %}
+ jump VYOS_STATE_POLICY{{ suffix }}
+{% endif %}
+{% for zone_name, zone_conf in zone.items() %}
+{% if 'local_zone' in zone_conf %}
+ counter jump VZONE_{{ zone_name }}_OUT
+{% endif %}
+{% endfor %}
+ }
+{% for zone_name, zone_conf in zone.items() %}
+{% if zone_conf.local_zone is vyos_defined %}
+ chain VZONE_{{ zone_name }}_IN {
+ iifname lo counter return
+{% if zone_conf.from is vyos_defined %}
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall[fw_name] is vyos_defined %}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% endfor %}
+{% endif %}
+ {{ zone_conf | nft_default_rule('zone_' + zone_name, family) }}
+ }
+ chain VZONE_{{ zone_name }}_OUT {
+ oifname lo counter return
+{% if zone_conf.from_local is vyos_defined %}
+{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall[fw_name] is vyos_defined %}
+ oifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ oifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% endfor %}
+{% endif %}
+ {{ zone_conf | nft_default_rule('zone_' + zone_name, family) }}
+ }
+{% else %}
+ chain VZONE_{{ zone_name }} {
+ iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6) }}
+{% if zone_conf.intra_zone_filtering is vyos_defined %}
+ iifname { {{ zone_conf.interface | join(",") }} } counter return
+{% endif %}
+{% if zone_conf.from is vyos_defined %}
+{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall[fw_name] is vyos_defined %}
+{% if zone[from_zone].local_zone is not defined %}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
+ iifname { {{ zone[from_zone].interface | join(",") }} } counter return
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ zone_conf | nft_default_rule('zone_' + zone_name, family) }}
+ }
+{% endif %}
+{% endfor %}
+{% endmacro %} \ No newline at end of file
diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2
new file mode 100644
index 0000000..833df3a
--- /dev/null
+++ b/data/templates/firewall/nftables.j2
@@ -0,0 +1,327 @@
+#!/usr/sbin/nft -f
+
+{% import 'firewall/nftables-defines.j2' as group_tmpl %}
+{% import 'firewall/nftables-bridge.j2' as bridge_tmpl %}
+{% import 'firewall/nftables-offload.j2' as offload_tmpl %}
+{% import 'firewall/nftables-zone.j2' as zone_tmpl %}
+
+flush chain raw vyos_global_rpfilter
+flush chain ip6 raw vyos_global_rpfilter
+
+table raw {
+ chain vyos_global_rpfilter {
+{% if global_options.source_validation is vyos_defined('loose') %}
+ fib saddr oif 0 counter drop
+{% elif global_options.source_validation is vyos_defined('strict') %}
+ fib saddr . iif oif 0 counter drop
+{% endif %}
+ return
+ }
+}
+
+table ip6 raw {
+ chain vyos_global_rpfilter {
+{% if global_options.ipv6_source_validation is vyos_defined('loose') %}
+ fib saddr oif 0 counter drop
+{% elif global_options.ipv6_source_validation is vyos_defined('strict') %}
+ fib saddr . iif oif 0 counter drop
+{% endif %}
+ return
+ }
+}
+
+{% if first_install is not vyos_defined %}
+delete table ip vyos_filter
+{% endif %}
+table ip vyos_filter {
+{% if ipv4 is vyos_defined %}
+{% if flowtable is vyos_defined %}
+{% for name, flowtable_conf in flowtable.items() %}
+{{ offload_tmpl.flowtable(name, flowtable_conf) }}
+{% endfor %}
+{% endif %}
+
+{% set ns = namespace(sets=[]) %}
+{% if ipv4.forward is vyos_defined %}
+{% for prior, conf in ipv4.forward.items() %}
+ chain VYOS_FORWARD_{{ prior }} {
+ type filter hook forward priority {{ prior }}; policy accept;
+{% if global_options.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('FWD', prior, rule_id) }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['FWD_' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('FWD-filter', 'ipv4') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% if ipv4.input is vyos_defined %}
+{% for prior, conf in ipv4.input.items() %}
+ chain VYOS_INPUT_{{ prior }} {
+ type filter hook input priority {{ prior }}; policy accept;
+{% if global_options.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('INP',prior, rule_id) }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['INP_' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('INP-filter', 'ipv4') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% if ipv4.output is vyos_defined %}
+{% for prior, conf in ipv4.output.items() %}
+ chain VYOS_OUTPUT_{{ prior }} {
+ type filter hook output priority {{ prior }}; policy accept;
+{% if global_options.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY
+{% endif %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('OUT', prior, rule_id) }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['OUT_' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('OUT-filter', 'ipv4') }}
+ }
+{% endfor %}
+{% endif %}
+ chain VYOS_FRAG_MARK {
+ type filter hook prerouting priority -450; policy accept;
+ ip frag-off & 0x3fff != 0 meta mark set 0xffff1 return
+ }
+{% if ipv4.prerouting is vyos_defined %}
+{% for prior, conf in ipv4.prerouting.items() %}
+ chain VYOS_PREROUTING_{{ prior }} {
+ type filter hook prerouting priority {{ prior }}; policy accept;
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('PRE', prior, rule_id) }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['PRE_' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('PRE-filter', 'ipv4') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% if ipv4.name is vyos_defined %}
+{% for name_text, conf in ipv4.name.items() %}
+ chain NAME_{{ name_text }} {
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('NAM', name_text, rule_id) }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['NAM_' + name_text + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule(name_text, 'ipv4') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% for set_name in ns.sets %}
+ set RECENT_{{ set_name }} {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+{% endfor %}
+{% for set_name in ip_fqdn %}
+ set FQDN_{{ set_name }} {
+ type ipv4_addr
+ flags interval
+ }
+{% endfor %}
+{% if geoip_updated.name is vyos_defined %}
+{% for setname in geoip_updated.name %}
+ set {{ setname }} {
+ type ipv4_addr
+ flags interval
+ }
+{% endfor %}
+{% endif %}
+{% endif %}
+{{ group_tmpl.groups(group, False, True) }}
+
+{% if zone is vyos_defined %}
+{{ zone_tmpl.zone_chains(zone, False, global_options.state_policy is vyos_defined) }}
+{% endif %}
+{% if global_options.state_policy is vyos_defined %}
+ chain VYOS_STATE_POLICY {
+{% if global_options.state_policy.established is vyos_defined %}
+ {{ global_options.state_policy.established | nft_state_policy('established') }}
+{% endif %}
+{% if global_options.state_policy.invalid is vyos_defined %}
+ {{ global_options.state_policy.invalid | nft_state_policy('invalid') }}
+{% endif %}
+{% if global_options.state_policy.related is vyos_defined %}
+ {{ global_options.state_policy.related | nft_state_policy('related') }}
+{% endif %}
+ return
+ }
+{% endif %}
+}
+
+{% if first_install is not vyos_defined %}
+delete table ip6 vyos_filter
+{% endif %}
+table ip6 vyos_filter {
+{% if ipv6 is vyos_defined %}
+{% if flowtable is vyos_defined %}
+{% for name, flowtable_conf in flowtable.items() %}
+{{ offload_tmpl.flowtable(name, flowtable_conf) }}
+{% endfor %}
+{% endif %}
+
+{% set ns = namespace(sets=[]) %}
+{% if ipv6.forward is vyos_defined %}
+{% for prior, conf in ipv6.forward.items() %}
+ chain VYOS_IPV6_FORWARD_{{ prior }} {
+ type filter hook forward priority {{ prior }}; policy accept;
+{% if global_options.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('FWD', prior, rule_id ,'ip6') }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['FWD_' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('FWD-filter', 'ipv6') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% if ipv6.input is vyos_defined %}
+{% for prior, conf in ipv6.input.items() %}
+ chain VYOS_IPV6_INPUT_{{ prior }} {
+ type filter hook input priority {{ prior }}; policy accept;
+{% if global_options.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('INP', prior, rule_id ,'ip6') }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['INP_' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('INP-filter', 'ipv6') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% if ipv6.output is vyos_defined %}
+{% for prior, conf in ipv6.output.items() %}
+ chain VYOS_IPV6_OUTPUT_{{ prior }} {
+ type filter hook output priority {{ prior }}; policy accept;
+{% if global_options.state_policy is vyos_defined %}
+ jump VYOS_STATE_POLICY6
+{% endif %}
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('OUT', prior, rule_id ,'ip6') }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['OUT_ ' + prior + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule('OUT-filter', 'ipv6') }}
+ }
+{% endfor %}
+{% endif %}
+
+ chain VYOS_FRAG6_MARK {
+ type filter hook prerouting priority -450; policy accept;
+ exthdr frag exists meta mark set 0xffff1 return
+ }
+
+{% if ipv6.name is vyos_defined %}
+{% for name_text, conf in ipv6.name.items() %}
+ chain NAME6_{{ name_text }} {
+{% if conf.rule is vyos_defined %}
+{% for rule_id, rule_conf in conf.rule.items() if rule_conf.disable is not vyos_defined %}
+ {{ rule_conf | nft_rule('NAM', name_text, rule_id, 'ip6') }}
+{% if rule_conf.recent is vyos_defined %}
+{% set ns.sets = ns.sets + ['NAM_' + name_text + '_' + rule_id] %}
+{% endif %}
+{% endfor %}
+{% endif %}
+ {{ conf | nft_default_rule(name_text, 'ipv6') }}
+ }
+{% endfor %}
+{% endif %}
+
+{% for set_name in ns.sets %}
+ set RECENT6_{{ set_name }} {
+ type ipv6_addr
+ size 65535
+ flags dynamic
+ }
+{% endfor %}
+{% for set_name in ip6_fqdn %}
+ set FQDN_{{ set_name }} {
+ type ipv6_addr
+ flags interval
+ }
+{% endfor %}
+{% if geoip_updated.ipv6_name is vyos_defined %}
+{% for setname in geoip_updated.ipv6_name %}
+ set {{ setname }} {
+ type ipv6_addr
+ flags interval
+ }
+{% endfor %}
+{% endif %}
+{% endif %}
+{{ group_tmpl.groups(group, True, True) }}
+{% if zone is vyos_defined %}
+{{ zone_tmpl.zone_chains(zone, True, global_options.state_policy is vyos_defined) }}
+{% endif %}
+{% if global_options.state_policy is vyos_defined %}
+ chain VYOS_STATE_POLICY6 {
+{% if global_options.state_policy.established is vyos_defined %}
+ {{ global_options.state_policy.established | nft_state_policy('established') }}
+{% endif %}
+{% if global_options.state_policy.invalid is vyos_defined %}
+ {{ global_options.state_policy.invalid | nft_state_policy('invalid') }}
+{% endif %}
+{% if global_options.state_policy.related is vyos_defined %}
+ {{ global_options.state_policy.related | nft_state_policy('related') }}
+{% endif %}
+ return
+ }
+{% endif %}
+}
+
+## Bridge Firewall
+{% if first_install is not vyos_defined %}
+delete table bridge vyos_filter
+{% endif %}
+table bridge vyos_filter {
+{{ bridge_tmpl.bridge(bridge) }}
+{{ group_tmpl.groups(group, False, False) }}
+
+}