diff options
Diffstat (limited to 'data/templates/firewall')
-rw-r--r-- | data/templates/firewall/nftables-defines.j2 | 32 | ||||
-rw-r--r-- | data/templates/firewall/nftables-nat.j2 | 182 | ||||
-rw-r--r-- | data/templates/firewall/nftables-nat.tmpl | 181 | ||||
-rw-r--r-- | data/templates/firewall/nftables-nat66.j2 | 102 | ||||
-rw-r--r-- | data/templates/firewall/nftables-nat66.tmpl | 102 | ||||
-rw-r--r-- | data/templates/firewall/nftables-policy.j2 | 55 | ||||
-rw-r--r-- | data/templates/firewall/nftables-vrf-zones.j2 (renamed from data/templates/firewall/nftables-vrf-zones.tmpl) | 0 | ||||
-rw-r--r-- | data/templates/firewall/nftables.j2 | 274 | ||||
-rw-r--r-- | data/templates/firewall/upnpd.conf.j2 | 172 |
9 files changed, 817 insertions, 283 deletions
diff --git a/data/templates/firewall/nftables-defines.j2 b/data/templates/firewall/nftables-defines.j2 new file mode 100644 index 000000000..4fa92f2e3 --- /dev/null +++ b/data/templates/firewall/nftables-defines.j2 @@ -0,0 +1,32 @@ +{% if group is vyos_defined %} +{% if group.address_group is vyos_defined %} +{% for group_name, group_conf in group.address_group.items() %} +define A_{{ group_name }} = { {{ group_conf.address | join(",") }} } +{% endfor %} +{% endif %} +{% if group.ipv6_address_group is vyos_defined %} +{% for group_name, group_conf in group.ipv6_address_group.items() %} +define A6_{{ group_name }} = { {{ group_conf.address | join(",") }} } +{% endfor %} +{% endif %} +{% if group.mac_group is vyos_defined %} +{% for group_name, group_conf in group.mac_group.items() %} +define M_{{ group_name }} = { {{ group_conf.mac_address | join(",") }} } +{% endfor %} +{% endif %} +{% if group.network_group is vyos_defined %} +{% for group_name, group_conf in group.network_group.items() %} +define N_{{ group_name }} = { {{ group_conf.network | join(",") }} } +{% endfor %} +{% endif %} +{% if group.ipv6_network_group is vyos_defined %} +{% for group_name, group_conf in group.ipv6_network_group.items() %} +define N6_{{ group_name }} = { {{ group_conf.network | join(",") }} } +{% endfor %} +{% endif %} +{% if group.port_group is vyos_defined %} +{% for group_name, group_conf in group.port_group.items() %} +define P_{{ group_name }} = { {{ group_conf.port | join(",") }} } +{% endfor %} +{% endif %} +{% endif %}
\ No newline at end of file diff --git a/data/templates/firewall/nftables-nat.j2 b/data/templates/firewall/nftables-nat.j2 new file mode 100644 index 000000000..1481e9104 --- /dev/null +++ b/data/templates/firewall/nftables-nat.j2 @@ -0,0 +1,182 @@ +#!/usr/sbin/nft -f + +{% macro nat_rule(rule, config, chain) %} +{% set comment = '' %} +{% set base_log = '' %} +{% set src_addr = 'ip saddr ' ~ config.source.address.replace('!','!= ') if config.source.address is vyos_defined %} +{% set dst_addr = 'ip daddr ' ~ config.destination.address.replace('!','!= ') if config.destination.address is vyos_defined %} +{# negated port groups need special treatment, move != in front of { } group #} +{% if config.source.port is vyos_defined and config.source.port.startswith('!') %} +{% set src_port = 'sport != { ' ~ config.source.port.replace('!','') ~ ' }' %} +{% else %} +{% set src_port = 'sport { ' ~ config.source.port ~ ' }' if config.source.port is vyos_defined %} +{% endif %} +{# negated port groups need special treatment, move != in front of { } group #} +{% if config.destination.port is vyos_defined and config.destination.port.startswith('!') %} +{% set dst_port = 'dport != { ' ~ config.destination.port.replace('!','') ~ ' }' %} +{% else %} +{% set dst_port = 'dport { ' ~ config.destination.port ~ ' }' if config.destination.port is vyos_defined %} +{% endif %} +{% if chain is vyos_defined('PREROUTING') %} +{% set comment = 'DST-NAT-' ~ rule %} +{% set base_log = '[NAT-DST-' ~ rule %} +{% set interface = ' iifname "' ~ config.inbound_interface ~ '"' if config.inbound_interface is vyos_defined and config.inbound_interface is not vyos_defined('any') else '' %} +{% if config.translation.address is vyos_defined %} +{# support 1:1 network translation #} +{% if config.translation.address | is_ip_network %} +{% set trns_addr = 'dnat ip prefix to ip daddr map { ' ~ config.destination.address ~ ' : ' ~ config.translation.address ~ ' }' %} +{# we can now clear out the dst_addr part as it's already covered in aboves map #} +{% set dst_addr = '' %} +{% else %} +{% set trns_addr = 'dnat to ' ~ config.translation.address %} +{% endif %} +{% endif %} +{% elif chain is vyos_defined('POSTROUTING') %} +{% set comment = 'SRC-NAT-' ~ rule %} +{% set base_log = '[NAT-SRC-' ~ rule %} +{% set interface = ' oifname "' ~ config.outbound_interface ~ '"' if config.outbound_interface is vyos_defined and config.outbound_interface is not vyos_defined('any') else '' %} +{% if config.translation.address is vyos_defined %} +{% if config.translation.address is vyos_defined('masquerade') %} +{% set trns_addr = config.translation.address %} +{% if config.translation.port is vyos_defined %} +{% set trns_addr = trns_addr ~ ' to ' %} +{% endif %} +{# support 1:1 network translation #} +{% elif config.translation.address | is_ip_network %} +{% set trns_addr = 'snat ip prefix to ip saddr map { ' ~ config.source.address ~ ' : ' ~ config.translation.address ~ ' }' %} +{# we can now clear out the src_addr part as it's already covered in aboves map #} +{% set src_addr = '' %} +{% else %} +{% set trns_addr = 'snat to ' ~ config.translation.address %} +{% endif %} +{% endif %} +{% endif %} +{% set trns_port = ':' ~ config.translation.port if config.translation.port is vyos_defined %} +{# protocol has a default value thus it is always present #} +{% if config.protocol is vyos_defined('tcp_udp') %} +{% set protocol = 'tcp' %} +{% set comment = comment ~ ' tcp_udp' %} +{% else %} +{% set protocol = config.protocol %} +{% endif %} +{% if config.log is vyos_defined %} +{% if config.exclude is vyos_defined %} +{% set log = base_log ~ '-EXCL]' %} +{% elif config.translation.address is vyos_defined('masquerade') %} +{% set log = base_log ~ '-MASQ]' %} +{% else %} +{% set log = base_log ~ ']' %} +{% endif %} +{% endif %} +{% if config.exclude is vyos_defined %} +{# rule has been marked as 'exclude' thus we simply return here #} +{% set trns_addr = 'return' %} +{% set trns_port = '' %} +{% endif %} +{# T1083: NAT address and port translation options #} +{% if config.translation.options is vyos_defined %} +{% if config.translation.options.address_mapping is vyos_defined('persistent') %} +{% set trns_opts_addr = 'persistent' %} +{% endif %} +{% if config.translation.options.port_mapping is vyos_defined('random') %} +{% set trns_opts_port = 'random' %} +{% elif config.translation.options.port_mapping is vyos_defined('fully-random') %} +{% set trns_opts_port = 'fully-random' %} +{% endif %} +{% endif %} +{% if trns_opts_addr is vyos_defined and trns_opts_port is vyos_defined %} +{% set trns_opts = trns_opts_addr ~ ',' ~ trns_opts_port %} +{% elif trns_opts_addr is vyos_defined %} +{% set trns_opts = trns_opts_addr %} +{% elif trns_opts_port is vyos_defined %} +{% set trns_opts = trns_opts_port %} +{% endif %} +{% set output = 'add rule ip nat ' ~ chain ~ interface %} +{% if protocol is not vyos_defined('all') %} +{% set output = output ~ ' ip protocol ' ~ protocol %} +{% endif %} +{% if src_addr is vyos_defined %} +{% set output = output ~ ' ' ~ src_addr %} +{% endif %} +{% if src_port is vyos_defined %} +{% set output = output ~ ' ' ~ protocol ~ ' ' ~ src_port %} +{% endif %} +{% if dst_addr is vyos_defined %} +{% set output = output ~ ' ' ~ dst_addr %} +{% endif %} +{% if dst_port is vyos_defined %} +{% set output = output ~ ' ' ~ protocol ~ ' ' ~ dst_port %} +{% endif %} +{# Count packets #} +{% set output = output ~ ' counter' %} +{# Special handling of log option, we must repeat the entire rule before the #} +{# NAT translation options are added, this is essential #} +{% if log is vyos_defined %} +{% set log_output = output ~ ' log prefix "' ~ log ~ '" comment "' ~ comment ~ '"' %} +{% endif %} +{% if trns_addr is vyos_defined %} +{% set output = output ~ ' ' ~ trns_addr %} +{% endif %} +{% if trns_port is vyos_defined %} +{# Do not add a whitespace here, translation port must be directly added after IP address #} +{# e.g. 192.0.2.10:3389 #} +{% set output = output ~ trns_port %} +{% endif %} +{% if trns_opts is vyos_defined %} +{% set output = output ~ ' ' ~ trns_opts %} +{% endif %} +{% if comment is vyos_defined %} +{% set output = output ~ ' comment "' ~ comment ~ '"' %} +{% endif %} +{{ log_output if log_output is vyos_defined }} +{{ output }} +{# Special handling if protocol is tcp_udp, we must repeat the entire rule with udp as protocol #} +{% if config.protocol is vyos_defined('tcp_udp') %} +{# Beware of trailing whitespace, without it the comment tcp_udp will be changed to udp_udp #} +{{ log_output | replace('tcp ', 'udp ') if log_output is vyos_defined }} +{{ output | replace('tcp ', 'udp ') }} +{% endif %} +{% endmacro %} + +# Start with clean SNAT and DNAT chains +flush chain ip nat PREROUTING +flush chain ip nat POSTROUTING +{% if helper_functions is vyos_defined('remove') %} +{# NAT if going to be disabled - remove rules and targets from nftables #} +{% set base_command = 'delete rule ip raw' %} +{{ base_command }} PREROUTING handle {{ pre_ct_ignore }} +{{ base_command }} OUTPUT handle {{ out_ct_ignore }} +{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }} +{{ base_command }} OUTPUT handle {{ out_ct_conntrack }} + +delete chain ip raw NAT_CONNTRACK + +{% elif helper_functions is vyos_defined('add') %} +{# NAT if enabled - add targets to nftables #} +add chain ip raw NAT_CONNTRACK +add rule ip raw NAT_CONNTRACK counter accept +{% set base_command = 'add rule ip raw' %} +{{ base_command }} PREROUTING position {{ pre_ct_ignore }} counter jump VYOS_CT_HELPER +{{ base_command }} OUTPUT position {{ out_ct_ignore }} counter jump VYOS_CT_HELPER +{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK +{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK +{% endif %} + +# +# Destination NAT rules build up here +# +add rule ip nat PREROUTING 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 %} +{{ nat_rule(rule, config, 'PREROUTING') }} +{% endfor %} +{% endif %} +# +# Source NAT rules build up here +# +add rule ip nat POSTROUTING 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 %} +{{ nat_rule(rule, config, 'POSTROUTING') }} +{% endfor %} +{% endif %} diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl deleted file mode 100644 index 40ed1b916..000000000 --- a/data/templates/firewall/nftables-nat.tmpl +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/sbin/nft -f - -{% macro nat_rule(rule, config, chain) %} -{% set comment = '' %} -{% set base_log = '' %} -{% set src_addr = 'ip saddr ' + config.source.address.replace('!','!= ') if config.source is defined and config.source.address is defined and config.source.address is not none %} -{% set dst_addr = 'ip daddr ' + config.destination.address.replace('!','!= ') if config.destination is defined and config.destination.address is defined and config.destination.address is not none %} -{# negated port groups need special treatment, move != in front of { } group #} -{% if config.source is defined and config.source.port is defined and config.source.port is not none and config.source.port.startswith('!=') %} -{% set src_port = 'sport != { ' + config.source.port.replace('!=','') + ' }' %} -{% else %} -{% set src_port = 'sport { ' + config.source.port + ' }' if config.source is defined and config.source.port is defined and config.source.port is not none %} -{% endif %} -{# negated port groups need special treatment, move != in front of { } group #} -{% if config.destination is defined and config.destination.port is defined and config.destination.port is not none and config.destination.port.startswith('!=') %} -{% set dst_port = 'dport != { ' + config.destination.port.replace('!=','') + ' }' %} -{% else %} -{% set dst_port = 'dport { ' + config.destination.port + ' }' if config.destination is defined and config.destination.port is defined and config.destination.port is not none %} -{% endif %} -{% if chain == 'PREROUTING' %} -{% set comment = 'DST-NAT-' + rule %} -{% set base_log = '[NAT-DST-' + rule %} -{% set interface = ' iifname "' + config.inbound_interface + '"' if config.inbound_interface is defined and config.inbound_interface != 'any' else '' %} -{% if config.translation is defined and config.translation.address is defined and config.translation.address is not none %} -{# support 1:1 network translation #} -{% if config.translation.address | is_ip_network %} -{% set trns_addr = 'dnat ip prefix to ip daddr map { ' + config.destination.address + ' : ' + config.translation.address + ' }' %} -{# we can now clear out the dst_addr part as it's already covered in aboves map #} -{% set dst_addr = '' %} -{% else %} -{% set trns_addr = 'dnat to ' + config.translation.address %} -{% endif %} -{% endif %} -{% elif chain == 'POSTROUTING' %} -{% set comment = 'SRC-NAT-' + rule %} -{% set base_log = '[NAT-SRC-' + rule %} -{% set interface = ' oifname "' + config.outbound_interface + '"' if config.outbound_interface is defined and config.outbound_interface != 'any' else '' %} -{% if config.translation is defined and config.translation.address is defined and config.translation.address is not none %} -{% if config.translation.address == 'masquerade' %} -{% set trns_addr = config.translation.address %} -{% if config.translation.port is defined and config.translation.port is not none %} -{% set trns_addr = trns_addr + ' to ' %} -{% endif %} -{# support 1:1 network translation #} -{% elif config.translation.address | is_ip_network %} -{% set trns_addr = 'snat ip prefix to ip saddr map { ' + config.source.address + ' : ' + config.translation.address + ' }' %} -{# we can now clear out the src_addr part as it's already covered in aboves map #} -{% set src_addr = '' %} -{% else %} -{% set trns_addr = 'snat to ' + config.translation.address %} -{% endif %} -{% endif %} -{% endif %} -{% set trns_port = ':' + config.translation.port if config.translation is defined and config.translation.port is defined and config.translation.port is not none %} -{# protocol has a default value thus it is always present #} -{% if config.protocol == 'tcp_udp' %} -{% set protocol = 'tcp' %} -{% set comment = comment + ' tcp_udp' %} -{% else %} -{% set protocol = config.protocol %} -{% endif %} -{% if config.log is defined %} -{% if config.exclude is defined %} -{% set log = base_log + '-EXCL]' %} -{% elif config.translation is defined and config.translation.address is defined and config.translation.address == 'masquerade' %} -{% set log = base_log +'-MASQ]' %} -{% else %} -{% set log = base_log + ']' %} -{% endif %} -{% endif %} -{% if config.exclude is defined %} -{# rule has been marked as 'exclude' thus we simply return here #} -{% set trns_addr = 'return' %} -{% set trns_port = '' %} -{% endif %} -{# T1083: NAT address and port translation options #} -{% if config.translation is defined and config.translation.options is defined and config.translation.options is not none %} -{% if config.translation.options.address_mapping is defined and config.translation.options.address_mapping == "persistent" %} -{% set trns_opts_addr = 'persistent' %} -{% endif %} -{% if config.translation.options.port_mapping is defined %} -{% if config.translation.options.port_mapping == "random" %} -{% set trns_opts_port = 'random' %} -{% elif config.translation.options.port_mapping == "fully-random" %} -{% set trns_opts_port = 'fully-random' %} -{% endif %} -{% endif %} -{% endif %} -{% if trns_opts_addr and trns_opts_port %} -{% set trns_opts = trns_opts_addr + ',' + trns_opts_port %} -{% elif trns_opts_addr %} -{% set trns_opts = trns_opts_addr %} -{% elif trns_opts_port %} -{% set trns_opts = trns_opts_port %} -{% endif %} -{% set output = 'add rule ip nat ' + chain + interface %} -{% if protocol != 'all' %} -{% set output = output + ' ip protocol ' + protocol %} -{% endif %} -{% if src_addr %} -{% set output = output + ' ' + src_addr %} -{% endif %} -{% if src_port %} -{% set output = output + ' ' + protocol + ' ' + src_port %} -{% endif %} -{% if dst_addr %} -{% set output = output + ' ' + dst_addr %} -{% endif %} -{% if dst_port %} -{% set output = output + ' ' + protocol + ' ' + dst_port %} -{% endif %} -{# Count packets #} -{% set output = output + ' counter' %} -{# Special handling of log option, we must repeat the entire rule before the #} -{# NAT translation options are added, this is essential #} -{% if log %} -{% set log_output = output + ' log prefix "' + log + '" comment "' + comment + '"' %} -{% endif %} -{% if trns_addr %} -{% set output = output + ' ' + trns_addr %} -{% endif %} -{% if trns_port %} -{# Do not add a whitespace here, translation port must be directly added after IP address #} -{# e.g. 192.0.2.10:3389 #} -{% set output = output + trns_port %} -{% endif %} -{% if trns_opts %} -{% set output = output + ' ' + trns_opts %} -{% endif %} -{% if comment %} -{% set output = output + ' comment "' + comment + '"' %} -{% endif %} -{{ log_output if log_output }} -{{ output }} -{# Special handling if protocol is tcp_udp, we must repeat the entire rule with udp as protocol #} -{% if config.protocol == 'tcp_udp' %} -{# Beware of trailing whitespace, without it the comment tcp_udp will be changed to udp_udp #} -{{ log_output | replace('tcp ', 'udp ') if log_output }} -{{ output | replace('tcp ', 'udp ') }} -{% endif %} -{% endmacro %} - -# Start with clean NAT table -flush table ip nat -{% if helper_functions == 'remove' %} -{# NAT if going to be disabled - remove rules and targets from nftables #} -{% set base_command = 'delete rule ip raw' %} -{{ base_command }} PREROUTING handle {{ pre_ct_ignore }} -{{ base_command }} OUTPUT handle {{ out_ct_ignore }} -{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }} -{{ base_command }} OUTPUT handle {{ out_ct_conntrack }} - -delete chain ip raw NAT_CONNTRACK - -{% elif helper_functions == 'add' %} -{# NAT if enabled - add targets to nftables #} -add chain ip raw NAT_CONNTRACK -add rule ip raw NAT_CONNTRACK counter accept -{% set base_command = 'add rule ip raw' %} -{{ base_command }} PREROUTING position {{ pre_ct_ignore }} counter jump VYATTA_CT_HELPER -{{ base_command }} OUTPUT position {{ out_ct_ignore }} counter jump VYATTA_CT_HELPER -{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK -{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK -{% endif %} - -# -# Destination NAT rules build up here -# -{% if destination is defined and destination.rule is defined and destination.rule is not none %} -{% for rule, config in destination.rule.items() if config.disable is not defined %} -{{ nat_rule(rule, config, 'PREROUTING') }} -{% endfor %} -{% endif %} -# -# Source NAT rules build up here -# -{% if source is defined and source.rule is defined and source.rule is not none %} -{% for rule, config in source.rule.items() if config.disable is not defined %} -{{ nat_rule(rule, config, 'POSTROUTING') }} -{% endfor %} -{% endif %} diff --git a/data/templates/firewall/nftables-nat66.j2 b/data/templates/firewall/nftables-nat66.j2 new file mode 100644 index 000000000..003b138b2 --- /dev/null +++ b/data/templates/firewall/nftables-nat66.j2 @@ -0,0 +1,102 @@ +#!/usr/sbin/nft -f + +{% macro nptv6_rule(rule,config, chain) %} +{% set comment = '' %} +{% set base_log = '' %} +{% set src_prefix = 'ip6 saddr ' ~ config.source.prefix if config.source.prefix is vyos_defined %} +{% set dest_address = 'ip6 daddr ' ~ config.destination.address if config.destination.address is vyos_defined %} +{% if chain is vyos_defined('PREROUTING') %} +{% set comment = 'DST-NAT66-' ~ rule %} +{% set base_log = '[NAT66-DST-' ~ rule %} +{% set interface = ' iifname "' ~ config.inbound_interface ~ '"' if config.inbound_interface is vyos_defined and config.inbound_interface is not vyos_defined('any') else '' %} +{% if config.translation.address | is_ip_network %} +{# support 1:1 network translation #} +{% set dnat_type = 'dnat prefix to ' %} +{% else %} +{% set dnat_type = 'dnat to ' %} +{% endif %} +{% set trns_address = dnat_type ~ config.translation.address if config.translation.address is vyos_defined %} +{% elif chain is vyos_defined('POSTROUTING') %} +{% set comment = 'SRC-NAT66-' ~ rule %} +{% set base_log = '[NAT66-SRC-' ~ rule %} +{% if config.translation.address is vyos_defined %} +{% if config.translation.address is vyos_defined('masquerade') %} +{% set trns_address = config.translation.address %} +{% else %} +{% if config.translation.address | is_ip_network %} +{# support 1:1 network translation #} +{% set snat_type = 'snat prefix to ' %} +{% else %} +{% set snat_type = 'snat to ' %} +{% endif %} +{% set trns_address = snat_type ~ config.translation.address %} +{% endif %} +{% endif %} +{% set interface = ' oifname "' ~ config.outbound_interface ~ '"' if config.outbound_interface is vyos_defined else '' %} +{% endif %} +{% if config.log is vyos_defined %} +{% if config.translation.address is vyos_defined('masquerade') %} +{% set log = base_log ~ '-MASQ]' %} +{% else %} +{% set log = base_log ~ ']' %} +{% endif %} +{% endif %} +{% set output = 'add rule ip6 nat ' ~ chain ~ interface %} +{# Count packets #} +{% set output = output ~ ' counter' %} +{# Special handling of log option, we must repeat the entire rule before the #} +{# NAT translation options are added, this is essential #} +{% if log is vyos_defined %} +{% set log_output = output ~ ' log prefix "' ~ log ~ '" comment "' ~ comment ~ '"' %} +{% endif %} +{% if src_prefix is vyos_defined %} +{% set output = output ~ ' ' ~ src_prefix %} +{% endif %} +{% if dest_address is vyos_defined %} +{% set output = output ~ ' ' ~ dest_address %} +{% endif %} +{% if trns_address is vyos_defined %} +{% set output = output ~ ' ' ~ trns_address %} +{% endif %} +{% if comment is vyos_defined %} +{% set output = output ~ ' comment "' ~ comment ~ '"' %} +{% endif %} +{{ log_output if log_output is vyos_defined }} +{{ output }} +{% endmacro %} + +# Start with clean NAT table +flush table ip6 nat +{% if helper_functions is vyos_defined('remove') %} +{# NAT if going to be disabled - remove rules and targets from nftables #} +{% set base_command = 'delete rule ip6 raw' %} +{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }} +{{ base_command }} OUTPUT handle {{ out_ct_conntrack }} + +delete chain ip6 raw NAT_CONNTRACK + +{% elif helper_functions is vyos_defined('add') %} +{# NAT if enabled - add targets to nftables #} +add chain ip6 raw NAT_CONNTRACK +add rule ip6 raw NAT_CONNTRACK counter accept +{% set base_command = 'add rule ip6 raw' %} +{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK +{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK +{% endif %} + +# +# Destination NAT66 rules build up here +# +{% if destination.rule is vyos_defined %} +{% for rule, config in destination.rule.items() if config.disable is not vyos_defined %} +{{ nptv6_rule(rule, config, 'PREROUTING') }} +{% endfor %} +{% endif %} +# +# Source NAT66 rules build up here +# +{% if source.rule is vyos_defined %} +{% for rule, config in source.rule.items() if config.disable is not vyos_defined %} +{{ nptv6_rule(rule, config, 'POSTROUTING') }} +{% endfor %} +{% endif %} diff --git a/data/templates/firewall/nftables-nat66.tmpl b/data/templates/firewall/nftables-nat66.tmpl deleted file mode 100644 index e5c1b1b8d..000000000 --- a/data/templates/firewall/nftables-nat66.tmpl +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/sbin/nft -f - -{% macro nptv6_rule(rule,config, chain) %} -{% set comment = '' %} -{% set base_log = '' %} -{% set src_prefix = "ip6 saddr " + config.source.prefix if config.source is defined and config.source.prefix is defined and config.source.prefix is not none %} -{% set dest_address = "ip6 daddr " + config.destination.address if config.destination is defined and config.destination.address is defined and config.destination.address is not none %} -{% if chain == "PREROUTING" %} -{% set comment = "DST-NAT66-" + rule %} -{% set base_log = '[NAT66-DST-' + rule %} -{% set interface = " iifname \"" + config.inbound_interface + "\"" if config.inbound_interface is defined and config.inbound_interface != 'any' else '' %} -{% if config.translation.address | is_ip_network %} -{# support 1:1 network translation #} -{% set dnat_type = "dnat prefix to " %} -{% else %} -{% set dnat_type = "dnat to " %} -{% endif %} -{% set trns_address = dnat_type + config.translation.address if config.translation is defined and config.translation.address is defined and config.translation.address is not none %} -{% elif chain == "POSTROUTING" %} -{% set comment = 'SRC-NAT66-' + rule %} -{% set base_log = '[NAT66-SRC-' + rule %} -{% if config.translation is defined and config.translation.address is defined and config.translation.address is not none %} -{% if config.translation.address == 'masquerade' %} -{% set trns_address = config.translation.address %} -{% else %} -{% if config.translation.address | is_ip_network %} -{# support 1:1 network translation #} -{% set snat_type = "snat prefix to " %} -{% else %} -{% set snat_type = "snat to " %} -{% endif %} -{% set trns_address = snat_type + config.translation.address %} -{% endif %} -{% endif %} -{% set interface = " oifname \"" + config.outbound_interface + "\"" if config.outbound_interface is defined else '' %} -{% endif %} -{% if config.log is defined %} -{% if config.translation is defined and config.translation.address is defined and config.translation.address == 'masquerade' %} -{% set log = base_log +'-MASQ]' %} -{% else %} -{% set log = base_log + "]" %} -{% endif %} -{% endif %} -{% set output = "add rule ip6 nat " + chain + interface %} -{# Count packets #} -{% set output = output + " counter" %} -{# Special handling of log option, we must repeat the entire rule before the #} -{# NAT translation options are added, this is essential #} -{% if log %} -{% set log_output = output + " log prefix \"" + log + "\" comment \"" + comment + "\"" %} -{% endif %} -{% if src_prefix %} -{% set output = output + " " + src_prefix %} -{% endif %} -{% if dest_address %} -{% set output = output + " " + dest_address %} -{% endif %} -{% if trns_address %} -{% set output = output + " " + trns_address %} -{% endif %} -{% if comment %} -{% set output = output + " comment \"" + comment + "\"" %} -{% endif %} -{{ log_output if log_output }} -{{ output }} -{% endmacro %} - -# Start with clean NAT table -flush table ip6 nat -{% if helper_functions == 'remove' %} -{# NAT if going to be disabled - remove rules and targets from nftables #} -{% set base_command = "delete rule ip6 raw" %} -{{base_command}} PREROUTING handle {{ pre_ct_conntrack }} -{{base_command}} OUTPUT handle {{ out_ct_conntrack }} - -delete chain ip6 raw NAT_CONNTRACK - -{% elif helper_functions == 'add' %} -{# NAT if enabled - add targets to nftables #} -add chain ip6 raw NAT_CONNTRACK -add rule ip6 raw NAT_CONNTRACK counter accept -{% set base_command = "add rule ip6 raw" %} -{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK -{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK -{% endif %} - -# -# Destination NAT66 rules build up here -# -{% if destination is defined and destination.rule is defined and destination.rule is not none %} -{% for rule, config in destination.rule.items() if config.disable is not defined %} -{{ nptv6_rule(rule, config, 'PREROUTING') }} -{% endfor %} -{% endif %} -# -# Source NAT66 rules build up here -# -{% if source is defined and source.rule is defined and source.rule is not none %} -{% for rule, config in source.rule.items() if config.disable is not defined %} -{{ nptv6_rule(rule, config, 'POSTROUTING') }} -{% endfor %} -{% endif %} diff --git a/data/templates/firewall/nftables-policy.j2 b/data/templates/firewall/nftables-policy.j2 new file mode 100644 index 000000000..0154c9f7e --- /dev/null +++ b/data/templates/firewall/nftables-policy.j2 @@ -0,0 +1,55 @@ +#!/usr/sbin/nft -f + +{% if cleanup_commands is vyos_defined %} +{% for command in cleanup_commands %} +{{ command }} +{% endfor %} +{% endif %} + +include "/run/nftables_defines.conf" + +table ip mangle { +{% if first_install is vyos_defined %} + chain VYOS_PBR_PREROUTING { + type filter hook prerouting priority -150; policy accept; + } + chain VYOS_PBR_POSTROUTING { + type filter hook postrouting priority -150; policy accept; + } +{% endif %} +{% if route is vyos_defined %} +{% for route_text, conf in route.items() %} + chain VYOS_PBR_{{ 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_text, rule_id, 'ip') }} +{% endfor %} +{% endif %} + {{ conf | nft_default_rule(route_text) }} + } +{% endfor %} +{% endif %} +} + +table ip6 mangle { +{% if first_install is vyos_defined %} + chain VYOS_PBR6_PREROUTING { + type filter hook prerouting priority -150; policy accept; + } + chain VYOS_PBR6_POSTROUTING { + type filter hook postrouting priority -150; policy accept; + } +{% endif %} +{% if route6 is vyos_defined %} +{% for route_text, conf in route6.items() %} + chain VYOS_PBR6_{{ 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_text, rule_id, 'ip6') }} +{% endfor %} +{% endif %} + {{ conf | nft_default_rule(route_text) }} + } +{% endfor %} +{% endif %} +} diff --git a/data/templates/firewall/nftables-vrf-zones.tmpl b/data/templates/firewall/nftables-vrf-zones.j2 index eecf47b78..eecf47b78 100644 --- a/data/templates/firewall/nftables-vrf-zones.tmpl +++ b/data/templates/firewall/nftables-vrf-zones.j2 diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2 new file mode 100644 index 000000000..fac3fad03 --- /dev/null +++ b/data/templates/firewall/nftables.j2 @@ -0,0 +1,274 @@ +#!/usr/sbin/nft -f + +{% if cleanup_commands is vyos_defined %} +{% for command in cleanup_commands %} +{{ command }} +{% endfor %} +{% endif %} + +include "/run/nftables_defines.conf" + +table ip filter { +{% if first_install is vyos_defined %} + chain VYOS_FW_FORWARD { + type filter hook forward priority 0; policy accept; + jump VYOS_POST_FW + } + chain VYOS_FW_LOCAL { + type filter hook input priority 0; policy accept; + jump VYOS_POST_FW + } + chain VYOS_FW_OUTPUT { + type filter hook output priority 0; policy accept; + jump VYOS_POST_FW + } + chain VYOS_POST_FW { + return + } + chain VYOS_FRAG_MARK { + type filter hook prerouting priority -450; policy accept; + ip frag-off & 0x3fff != 0 meta mark set 0xffff1 return + } +{% endif %} +{% if name is vyos_defined %} +{% set ns = namespace(sets=[]) %} +{% for name_text, conf in 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(name_text, rule_id) }} +{% if rule_conf.recent is vyos_defined %} +{% set ns.sets = ns.sets + [name_text + '_' + rule_id] %} +{% endif %} +{% endfor %} +{% endif %} + {{ conf | nft_default_rule(name_text) }} + } +{% endfor %} +{% for set_name in ns.sets %} + set RECENT_{{ set_name }} { + type ipv4_addr + size 65535 + flags dynamic + } +{% endfor %} +{% endif %} +{% if state_policy is vyos_defined %} + chain VYOS_STATE_POLICY { +{% if state_policy.established is vyos_defined %} + {{ state_policy.established | nft_state_policy('established') }} +{% endif %} +{% if state_policy.invalid is vyos_defined %} + {{ state_policy.invalid | nft_state_policy('invalid') }} +{% endif %} +{% if state_policy.related is vyos_defined %} + {{ state_policy.related | nft_state_policy('related') }} +{% endif %} + return + } +{% endif %} +} + +table ip6 filter { +{% if first_install is vyos_defined %} + chain VYOS_FW6_FORWARD { + type filter hook forward priority 0; policy accept; + jump VYOS_POST_FW6 + } + chain VYOS_FW6_LOCAL { + type filter hook input priority 0; policy accept; + jump VYOS_POST_FW6 + } + chain VYOS_FW6_OUTPUT { + type filter hook output priority 0; policy accept; + jump VYOS_POST_FW6 + } + chain VYOS_POST_FW6 { + return + } + chain VYOS_FRAG6_MARK { + type filter hook prerouting priority -450; policy accept; + exthdr frag exists meta mark set 0xffff1 return + } +{% endif %} +{% if ipv6_name is vyos_defined %} +{% set ns = namespace(sets=[]) %} +{% 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(name_text, rule_id, 'ip6') }} +{% if rule_conf.recent is vyos_defined %} +{% set ns.sets = ns.sets + [name_text + '_' + rule_id] %} +{% endif %} +{% endfor %} +{% endif %} + {{ conf | nft_default_rule(name_text) }} + } +{% endfor %} +{% for set_name in ns.sets %} + set RECENT6_{{ set_name }} { + type ipv6_addr + size 65535 + flags dynamic + } +{% endfor %} +{% endif %} +{% if state_policy is vyos_defined %} + chain VYOS_STATE_POLICY6 { +{% if state_policy.established is vyos_defined %} + {{ state_policy.established | nft_state_policy('established', ipv6=True) }} +{% endif %} +{% if state_policy.invalid is vyos_defined %} + {{ state_policy.invalid | nft_state_policy('invalid', ipv6=True) }} +{% endif %} +{% if state_policy.related is vyos_defined %} + {{ state_policy.related | nft_state_policy('related', ipv6=True) }} +{% endif %} + return + } +{% endif %} +} + +{% if first_install is vyos_defined %} +table ip nat { + chain PREROUTING { + type nat hook prerouting priority -100; policy accept; + counter jump VYOS_PRE_DNAT_HOOK + } + + chain POSTROUTING { + type nat hook postrouting priority 100; policy accept; + counter jump VYOS_PRE_SNAT_HOOK + } + + chain VYOS_PRE_DNAT_HOOK { + return + } + + chain VYOS_PRE_SNAT_HOOK { + return + } +} + +table ip6 nat { + chain PREROUTING { + type nat hook prerouting priority -100; policy accept; + counter jump VYOS_DNPT_HOOK + } + + chain POSTROUTING { + type nat hook postrouting priority 100; policy accept; + counter jump VYOS_SNPT_HOOK + } + + chain VYOS_DNPT_HOOK { + return + } + + chain VYOS_SNPT_HOOK { + return + } +} + +table inet mangle { + chain FORWARD { + type filter hook forward priority -150; policy accept; + } +} + +table raw { + chain VYOS_TCP_MSS { + type filter hook forward priority -300; policy accept; + } + + chain PREROUTING { + type filter hook prerouting priority -200; policy accept; + counter jump VYOS_CT_IGNORE + counter jump VYOS_CT_TIMEOUT + counter jump VYOS_CT_PREROUTING_HOOK + counter jump FW_CONNTRACK + notrack + } + + chain OUTPUT { + type filter hook output priority -200; policy accept; + counter jump VYOS_CT_IGNORE + counter jump VYOS_CT_TIMEOUT + counter jump VYOS_CT_OUTPUT_HOOK + counter jump FW_CONNTRACK + notrack + } + + ct helper rpc_tcp { + type "rpc" protocol tcp; + } + + ct helper rpc_udp { + type "rpc" protocol udp; + } + + ct helper tns_tcp { + type "tns" protocol tcp; + } + + chain VYOS_CT_HELPER { + ct helper set "rpc_tcp" tcp dport {111} return + ct helper set "rpc_udp" udp dport {111} return + ct helper set "tns_tcp" tcp dport {1521,1525,1536} return + return + } + + chain VYOS_CT_IGNORE { + return + } + + chain VYOS_CT_TIMEOUT { + return + } + + chain VYOS_CT_PREROUTING_HOOK { + return + } + + chain VYOS_CT_OUTPUT_HOOK { + return + } + + chain FW_CONNTRACK { + accept + } +} + +table ip6 raw { + chain VYOS_TCP_MSS { + type filter hook forward priority -300; policy accept; + } + + chain PREROUTING { + type filter hook prerouting priority -300; policy accept; + counter jump VYOS_CT_PREROUTING_HOOK + counter jump FW_CONNTRACK + notrack + } + + chain OUTPUT { + type filter hook output priority -300; policy accept; + counter jump VYOS_CT_OUTPUT_HOOK + counter jump FW_CONNTRACK + notrack + } + + chain VYOS_CT_PREROUTING_HOOK { + return + } + + chain VYOS_CT_OUTPUT_HOOK { + return + } + + chain FW_CONNTRACK { + accept + } +} +{% endif %} diff --git a/data/templates/firewall/upnpd.conf.j2 b/data/templates/firewall/upnpd.conf.j2 new file mode 100644 index 000000000..27573cbf9 --- /dev/null +++ b/data/templates/firewall/upnpd.conf.j2 @@ -0,0 +1,172 @@ +# This is the UPNP configuration file + +# WAN network interface +ext_ifname={{ wan_interface }} +{% if wan_ip is vyos_defined %} +# If the WAN interface has several IP addresses, you +# can specify the one to use below +{% for addr in wan_ip %} +ext_ip={{ addr }} +{% endfor %} +{% endif %} + +# LAN network interfaces IPs / networks +{% if listen is vyos_defined %} +# There can be multiple listening IPs for SSDP traffic, in that case +# use multiple 'listening_ip=...' lines, one for each network interface. +# It can be IP address or network interface name (ie. "eth0") +# It is mandatory to use the network interface name in order to enable IPv6 +# HTTP is available on all interfaces. +# When MULTIPLE_EXTERNAL_IP is enabled, the external IP +# address associated with the subnet follows. For example: +# listening_ip=192.168.0.1/24 88.22.44.13 +{% for addr in listen %} +{% if addr | is_ipv4 %} +listening_ip={{ addr }} +{% elif addr | is_ipv6 %} +ipv6_listening_ip={{ addr }} +{% else %} +listening_ip={{ addr }} +{% endif %} +{% endfor %} +{% endif %} + +# CAUTION: mixing up WAN and LAN interfaces may introduce security risks! +# Be sure to assign the correct interfaces to LAN and WAN and consider +# implementing UPnP permission rules at the bottom of this configuration file + +# Port for HTTP (descriptions and SOAP) traffic. Set to 0 for autoselect. +#http_port=0 +# Port for HTTPS. Set to 0 for autoselect (default) +#https_port=0 + +# Path to the UNIX socket used to communicate with MiniSSDPd +# If running, MiniSSDPd will manage M-SEARCH answering. +# default is /var/run/minissdpd.sock +#minissdpdsocket=/var/run/minissdpd.sock + +{% if nat_pmp is vyos_defined %} +# Enable NAT-PMP support (default is no) +enable_natpmp=yes +{% endif %} + +# Enable UPNP support (default is yes) +enable_upnp=yes + +{% if pcp_lifetime is vyos_defined %} +# PCP +# Configure the minimum and maximum lifetime of a port mapping in seconds +# 120s and 86400s (24h) are suggested values from PCP-base +{% if pcp_lifetime.max is vyos_defined %} +max_lifetime={{ pcp_lifetime.max }} +{% endif %} +{% if pcp_lifetime.min is vyos_defined %} +min_lifetime={{ pcp_lifetime.min }} +{% endif %} +{% endif %} + + +# To enable the next few runtime options, see compile time +# ENABLE_MANUFACTURER_INFO_CONFIGURATION (config.h) + +{% if friendly_name is vyos_defined %} +# Name of this service, default is "`uname -s` router" +friendly_name= {{ friendly_name }} +{% endif %} + +# Manufacturer name, default is "`uname -s`" +manufacturer_name=VyOS + +# Manufacturer URL, default is URL of OS vendor +manufacturer_url=https://vyos.io/ + +# Model name, default is "`uname -s` router" +model_name=VyOS Router Model + +# Model description, default is "`uname -s` router" +model_description=Vyos open source enterprise router/firewall operating system + +# Model URL, default is URL of OS vendor +model_url=https://vyos.io/ + +{% if secure_mode is vyos_defined %} +# Secure Mode, UPnP clients can only add mappings to their own IP +secure_mode=yes +{% else %} +# Secure Mode, UPnP clients can only add mappings to their own IP +secure_mode=no +{% endif %} + +{% if presentation_url is vyos_defined %} +# Default presentation URL is HTTP address on port 80 +# If set to an empty string, no presentationURL element will appear +# in the XML description of the device, which prevents MS Windows +# from displaying an icon in the "Network Connections" panel. +#presentation_url= {{ presentation_url }} +{% endif %} + +# Report system uptime instead of daemon uptime +system_uptime=yes + +# Unused rules cleaning. +# never remove any rule before this threshold for the number +# of redirections is exceeded. default to 20 +clean_ruleset_threshold=10 +# Clean process work interval in seconds. default to 0 (disabled). +# a 600 seconds (10 minutes) interval makes sense +clean_ruleset_interval=600 + +# Anchor name in pf (default is miniupnpd) +anchor=VyOS + +uuid={{ uuid }} + +# Lease file location +lease_file=/config/upnp.leases + +# Daemon's serial and model number when reporting to clients +# (in XML description) +#serial=12345678 +#model_number=1 + +{% if rules is vyos_defined %} +# UPnP permission rules +# (allow|deny) (external port range) IP/mask (internal port range) +# A port range is <min port>-<max port> or <port> if there is only +# one port in the range. +# IP/mask format must be nnn.nnn.nnn.nnn/nn +# It is advised to only allow redirection of port >= 1024 +# and end the rule set with "deny 0-65535 0.0.0.0/0 0-65535" +# The following default ruleset allows specific LAN side IP addresses +# to request only ephemeral ports. It is recommended that users +# modify the IP ranges to match their own internal networks, and +# also consider implementing network-specific restrictions +# CAUTION: failure to enforce any rules may permit insecure requests to be made! +{% for rule, config in rules.items() %} +{% if config.disable is vyos_defined %} +{{ config.action }} {{ config.external_port_range }} {{ config.ip }} {{ config.internal_port_range }} +{% endif %} +{% endfor %} +{% endif %} + +{% if stun is vyos_defined %} +# WAN interface must have public IP address. Otherwise it is behind NAT +# and port forwarding is impossible. In some cases WAN interface can be +# behind unrestricted NAT 1:1 when all incoming traffic is NAT-ed and +# routed to WAN interfaces without any filtering. In this cases miniupnpd +# needs to know public IP address and it can be learnt by asking external +# server via STUN protocol. Following option enable retrieving external +# public IP address from STUN server and detection of NAT type. You need +# to specify also external STUN server in stun_host option below. +# This option is disabled by default. +ext_perform_stun=yes +# Specify STUN server, either hostname or IP address +# Some public STUN servers: +# stun.stunprotocol.org +# stun.sipgate.net +# stun.xten.com +# stun.l.google.com (on non standard port 19302) +ext_stun_host={{ stun.host }} +# Specify STUN UDP port, by default it is standard port 3478. +ext_stun_port={{ stun.port }} +{% endif %} |