summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/firewall/nftables-nat66.tmpl8
-rw-r--r--interface-definitions/nat66.xml.in14
-rwxr-xr-xsmoketest/scripts/cli/test_nat66.py33
3 files changed, 49 insertions, 6 deletions
diff --git a/data/templates/firewall/nftables-nat66.tmpl b/data/templates/firewall/nftables-nat66.tmpl
index af533812e..1a739cbe2 100644
--- a/data/templates/firewall/nftables-nat66.tmpl
+++ b/data/templates/firewall/nftables-nat66.tmpl
@@ -7,7 +7,13 @@
{% if chain == "PREROUTING" %}
{% set interface = " iifname \"" + config.inbound_interface + "\"" if config.inbound_interface is defined and config.inbound_interface != 'any' else '' %}
-{% set trns_address = "dnat to " + config.translation.address if config.translation is defined and config.translation.address is defined and config.translation.address is not none %}
+{% 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 interface = " oifname \"" + config.outbound_interface + "\"" if config.outbound_interface is defined and config.outbound_interface != 'any' else '' %}
{% set trns_prefix = "snat prefix to " + config.translation.prefix if config.translation is defined and config.translation.prefix is defined and config.translation.prefix is not none %}
diff --git a/interface-definitions/nat66.xml.in b/interface-definitions/nat66.xml.in
index b8e8a8859..36b55f658 100644
--- a/interface-definitions/nat66.xml.in
+++ b/interface-definitions/nat66.xml.in
@@ -141,13 +141,18 @@
<children>
<leafNode name="address">
<properties>
- <help>IPv6 address to be translated</help>
+ <help>IPv6 address or prefix to be translated</help>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address</description>
</valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 prefix</description>
+ </valueHelp>
<constraint>
<validator name="ipv6-address"/>
+ <validator name="ipv6-prefix"/>
</constraint>
</properties>
</leafNode>
@@ -160,13 +165,18 @@
<children>
<leafNode name="address">
<properties>
- <help>IPv6 address to translate to</help>
+ <help>IPv6 address or prefix to translate to</help>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address</description>
</valueHelp>
+ <valueHelp>
+ <format>ipv6net</format>
+ <description>IPv6 prefix</description>
+ </valueHelp>
<constraint>
<validator name="ipv6-address"/>
+ <validator name="ipv6-prefix"/>
</constraint>
</properties>
</leafNode>
diff --git a/smoketest/scripts/cli/test_nat66.py b/smoketest/scripts/cli/test_nat66.py
index f94f77b60..042c61ace 100755
--- a/smoketest/scripts/cli/test_nat66.py
+++ b/smoketest/scripts/cli/test_nat66.py
@@ -72,10 +72,10 @@ class TestNAT66(unittest.TestCase):
self.assertEqual(f'{address}/{mask}', source_prefix)
def test_destination_nat66(self):
- source_address = 'fc00::1'
+ destination_address = 'fc00::1'
translation_address = 'fc01::1'
self.session.set(dst_path + ['rule', '1', 'inbound-interface', 'eth1'])
- self.session.set(dst_path + ['rule', '1', 'destination', 'address', source_address])
+ self.session.set(dst_path + ['rule', '1', 'destination', 'address', destination_address])
self.session.set(dst_path + ['rule', '1', 'translation', 'address', translation_address])
# check validate() - outbound-interface must be defined
@@ -96,8 +96,35 @@ class TestNAT66(unittest.TestCase):
self.assertEqual(dnat_addr, translation_address)
self.assertEqual(iface, 'eth1')
+
+ def test_destination_nat66_prefix(self):
+ destination_prefix = 'fc00::/64'
+ translation_prefix = 'fc01::/64'
+ self.session.set(dst_path + ['rule', '1', 'inbound-interface', 'eth1'])
+ self.session.set(dst_path + ['rule', '1', 'destination', 'address', destination_prefix])
+ self.session.set(dst_path + ['rule', '1', 'translation', 'address', translation_prefix])
+
+ # check validate() - outbound-interface must be defined
+ self.session.commit()
+
+ tmp = cmd('sudo nft -j list table ip6 nat')
+ data_json = jmespath.search('nftables[?rule].rule[?chain]', json.loads(tmp))
+
+ for idx in range(0, len(data_json)):
+ data = data_json[idx]
+
+ self.assertEqual(data['chain'], 'PREROUTING')
+ self.assertEqual(data['family'], 'ip6')
+ self.assertEqual(data['table'], 'nat')
+
+ iface = dict_search('match.right', data['expr'][0])
+ translation_address = dict_search('dnat.addr.prefix.addr', data['expr'][3])
+ translation_mask = dict_search('dnat.addr.prefix.len', data['expr'][3])
+
+ self.assertEqual(f'{translation_address}/{translation_mask}', translation_prefix)
+ self.assertEqual(iface, 'eth1')
- def test_snat_required_translation_prefix(self):
+ def test_source_nat66_required_translation_prefix(self):
# T2813: Ensure translation address is specified
rule = '5'
source_prefix = 'fc00::/64'