summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2025-10-21 21:02:23 +0200
committerGitHub <noreply@github.com>2025-10-21 21:02:23 +0200
commit9e1cb14a5eb1eedd1fce67732ad84f6528e30314 (patch)
tree9c21ef35446f1e94940a0f3a20d41e1bc1ad4bd5
parent2de4e9df6382edbb4b2af6148ef267854fa7ebbf (diff)
parentf87b522967bb7e3354278628d5d6ef9356a87948 (diff)
downloadvyos-1x-9e1cb14a5eb1eedd1fce67732ad84f6528e30314.tar.gz
vyos-1x-9e1cb14a5eb1eedd1fce67732ad84f6528e30314.zip
Merge pull request #4792 from sarthurdev/kea_config
kea: T7925: Improve error handling, validate IPv6 PD prefix length
-rw-r--r--python/vyos/kea.py11
-rw-r--r--smoketest/config-tests/basic-vyos28
-rw-r--r--smoketest/configs/basic-vyos4
-rwxr-xr-xsmoketest/scripts/cli/test_service_dhcpv6-server.py7
-rwxr-xr-xsrc/conf_mode/service_dhcp-server.py5
-rwxr-xr-xsrc/conf_mode/service_dhcpv6-server.py18
6 files changed, 52 insertions, 21 deletions
diff --git a/python/vyos/kea.py b/python/vyos/kea.py
index 5ce6f47f1..f48cf293d 100644
--- a/python/vyos/kea.py
+++ b/python/vyos/kea.py
@@ -15,6 +15,7 @@
import json
import os
+import re
import socket
from datetime import datetime
@@ -25,7 +26,7 @@ from vyos.template import is_ipv6
from vyos.template import netmask_from_cidr
from vyos.utils.dict import dict_search_args
from vyos.utils.file import file_permissions
-from vyos.utils.process import run
+from vyos.utils.process import run, rc_cmd
kea4_options = {
'name_server': 'domain-name-servers',
@@ -86,6 +87,14 @@ def _find_list_of_dict_index(lst, key='ip', value=''):
idx = next((index for (index, d) in enumerate(lst) if d[key] == value), None)
return idx
+def kea_test_config(process: str, config_path: str) -> tuple[bool, str]:
+ result, output = rc_cmd(f'{process} -t {config_path}')
+
+ if result == 0:
+ return (True, None)
+
+ find = re.search(r'Error encountered:\s([^\n$]+)', output)
+ return (False, find[1] if find else None)
def kea_parse_options(config):
options = []
diff --git a/smoketest/config-tests/basic-vyos b/smoketest/config-tests/basic-vyos
index aaf450e80..601051d8f 100644
--- a/smoketest/config-tests/basic-vyos
+++ b/smoketest/config-tests/basic-vyos
@@ -63,20 +63,20 @@ set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 subnet-id
set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 dynamic-dns-update send-updates 'enable'
set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 dynamic-dns-update generated-prefix 'myhost'
set service dhcp-server shared-network-name LAN subnet 192.168.0.0/24 dynamic-dns-update qualifying-suffix 'lan1.domain.lan'
-set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 interface 'eth0'
-set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 option domain-search 'vyos.net'
-set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 option name-server 'fe88::1'
-set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 range 1 prefix 'fe88::/60'
-set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 range 2 start 'fe88:0000:0000:fe::'
-set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 range 2 stop 'fe88:0000:0000:ff::'
-set service dhcpv6-server shared-network-name LAN6 subnet fe88::/56 subnet-id '1'
-set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 interface 'eth2.200.201'
-set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 option domain-search 'vyos.net'
-set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 option name-server 'fe89::1'
-set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 range 1 prefix 'fe89::/60'
-set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 range 2 start 'fe89:0000:0000:fe::'
-set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 range 2 stop 'fe89:0000:0000:ff::'
-set service dhcpv6-server shared-network-name LAN6 subnet fe89::/56 subnet-id '2'
+set service dhcpv6-server shared-network-name LAN6-1 subnet fe88::/56 interface 'eth0'
+set service dhcpv6-server shared-network-name LAN6-1 subnet fe88::/56 option domain-search 'vyos.net'
+set service dhcpv6-server shared-network-name LAN6-1 subnet fe88::/56 option name-server 'fe88::1'
+set service dhcpv6-server shared-network-name LAN6-1 subnet fe88::/56 range 1 prefix 'fe88::/60'
+set service dhcpv6-server shared-network-name LAN6-1 subnet fe88::/56 range 2 start 'fe88:0000:0000:fe::'
+set service dhcpv6-server shared-network-name LAN6-1 subnet fe88::/56 range 2 stop 'fe88:0000:0000:ff::'
+set service dhcpv6-server shared-network-name LAN6-1 subnet fe88::/56 subnet-id '1'
+set service dhcpv6-server shared-network-name LAN6-2 subnet fe89::/56 interface 'eth2.200.201'
+set service dhcpv6-server shared-network-name LAN6-2 subnet fe89::/56 option domain-search 'vyos.net'
+set service dhcpv6-server shared-network-name LAN6-2 subnet fe89::/56 option name-server 'fe89::1'
+set service dhcpv6-server shared-network-name LAN6-2 subnet fe89::/56 range 1 prefix 'fe89::/60'
+set service dhcpv6-server shared-network-name LAN6-2 subnet fe89::/56 range 2 start 'fe89:0000:0000:fe::'
+set service dhcpv6-server shared-network-name LAN6-2 subnet fe89::/56 range 2 stop 'fe89:0000:0000:ff::'
+set service dhcpv6-server shared-network-name LAN6-2 subnet fe89::/56 subnet-id '2'
set service dns forwarding allow-from '192.168.0.0/16'
set service dns forwarding cache-size '10000'
set service dns forwarding dnssec 'off'
diff --git a/smoketest/configs/basic-vyos b/smoketest/configs/basic-vyos
index 5f7a71237..74928dc9b 100644
--- a/smoketest/configs/basic-vyos
+++ b/smoketest/configs/basic-vyos
@@ -174,7 +174,7 @@ service {
}
}
dhcpv6-server {
- shared-network-name LAN6 {
+ shared-network-name LAN6-1 {
subnet fe88::/56 {
address-range {
prefix fe88::/60 {
@@ -193,6 +193,8 @@ service {
}
}
}
+ }
+ shared-network-name LAN6-2 {
subnet fe89::/56 {
address-range {
prefix fe89::/60 {
diff --git a/smoketest/scripts/cli/test_service_dhcpv6-server.py b/smoketest/scripts/cli/test_service_dhcpv6-server.py
index 5e0dd7cc2..769c799b2 100755
--- a/smoketest/scripts/cli/test_service_dhcpv6-server.py
+++ b/smoketest/scripts/cli/test_service_dhcpv6-server.py
@@ -221,6 +221,7 @@ class TestServiceDHCPv6Server(VyOSUnitTestSHIM.TestCase):
range_stop = inc_ip(subnet, 65535) # ::ffff
delegate_start = '2001:db8:ee::'
delegate_len = '64'
+ bad_prefix_len = '32'
prefix_len = '56'
exclude_len = '66'
@@ -229,11 +230,15 @@ class TestServiceDHCPv6Server(VyOSUnitTestSHIM.TestCase):
self.cli_set(pool + ['range', '1', 'start', range_start])
self.cli_set(pool + ['range', '1', 'stop', range_stop])
self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'delegated-length', delegate_len])
- self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'prefix-length', prefix_len])
+ self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'prefix-length', bad_prefix_len])
self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'excluded-prefix', delegate_start])
self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'excluded-prefix-length', exclude_len])
# commit changes
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(pool + ['prefix-delegation', 'prefix', delegate_start, 'prefix-length', prefix_len])
self.cli_commit()
config = read_file(KEA6_CONF)
diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py
index d92321ab8..e4730f8a8 100755
--- a/src/conf_mode/service_dhcp-server.py
+++ b/src/conf_mode/service_dhcp-server.py
@@ -25,6 +25,7 @@ from ipaddress import ip_network
from netaddr import IPRange
from vyos.config import Config
+from vyos.kea import kea_test_config
from vyos.pki import wrap_certificate
from vyos.pki import wrap_private_key
from vyos.template import render
@@ -595,6 +596,10 @@ def apply(dhcp):
return None
+ result, output = kea_test_config('kea-dhcp4', config_file)
+ if not result:
+ raise ConfigError(f'Unexpected error with Kea configuration:\n{output}')
+
for service in services:
action = 'restart'
diff --git a/src/conf_mode/service_dhcpv6-server.py b/src/conf_mode/service_dhcpv6-server.py
index b6a7a87c3..d7b2f2a6d 100755
--- a/src/conf_mode/service_dhcpv6-server.py
+++ b/src/conf_mode/service_dhcpv6-server.py
@@ -24,6 +24,7 @@ from ipaddress import ip_address
from ipaddress import ip_network
from vyos.config import Config
+from vyos.kea import kea_test_config
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.file import chmod_775
@@ -191,16 +192,21 @@ def verify(dhcpv6):
if 'prefix_length' not in prefix_config:
raise ConfigError('Length of delegated IPv6 prefix must be configured')
- if prefix_config['prefix_length'] > prefix_config['delegated_length']:
+ prefix_len = prefix_config['prefix_length']
+ prefix_obj = None
+
+ if prefix_len > prefix_config['delegated_length']:
raise ConfigError('Length of delegated IPv6 prefix must be within parent prefix')
+ try:
+ prefix_obj = ip_network(f'{prefix}/{prefix_len}')
+ except ValueError:
+ raise ConfigError('Invalid prefix-length for delegated prefix')
+
if 'excluded_prefix' in prefix_config:
if 'excluded_prefix_length' not in prefix_config:
raise ConfigError('Length of excluded IPv6 prefix must be configured')
- prefix_len = prefix_config['prefix_length']
- prefix_obj = ip_network(f'{prefix}/{prefix_len}')
-
excluded_prefix = prefix_config['excluded_prefix']
excluded_len = prefix_config['excluded_prefix_length']
excluded_obj = ip_network(f'{excluded_prefix}/{excluded_len}')
@@ -301,6 +307,10 @@ def apply(dhcpv6):
os.unlink(config_file)
return None
+ result, output = kea_test_config('kea-dhcp6', config_file)
+ if not result:
+ raise ConfigError(f'Unexpected error with Kea configuration:\n{output}')
+
call(f'systemctl restart {service_name}')
return None