From c5f2af18e855417ffbefc77ece3070e94cc4dca9 Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Tue, 19 May 2026 16:30:48 +0200 Subject: [PATCH] interfaces: add prefix range option for Kea dynamic PD This extends the prefix ID selection to be able to reserve a range of IDs in order to automatically hand them out via Kea. The accepted value is between 1 and the end of the PD ID range and also validates against other IDs and their ranges. This approach differs from the old ISC DHCPv6 in that we can make room for delegation to avoid later surprises. It might force a user to reshuffle his ID range, but Kea wants a IA-NA subnet that is within the pool reserved here. --- src/www/interfaces.php | 49 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/www/interfaces.php b/src/www/interfaces.php index 989f01bb35..68b82b5bfb 100644 --- a/src/www/interfaces.php +++ b/src/www/interfaces.php @@ -248,17 +248,38 @@ function validate_track6_idassoc6(&$pconfig, $if) if ($ipv6_delegation_length >= 0) { $ipv6_num_prefix_ids = pow(2, $ipv6_delegation_length); $track6_prefix_id = intval($pconfig["{$pconfig['type6']}-prefix-id--hex"], 16); + $track6_prefix_range = $pconfig["{$pconfig['type6']}_prefix_range"]; if ($track6_prefix_id < 0 || $track6_prefix_id >= $ipv6_num_prefix_ids) { $input_errors[] = gettext("You specified an IPv6 prefix ID that is out of range."); + } elseif (strlen($track6_prefix_range)) { + if (!ctype_digit($track6_prefix_range)) { + $input_errors[] = gettext("You specified an IPv6 prefix range that is not valid."); + } elseif ($track6_prefix_range < 1 || $track6_prefix_id + $track6_prefix_range > $ipv6_num_prefix_ids) { + $input_errors[] = gettext("You specified an IPv6 prefix range that is out of range."); + } } $default_id = interface_dhcpv6_id($pconfig["{$pconfig['type6']}-interface"]); $assoc_pd_ref = !empty($pconfig["{$pconfig['type6']}_assoc_pd"]) && ctype_digit($pconfig["{$pconfig['type6']}_assoc_pd"]) ? $pconfig["{$pconfig['type6']}_assoc_pd"] : $default_id; foreach (link_interface_to_track6($pconfig["{$pconfig['type6']}-interface"]) as $trackif => $trackcfg) { + if ($trackif == $if) { + continue; + } $assoc_pd_link = !empty($trackcfg['track6_assoc_pd']) ? $trackcfg['track6_assoc_pd'] : $default_id; - if ($trackif != $if && $assoc_pd_ref == $assoc_pd_ref && $trackcfg['track6-prefix-id'] == $track6_prefix_id) { + if ($assoc_pd_ref != $assoc_pd_ref) { + continue; + } + /* the end of non-overlapping intervals needs to specify 0 ... n-1 */ + $track6_range_end = !empty($track6_prefix_range) ? $track6_prefix_range - 1 : 0; + $track6_range_end += $track6_prefix_id; + $range_end_link = !empty($trackcfg['track6_prefix_range']) ? $trackcfg['track6_prefix_range'] - 1 : 0; + $range_end_link += $trackcfg['track6-prefix-id']; + if ($trackcfg['track6-prefix-id'] == $track6_prefix_id) { $input_errors[] = gettext('You specified an IPv6 prefix ID that is already in use.'); break; + } elseif ($trackcfg['track6-prefix-id'] <= $track6_range_end && $track6_prefix_id <= $range_end_link) { + $input_errors[] = gettext('You specified an IPv6 prefix range that is already in use.'); + break; } } if (isset($config['interfaces'][$pconfig["{$pconfig['type6']}-interface"]]['dhcp6-prefix-id'])) { @@ -308,6 +329,9 @@ function store_track6_idassoc6(&$new_config, &$pconfig) if (isset($pconfig["{$pconfig['type6']}_ifid--hex"]) && ctype_xdigit($pconfig["{$pconfig['type6']}_ifid--hex"])) { $new_config['track6_ifid'] = intval($pconfig["{$pconfig['type6']}_ifid--hex"], 16); } + if (!empty($pconfig["{$pconfig['type6']}_prefix_range"])) { + $new_config['track6_prefix_range'] = $pconfig["{$pconfig['type6']}_prefix_range"]; + } if (!empty($pconfig["{$pconfig['type6']}_assoc_pd"])) { $new_config['track6_assoc_pd'] = $pconfig["{$pconfig['type6']}_assoc_pd"]; } @@ -504,6 +528,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { 'track6-prefix-id', 'track6_assoc_pd', 'track6_ifid', + 'track6_prefix_range', ]; foreach ($std_copy_fieldnames as $fieldname) { $pconfig[$fieldname] = isset($a_interfaces[$if][$fieldname]) ? $a_interfaces[$if][$fieldname] : null; @@ -524,7 +549,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $pconfig['dhcpd6track6allowoverride'] = isset($a_interfaces[$if]['dhcpd6track6allowoverride']); $pconfig['dhcp6_request_dns'] = empty($pconfig['dhcp6_norequest_dns']); - foreach(['-interface', '-prefix-id', '-prefix-id--hex', '_assoc_pd', '_ifid', '_ifid--hex'] as $fieldname) { + foreach(['-interface', '-prefix-id', '-prefix-id--hex', '_assoc_pd', '_ifid', '_ifid--hex', '_prefix_range'] as $fieldname) { /* only for form consistency */ $pconfig["idassoc6{$fieldname}"] = $pconfig["track6{$fieldname}"]; } @@ -2641,6 +2666,16 @@ include("head.inc"); + + + + + + + + @@ -2706,6 +2741,16 @@ include("head.inc"); + + + + + + + +