Skip to content

Commit a24272e

Browse files
committed
dhcp/kea: Install prefix delegation routes targeting IA_NA address
1 parent e15f5ee commit a24272e

File tree

5 files changed

+158
-0
lines changed

5 files changed

+158
-0
lines changed

plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,8 @@
10941094
/usr/local/opnsense/scripts/dhcp/get_leases6.py
10951095
/usr/local/opnsense/scripts/dhcp/prefixes.php
10961096
/usr/local/opnsense/scripts/dhcp/prefixes.sh
1097+
/usr/local/opnsense/scripts/dhcp/prefixeskea.php
1098+
/usr/local/opnsense/scripts/dhcp/prefixeskea.sh
10971099
/usr/local/opnsense/scripts/dhcp/unbound_watcher.py
10981100
/usr/local/opnsense/scripts/dns/dnsmasq_dhcp_options.py
10991101
/usr/local/opnsense/scripts/dns/query_dns.py

src/etc/inc/plugins.inc.d/kea.inc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,16 @@ function kea_configure_do($verbose = false)
157157
$keaDhcpv6->generateConfig();
158158
}
159159
(new \OPNsense\Kea\KeaCtrlAgent())->generateConfig();
160+
if ($keaDhcpv6->isEnabled()) {
161+
killbypid('/var/run/prefixeskea.pid');
162+
mwexecf(
163+
'/usr/sbin/daemon -m0 -f -p %s %s',
164+
['/var/run/prefixeskea.pid', '/usr/local/opnsense/scripts/kea/prefixeskea.sh']
165+
);
166+
}
160167
service_log("done.\n", $verbose);
168+
} else {
169+
killbypid('/var/run/prefixeskea.pid');
161170
}
162171
}
163172

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/local/bin/php
2+
<?php
3+
4+
/*
5+
* Copyright (C) 2025 Deciso B.V.
6+
* Copyright (C) 2022-2024 Franco Fichtner <[email protected]>
7+
* Copyright (C) 2012 Seth Mos <[email protected]>
8+
* All rights reserved.
9+
*
10+
* Redistribution and use in source and binary forms, with or without
11+
* modification, are permitted provided that the following conditions are met:
12+
*
13+
* 1. Redistributions of source code must retain the above copyright notice,
14+
* this list of conditions and the following disclaimer.
15+
*
16+
* 2. Redistributions in binary form must reproduce the above copyright
17+
* notice, this list of conditions and the following disclaimer in the
18+
* documentation and/or other materials provided with the distribution.
19+
*
20+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22+
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23+
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24+
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
32+
require_once 'config.inc';
33+
require_once 'interfaces.inc';
34+
require_once 'util.inc';
35+
36+
$leases_file = '/var/db/kea/kea-leases6.csv';
37+
if (!file_exists($leases_file)) {
38+
exit(1);
39+
}
40+
41+
$duid_arr = [];
42+
$now = time();
43+
if (($fh = fopen($leases_file, 'r')) !== false) {
44+
$header = fgetcsv($fh);
45+
46+
while (($row = fgetcsv($fh)) !== false) {
47+
$lease = @array_combine($header, $row);
48+
if (empty($lease['duid']) || empty($lease['lease_type']) || empty($lease['address'])) {
49+
continue;
50+
}
51+
52+
$type = trim($lease['lease_type']);
53+
$prefix_len = (int)$lease['prefix_len'];
54+
$expire = (int)$lease['expire'];
55+
$duid = strtolower(trim($lease['duid']));
56+
$address = trim($lease['address']);
57+
58+
/* Skip expired leases */
59+
if ($expire <= $now) {
60+
continue;
61+
}
62+
63+
if (!isset($duid_arr[$duid])) {
64+
$duid_arr[$duid] = [];
65+
}
66+
67+
/* IA_NA: type 0, prefix_len 128 - used as gateway */
68+
if ($type === '0' && $prefix_len === 128) {
69+
$duid_arr[$duid]['address'] = $address;
70+
}
71+
/* IA_PD: type 2, prefix_len <= 64 - the delegated prefix */
72+
elseif ($type === '2' && $prefix_len <= 64) {
73+
$prefix = "{$address}/{$prefix_len}";
74+
$duid_arr[$duid]['prefix'][] = $prefix;
75+
}
76+
}
77+
fclose($fh);
78+
}
79+
80+
$routes = [];
81+
82+
/* collect active leases */
83+
foreach ($duid_arr as $entry) {
84+
if (!empty($entry['prefix']) && !empty($entry['address'])) {
85+
foreach ($entry['prefix'] as $prefix) {
86+
/* new or reassigned takes priority */
87+
$routes[$prefix] = $entry['address'];
88+
}
89+
}
90+
}
91+
92+
/* expire all first */
93+
foreach (array_keys($routes) as $prefix) {
94+
mwexecf('/sbin/route delete -inet6 %s', [$prefix], true);
95+
}
96+
97+
/* active route apply */
98+
foreach ($routes as $prefix => $address) {
99+
if (!empty($address)) {
100+
mwexecf('/sbin/route add -inet6 %s %s', [$prefix, $address]);
101+
}
102+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/sh
2+
3+
# Copyright (c) 2025 Deciso B.V.
4+
# All rights reserved.
5+
#
6+
# Redistribution and use in source and binary forms, with or without
7+
# modification, are permitted provided that the following conditions are met:
8+
#
9+
# 1. Redistributions of source code must retain the above copyright notice,
10+
# this list of conditions and the following disclaimer.
11+
#
12+
# 2. Redistributions in binary form must reproduce the above copyright
13+
# notice, this list of conditions and the following disclaimer in the
14+
# documentation and/or other materials provided with the distribution.
15+
#
16+
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17+
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18+
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
# AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
20+
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25+
# POSSIBILITY OF SUCH DAMAGE.
26+
27+
CHECKSUM="md5 -q"
28+
INTERVAL=${1:-20}
29+
LEASES="/var/db/kea/kea-leases6.csv"
30+
PREVIOUS=
31+
32+
while :; do
33+
CURRENT=$(${CHECKSUM} ${LEASES})
34+
if [ "${CURRENT}" != "${PREVIOUS}" ]; then
35+
configctl kea update prefixes
36+
PREVIOUS=${CURRENT}
37+
fi
38+
sleep "${INTERVAL}"
39+
done

src/opnsense/service/conf/actions.d/actions_kea.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ command:/usr/local/opnsense/scripts/dhcp/get_kea_leases.py
3434
parameters:--proto inet6
3535
type:script_output
3636
message:list kea inet dhcp leases
37+
38+
[update.prefixes]
39+
command:/usr/local/opnsense/scripts/dhcp/prefixeskea.php
40+
parameters:
41+
type:script
42+
message:update kea IPv6 prefix routes

0 commit comments

Comments
 (0)