diff options
-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!') |