From 6f349ee3b4d3da731ca22a70db6650848a0c28d9 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 16 May 2020 16:16:09 +0200 Subject: nat: T2198: use Jinja2 macro for common ruleset for SNAT and DNAT By using a Jinja2 macro the same template code can be used to create both source and destination NAT rules with only minor changes introduced by e.g. the used chain (POSTROUTING vs PREROUTING). Used the following configuration for testing on two systems with VyOS 1.2 and the old implementation vs the new one here. set nat destination rule 15 description 'foo-10' set nat destination rule 15 destination address '1.1.1.1' set nat destination rule 15 inbound-interface 'eth0.202' set nat destination rule 15 protocol 'tcp_udp' set nat destination rule 15 translation address '192.0.2.10' set nat destination rule 15 translation port '3389' set nat destination rule 20 description 'foo-20' set nat destination rule 20 destination address '2.2.2.2' set nat destination rule 20 destination port '22' set nat destination rule 20 inbound-interface 'eth0.201' set nat destination rule 20 protocol 'tcp' set nat destination rule 20 translation address '192.0.2.10' set nat source rule 100 outbound-interface 'eth0.202' set nat source rule 100 protocol 'all' set nat source rule 100 source address '192.0.2.0/26' set nat source rule 100 translation address 'masquerade' set nat source rule 110 outbound-interface 'eth0.202' set nat source rule 110 protocol 'tcp' set nat source rule 110 source address '192.0.2.0/26' set nat source rule 110 source port '5556' set nat source rule 110 translation address 'masquerade' set nat source rule 120 outbound-interface 'eth0.202' set nat source rule 120 protocol 'tcp_udp' set nat source rule 120 source address '192.0.3.0/26' set nat source rule 120 translation address '2.2.2.2' --- data/templates/firewall/nftables-nat.tmpl | 138 +++++++++++------------------- 1 file changed, 50 insertions(+), 88 deletions(-) (limited to 'data') diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl index 5ce110d82..abb32ddc6 100644 --- a/data/templates/firewall/nftables-nat.tmpl +++ b/data/templates/firewall/nftables-nat.tmpl @@ -27,69 +27,76 @@ add rule ip raw NAT_CONNTRACK counter accept {{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK {% endif %} -# -# Destination NAT rules build up here -# -{% for r in destination if not r.disabled -%} -{% set chain = "PREROUTING" %} -{% set src_addr = "ip saddr " + r.source_address if r.source_address %} -{% set src_port = "sport { " + r.source_port +" }" if r.source_port %} -{% set dst_addr = "ip daddr " + r.dest_address if r.dest_address %} -{% set dst_port = "dport { " + r.dest_port +" }" if r.dest_port %} -{% set trns_addr = "dnat to " + r.translation_address %} -{% set trns_port = ":" + r.translation_port if r.translation_port %} -{% set interface = " iifname \"" + r.interface_in + "\"" %} -{% set comment = "DST-NAT-" + r.number %} - -{% if r.protocol == "tcp_udp" %} +{% macro nat_rule(rule, chain) %} +{% set src_addr = "ip saddr " + rule.source_address if rule.source_address %} +{% set src_port = "sport { " + rule.source_port +" }" if rule.source_port %} +{% set dst_addr = "ip daddr " + rule.dest_address if rule.dest_address %} +{% set dst_port = "dport { " + rule.dest_port +" }" if rule.dest_port %} +{% set comment = "DST-NAT-" + rule.number %} + +{% if chain == "PREROUTING" %} +{% set interface = " iifname \"" + rule.interface_in + "\"" %} +{% set trns_addr = "dnat to " + rule.translation_address %} +{% elif chain == "POSTROUTING" %} +{% set interface = " oifname \"" + rule.interface_out + "\"" %} +{% set trns_addr = rule.translation_address %} +{% if rule.translation_address != 'masquerade' %} +{% set trns_addr = "snat to " + trns_addr %} +{% endif %} +{% endif %} +{% set trns_port = ":" + rule.translation_port if rule.translation_port %} + +{% if rule.protocol == "tcp_udp" %} {% set protocol = "tcp" %} {% set comment = comment + " tcp_udp" %} {% else %} -{% set protocol = r.protocol %} +{% set protocol = rule.protocol %} {% endif %} -{% if r.log %} -{% set base_log = "[NAT-DST-" + r.number %} -{% if r.exclude %} +{% if rule.log %} +{% set base_log = "[NAT-DST-" + rule.number %} +{% if rule.exclude %} {% set log = base_log + "-EXCL]" %} -{% elif r.translation_address == 'masquerade' %} +{% elif rule.translation_address == 'masquerade' %} {% set log = base_log + "-MASQ]" %} {% else %} {% set log = base_log + "]" %} {% endif %} {% endif %} -{% if r.exclude %} +{% if rule.exclude %} {# rule has been marked as "exclude" thus we simply return here #} {% set trns_addr = "return" %} {% set trns_port = "" %} {% endif %} -{% set output = "add rule ip nat " + chain + interface + " counter" %} -{% set output = output + " comment \"" + comment + "\"" %} +{% 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 + " " + 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 %} -{% else %} -{% set output = output + " ip protocol " + protocol %} {% 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 + "\"" %} +{% set log_output = output + " log prefix \"" + log + "\" comment \"" + comment + "\"" %} {% endif %} {% if trns_addr %} @@ -102,76 +109,31 @@ add rule ip raw NAT_CONNTRACK counter accept {% set output = output + trns_port %} {% 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 r.protocol == "tcp_udp" %} +{% if rule.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 %} -{% endfor %} - - +{% endmacro %} +# +# Destination NAT rules build up here +# +{% for rule in destination if not rule.disabled -%} +{{ nat_rule(rule, 'PREROUTING') }} +{% endfor %} # # Source NAT rules build up here # -{% for r in source if not r.disabled -%} -{% set chain = "POSTROUTING" %} -{% set src_addr = "ip saddr " + r.source_address if r.source_address %} -{% set src_port = "sport { " + r.source_port +" }" if r.source_port %} -{% set dst_addr = "ip daddr " + r.dest_address if r.dest_address %} -{% set dst_port = "dport { " + r.dest_port +" }" if r.dest_port %} -{% set trns_addr = "snat to " + r.translation_address if r.translation_address != "masquerade" else "masquerade" %} -{% set trns_port = ":" + r.translation_port if r.translation_port %} -{% set comment = "SRC-NAT-" + r.number %} -{% set iface = r.interface_out %} - -{% if r.log %} -{% if r.exclude %} -{% set log = "[" + comment + "-EXCL]" %} -{% elif r.translation_address == 'masquerade' %} -{% set log = "[" + comment + "-MASQ]" %} -{% else %} -{% set log = "[" + comment + "]" %} -{% endif %} -{% endif %} - -{% if r.exclude %} -{# rule has been marked as "exclude" thus we simply return here #} -{% set trns_addr = "return" %} -{% set trns_port = "" %} -{% endif %} - -{% if r.protocol == 'tcp_udp' %} -{# Special handling for protocol tcp_udp which is represented as two individual rules #} -{% set comment = comment + " tcp_udp" %} -{% if log %} - -{% set tcp_dst_port = "tcp " + dst_port if dst_port else "ip protocol tcp" %} -{% set udp_dst_port = "udp " + dst_port if dst_port else "ip protocol udp" %} -{% set tcp_src_port = "tcp " + src_port if src_port %} -{% set udp_src_port = "udp " + src_port if src_port %} - -add rule ip nat {{ chain }} oifname "{{ iface }}" {{ tcp_src_port }} {{ src_port }} {{ tcp_dst_port }} {{ dst_addr }} counter log prefix "{{ log }}" comment "{{ comment }}" -{% endif %} -add rule ip nat {{ chain }} oifname "{{ iface }}" {{ tcp_src_port }} {{ src_port }} {{ tcp_dst_port }} {{ dst_addr }} counter {{ trns_addr }}{{ trns_port }} comment "{{ comment }}" -{% if log %} -add rule ip nat {{ chain }} oifname "{{ iface }}" {{ udp_src_port }} {{ src_port }} {{ udp_dst_port }} {{ dst_addr }} counter log prefix "{{ log }}" comment "{{ comment }}" -{% endif %} -add rule ip nat {{ chain }} oifname "{{ iface }}" {{ udp_src_port }} {{ src_port }} {{ udp_dst_port }} {{ dst_addr }} counter {{ trns_addr }}{{ trns_port }} comment "{{ comment }}" - -{% else %} -{% set proto_dst_port = dst_port if dst_port else "ip protocol " + r.protocol %} -{% set proto_dst_port = proto_dst_port if r.protocol != "all" %} -{% set proto_src_port = r.protocol + " " + src_port if r.protocol != "all" else src_port %} - -{% if log %} -add rule ip nat {{ chain }} oifname "{{ iface }}" {{ src_addr }} {{ proto_src_port }} {{ proto_dst_port }} {{ dst_addr }} counter log prefix "{{ log }}" comment "{{ comment }}" -{% endif %} -add rule ip nat {{ chain }} oifname "{{ iface }}" {{ src_addr }} {{ proto_src_port }} {{ proto_dst_port }} {{ dst_addr }} counter {{ trns_addr }}{{ trns_port }} comment "{{ comment }}" -{% endif %} +{% for rule in source if not rule.disabled -%} +{{ nat_rule(rule, 'POSTROUTING') }} {% endfor %} -- cgit v1.2.3