From b752c8779712ec4e1c3b653081768361359c57f7 Mon Sep 17 00:00:00 2001
From: Viacheslav Hletenko <v.gletenko@vyos.io>
Date: Sat, 20 Aug 2022 16:26:55 +0000
Subject: nat66: T4631: Add port and protocol to nat66

Ability to configure src/dst/translation port and protocol for
SNAT and DNAT IPv6
---
 data/templates/firewall/nftables-nat66.j2 | 41 +++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

(limited to 'data')

diff --git a/data/templates/firewall/nftables-nat66.j2 b/data/templates/firewall/nftables-nat66.j2
index 2fe04b4ff..28714c7a7 100644
--- a/data/templates/firewall/nftables-nat66.j2
+++ b/data/templates/firewall/nftables-nat66.j2
@@ -7,6 +7,17 @@
 {% set src_prefix  = 'ip6 saddr ' ~ config.source.prefix.replace('!','!= ') if config.source.prefix is vyos_defined %}
 {% set source_address  = 'ip6 saddr ' ~ config.source.address.replace('!','!= ') if config.source.address is vyos_defined %}
 {% set dest_address  = 'ip6 daddr ' ~ config.destination.address.replace('!','!= ') if config.destination.address is vyos_defined %}
+{# Port #}
+{% 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 %}
+{% 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-NAT66-' ~ rule %}
 {%     set base_log  = '[NAT66-DST-' ~ rule %}
@@ -36,6 +47,14 @@
 {%     endif   %}
 {%     set interface = ' oifname "' ~ config.outbound_interface ~ '"' if config.outbound_interface is vyos_defined else '' %}
 {% 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.translation.address is vyos_defined('masquerade') %}
 {%         set log = base_log ~ '-MASQ]' %}
@@ -43,6 +62,11 @@
 {%         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 %}
 {% set output = 'add rule ip6 nat ' ~ chain ~ interface %}
 {# Count packets #}
 {% set output = output ~ ' counter' %}
@@ -54,12 +78,18 @@
 {% if src_prefix is vyos_defined %}
 {%     set output = output ~ ' ' ~ src_prefix %}
 {% endif %}
+{% if dst_port is vyos_defined %}
+{%     set output = output ~ ' ' ~ protocol ~ ' ' ~ dst_port %}
+{% endif %}
 {% if dst_prefix is vyos_defined %}
 {%     set output = output ~ ' ' ~ dst_prefix %}
 {% endif %}
 {% if source_address is vyos_defined %}
 {%     set output = output ~ ' ' ~ source_address %}
 {% endif %}
+{% if src_port is vyos_defined %}
+{%     set output = output ~ ' ' ~ protocol ~ ' ' ~ src_port %}
+{% endif %}
 {% if dest_address is vyos_defined %}
 {%     set output = output ~ ' ' ~ dest_address %}
 {% endif %}
@@ -70,11 +100,22 @@
 {% if trns_address is vyos_defined %}
 {%     set output = output ~ ' ' ~ trns_address %}
 {% endif %}
+{% if trns_port is vyos_defined %}
+{#     Do not add a whitespace here, translation port must be directly added after IP address #}
+{#     e.g. 2001:db8::1:3389                                                                   #}
+{%     set output = output ~ trns_port %}
+{% 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 NAT table
-- 
cgit v1.2.3