%PDF- %PDF-
| Direktori : /backups/router/usr/local/opnsense/scripts/dhcp/ |
| Current File : //backups/router/usr/local/opnsense/scripts/dhcp/prefixes.php |
#!/usr/local/bin/php
<?php
/*
* Copyright (C) 2022-2024 Franco Fichtner <franco@opnsense.org>
* Copyright (C) 2012 Seth Mos <seth.mos@dds.nl>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once 'config.inc';
require_once 'interfaces.inc';
require_once 'util.inc';
require_once 'plugins.inc.d/dhcpd.inc';
$leases_file = '/var/dhcpd/var/db/dhcpd6.leases';
if (!file_exists($leases_file)) {
exit(1);
}
$duid_arr = [];
foreach (new SplFileObject($leases_file) as $line) {
if (preg_match("/^(ia-[np][ad])[ ]+\"(.*?)\"/i ", $line, $duidmatch)) {
$type = $duidmatch[1];
$duid = $duidmatch[2];
} elseif (preg_match("/iaaddr[ ]+([0-9a-f:]+)[ ]+/i", $line, $addressmatch)) {
$ia_na = $addressmatch[1];
} elseif (preg_match("/iaprefix[ ]+([0-9a-f:\/]+)[ ]+/i", $line, $prefixmatch)) {
$ia_pd = $prefixmatch[1];
} elseif (preg_match("/binding state active/i", $line, $activematch)) {
$active = true;
} elseif (preg_match("/^}/i ", $line)) {
$iaid_duid = dhcpd_parse_duid($duid);
$duid = implode(':', $iaid_duid[1]);
switch ($type) {
case 'ia-na':
if (!empty($ia_na) && !empty($active)) {
$duid_arr[$duid]['address'] = $ia_na;
}
break;
case 'ia-pd':
if (!empty($ia_pd) && !empty($active)) {
if (empty($duid_arr[$duid]['prefix'])) {
$duid_arr[$duid]['prefix'] = [];
}
$duid_arr[$duid]['prefix'][] = $ia_pd;
}
break;
}
unset($active);
unset($duid);
unset($ia_na);
unset($ia_pd);
unset($type);
}
}
/* since a route requires a gateway address try to derive it from static mapping as well */
foreach (plugins_run('static_mapping:dhcpd') as $map) {
foreach ($map as $host) {
if (empty($host['duid'])) {
continue;
}
if (empty($duid_arr[$host['duid']])) {
continue;
}
if (!empty($host['ipaddrv6'])) {
$ipaddrv6 = $host['ipaddrv6'];
/* although link-local is not a real static mapping use it to reach the downstream router */
if (is_linklocal($ipaddrv6) && strpos($ipaddrv6, '%') === false) {
$ipaddrv6 .= '%' . get_real_interface($host['interface'], 'inet6');
}
/* we want static mapping to have a higher priority */
$duid_arr[$host['duid']]['address'] = $ipaddrv6;
}
}
}
$routes = [];
/* collect expired leases */
$dhcpd_log = shell_safe('opnsense-log -n dhcpd');
if (!empty($dhcpd_log)) {
foreach (new SplFileObject($dhcpd_log) as $line) {
if (preg_match('/releases prefix ([0-9a-f:]+\/[0-9]+)/i', $line, $expire)) {
/* expire first, overwritten later when active */
$routes[$expire[1]] = null;
}
}
}
/* collect active leases */
foreach ($duid_arr as $entry) {
if (!empty($entry['prefix']) && !empty($entry['address'])) {
foreach ($entry['prefix'] as $prefix) {
/* new or reassigned takes priority */
$routes[$prefix] = $entry['address'];
}
}
}
/* expire all first */
foreach (array_keys($routes) as $prefix) {
mwexecf('/sbin/route delete -inet6 %s', [$prefix], true);
}
/* active route apply */
foreach ($routes as $prefix => $address) {
if (!empty($address)) {
mwexecf('/sbin/route add -inet6 %s %s', [$prefix, $address]);
}
}