diff options
author | Christian Breunig <christian@breunig.cc> | 2024-03-12 16:58:25 +0100 |
---|---|---|
committer | Mergify <37929162+mergify[bot]@users.noreply.github.com> | 2024-03-13 10:14:54 +0000 |
commit | 306e83a66e2e580417d87e3871200cad6c09cb49 (patch) | |
tree | 25986c25ba2e035cad57b579e2ac1e7f861ab77f | |
parent | c8528d080786a4be9436fa71c9ec969b9c3719fd (diff) | |
download | vyos-1x-306e83a66e2e580417d87e3871200cad6c09cb49.tar.gz vyos-1x-306e83a66e2e580417d87e3871200cad6c09cb49.zip |
radvd: T6118: add nat64prefix support RFC8781
Add support for pref64 option, as defined in RFC8781. The prefix valid lifetime
must not be smaller than the "interface interval max" definition which defaults
to 600.
set service router-advert interface eth1 nat64prefix 64:ff9b::/96
(cherry picked from commit f1ead5c6a16aba00699b8a5b9c18ef6cffe8cc4d)
-rw-r--r-- | data/templates/router-advert/radvd.conf.j2 | 7 | ||||
-rw-r--r-- | interface-definitions/service_router-advert.xml.in | 30 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_router-advert.py | 28 | ||||
-rwxr-xr-x | src/conf_mode/service_router-advert.py | 18 |
4 files changed, 80 insertions, 3 deletions
diff --git a/data/templates/router-advert/radvd.conf.j2 b/data/templates/router-advert/radvd.conf.j2 index 4ef4751dd..97180d164 100644 --- a/data/templates/router-advert/radvd.conf.j2 +++ b/data/templates/router-advert/radvd.conf.j2 @@ -50,6 +50,13 @@ interface {{ iface }} { {% endfor %} }; {% endif %} +{% if iface_config.nat64prefix is vyos_defined %} +{% for nat64prefix, nat64prefix_options in iface_config.nat64prefix.items() %} + nat64prefix {{ nat64prefix }} { + AdvValidLifetime {{ nat64prefix_options.valid_lifetime }}; + }; +{% endfor %} +{% endif %} {% if iface_config.prefix is vyos_defined %} {% for prefix, prefix_options in iface_config.prefix.items() %} prefix {{ prefix }} { diff --git a/interface-definitions/service_router-advert.xml.in b/interface-definitions/service_router-advert.xml.in index 16c29022d..166a4a0cf 100644 --- a/interface-definitions/service_router-advert.xml.in +++ b/interface-definitions/service_router-advert.xml.in @@ -225,6 +225,36 @@ </leafNode> </children> </tagNode> + <tagNode name="nat64prefix"> + <properties> + <help>NAT64 prefix included in the router advertisements</help> + <valueHelp> + <format>ipv6net</format> + <description>IPv6 prefix to be advertized</description> + </valueHelp> + <constraint> + <validator name="ipv6-prefix"/> + </constraint> + </properties> + <children> + <leafNode name="valid-lifetime"> + <properties> + <help>Time in seconds that the prefix will remain valid</help> + <completionHelp> + <list>infinity</list> + </completionHelp> + <valueHelp> + <format>u32:4-65528</format> + <description>Time in seconds that the prefix will remain valid</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 4-65528"/> + </constraint> + </properties> + <defaultValue>65528</defaultValue> + </leafNode> + </children> + </tagNode> <tagNode name="prefix"> <properties> <help>IPv6 prefix to be advertised in Router Advertisements (RAs)</help> diff --git a/smoketest/scripts/cli/test_service_router-advert.py b/smoketest/scripts/cli/test_service_router-advert.py index 5fc2019fd..d1ff25a58 100755 --- a/smoketest/scripts/cli/test_service_router-advert.py +++ b/smoketest/scripts/cli/test_service_router-advert.py @@ -195,6 +195,34 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase): for src in ra_src: self.assertIn(f' {src};', config) + def test_nat64prefix(self): + nat64prefix = '64:ff9b::/96' + nat64prefix_invalid = '64:ff9b::/44' + + self.cli_set(base_path + ['nat64prefix', nat64prefix]) + + # and another invalid prefix + # Invalid NAT64 prefix length for "2001:db8::/34", can only be one of: + # /32, /40, /48, /56, /64, /96 + self.cli_set(base_path + ['nat64prefix', nat64prefix_invalid]) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(base_path + ['nat64prefix', nat64prefix_invalid]) + + # NAT64 valid-lifetime must not be smaller then "interval max" + self.cli_set(base_path + ['nat64prefix', nat64prefix, 'valid-lifetime', '500']) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(base_path + ['nat64prefix', nat64prefix, 'valid-lifetime']) + + # commit changes + self.cli_commit() + + config = read_file(RADVD_CONF) + + tmp = f'nat64prefix {nat64prefix}' + ' {' + self.assertIn(tmp, config) + self.assertIn('AdvValidLifetime 65528;', config) # default if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/service_router-advert.py b/src/conf_mode/service_router-advert.py index dbb47de4e..88d767bb8 100755 --- a/src/conf_mode/service_router-advert.py +++ b/src/conf_mode/service_router-advert.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2018-2022 VyOS maintainers and contributors +# Copyright (C) 2018-2024 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -17,6 +17,8 @@ import os from sys import exit +from ipaddress import IPv6Network + from vyos.base import Warning from vyos.config import Config from vyos.template import render @@ -47,7 +49,9 @@ def verify(rtradv): return None for interface, interface_config in rtradv['interface'].items(): - if 'prefix' in interface: + interval_max = int(interface_config['interval']['max']) + + if 'prefix' in interface_config: for prefix, prefix_config in interface_config['prefix'].items(): valid_lifetime = prefix_config['valid_lifetime'] if valid_lifetime == 'infinity': @@ -60,6 +64,15 @@ def verify(rtradv): if not (int(valid_lifetime) >= int(preferred_lifetime)): raise ConfigError('Prefix valid-lifetime must be greater then or equal to preferred-lifetime') + if 'nat64prefix' in interface_config: + nat64_supported_lengths = [32, 40, 48, 56, 64, 96] + for prefix, prefix_config in interface_config['nat64prefix'].items(): + if IPv6Network(prefix).prefixlen not in nat64_supported_lengths: + raise ConfigError(f'Invalid NAT64 prefix length for "{prefix}", can only be one of: /' + ', /'.join(nat64_supported_lengths)) + + if int(prefix_config['valid_lifetime']) < interval_max: + raise ConfigError(f'NAT64 valid-lifetime must not be smaller then "interval max" which is "{interval_max}"!') + if 'name_server' in interface_config: if len(interface_config['name_server']) > 3: raise ConfigError('No more then 3 IPv6 name-servers supported!') @@ -72,7 +85,6 @@ def verify(rtradv): # ensure stale RDNSS info gets removed in a timely fashion, this # should not be greater than 2*MaxRtrAdvInterval. lifetime = int(interface_config['name_server_lifetime']) - interval_max = int(interface_config['interval']['max']) if lifetime > 0: if lifetime < int(interval_max): raise ConfigError(f'RDNSS lifetime must be at least "{interval_max}" seconds!') |