From 29e87aa3e4e4877e9b66ed8050ba49cd438eda6c Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Mon, 15 Apr 2024 21:29:45 +0200 Subject: [PATCH] Services: Kea DHCP [new]: Kea DHCPv4 - generate json payload from model, work in progress for https://github.com/opnsense/core/pull/7361 --- .../app/models/OPNsense/Kea/KeaCtrlAgent.php | 37 +++++ .../mvc/app/models/OPNsense/Kea/KeaDhcpv4.php | 132 ++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/src/opnsense/mvc/app/models/OPNsense/Kea/KeaCtrlAgent.php b/src/opnsense/mvc/app/models/OPNsense/Kea/KeaCtrlAgent.php index 876a9a4f7..43e8d4110 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Kea/KeaCtrlAgent.php +++ b/src/opnsense/mvc/app/models/OPNsense/Kea/KeaCtrlAgent.php @@ -28,8 +28,45 @@ namespace OPNsense\Kea; +use OPNsense\Core\File; use OPNsense\Base\BaseModel; class KeaCtrlAgent extends BaseModel { + public function generateConfig($target='/usr/local/etc/kea/kea-ctrl-agent.conf') + { + $cnf = [ + 'Control-agent' => [ + 'http-host' => (string)$this->general->http_host, + 'http-port' => (int)$this->general->http_port->__toString(), + 'control-sockets' => [ + 'dhcp4' => [ + 'socket-type' => 'unix', + 'socket-name' => '/var/run/kea4-ctrl-socket' + ], + 'dhcp6' => [ + 'socket-type' => 'unix', + 'socket-name'=> '/var/run/kea6-ctrl-socket' + ], + 'd2' => [ + 'socket-type' => 'unix', + 'socket-name' => '/var/run/kea-ddns-ctrl-socket' + ] + ], + 'loggers' => [ + [ + 'name' => 'kea-ctrl-agent', + 'output_options' => [ + [ + 'output' => 'syslog' + ] + ], + 'severity' => 'INFO', + 'debuglevel' => 0 + ] + ] + ] + ]; + File::file_put_contents($target, json_encode($cnf, JSON_PRETTY_PRINT), 0600); + } } diff --git a/src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php b/src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php index 175e08253..7bff8644f 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php +++ b/src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php @@ -32,6 +32,7 @@ use OPNsense\Base\Messages\Message; use OPNsense\Base\BaseModel; use OPNsense\Core\Config; use OPNsense\Core\Backend; +use OPNsense\Core\File; use OPNsense\Firewall\Util; class KeaDhcpv4 extends BaseModel @@ -102,4 +103,135 @@ class KeaDhcpv4 extends BaseModel (string)$this->general->fwrules == '1' && !empty((string)(string)$this->general->interfaces); } + + /** + * + */ + private function getConfigPhysicalInterfaces() + { + $result = []; + $cfg = Config::getInstance()->object(); + foreach (explode(',', $this->general->interfaces) as $if) { + if (isset($cfg->interfaces->$if) && !empty($cfg->interfaces->$if->if)) { + $result[] = (string)$cfg->interfaces->$if->if; + } + } + return $result; + } + + private function getConfigThisServerHostname() + { + $hostname = (string)$this->ha->this_server_name; + if (empty($hostname)) { + $hostname = (string)Config::getInstance()->object()->system->hostname; + } + return $hostname; + } + + private function getConfigSubnets() + { + $result = []; + $subnet_id = 1; + foreach ($this->subnets->subnet4->iterateItems() as $subnet_uuid => $subnet) { + $record = [ + 'id' => $subnet_id++, + 'subnet' => (string)$subnet->subnet, + 'option-data' => [], + 'pools' => [], + 'reservations' => [] + ]; + foreach ($subnet->option_data->iterateItems() as $key => $value) { + if (!empty((string)$value)) { + $record['option-data'][] = [ + 'name' => str_replace('_', '-', $key), + 'data' => (string)$value + ]; + } + } + foreach (array_filter(explode("\n", $subnet->pools)) as $pool) { + $record['pools'][] = ['pool' => $pool]; + } + foreach ($this->reservations->reservation->iterateItems() as $key => $reservation) { + if ($reservation->subnet != $subnet_uuid) { + continue; + } + $res = []; + foreach (['hw_address', 'ip_address', 'hostname'] as $key) { + if (!empty((string)$reservation->$key)) { + $res[str_replace('_', '-', $key)] = (string)$reservation->$key; + } + } + $record['reservations'][] = $res; + } + $result[] = $record; + } + return $result; + } + + public function generateConfig($target='/usr/local/etc/kea/kea-dhcp4.conf') + { + $cnf = [ + 'Dhcp4' => [ + 'valid-lifetime' => (int)$this->general->valid_lifetime->__toString(), + 'interfaces-config' => [ + 'interfaces' => $this->getConfigPhysicalInterfaces() + ], + 'lease-database' => [ + 'type' => 'memfile', + 'persist' => True + ], + 'control-socket' => [ + 'socket-type' => 'unix', + 'socket-name' => '/var/run/kea4-ctrl-socket' + ], + 'loggers' => [ + [ + 'name' => 'kea-dhcp4', + 'output_options' => [ + [ + 'output' => 'syslog' + ] + ], + 'severity' => 'INFO' + ] + ], + 'subnet4' => $this->getConfigSubnets() + ] + ]; + if (!empty((string)(new KeaCtrlAgent())->general->enabled)) { + $cnf['Dhcp4']['hooks-libraries'] = []; + $cnf['Dhcp4']['hooks-libraries'][] = [ + 'library' => '/usr/local/lib/kea/hooks/libdhcp_lease_cmds.so' + ]; + if (!empty((string)$this->ha->enabled)) { + $record = [ + 'library' => '/usr/local/lib/kea/hooks/libdhcp_ha.so', + 'parameters' => [ + 'high-availability' => [ + [ + 'this-server-name' => $this->getConfigThisServerHostname(), + 'mode' => 'hot-standby', + 'heartbeat-delay' => 10000, + 'max-response-delay' => 60000, + 'max-ack-delay' => 5000, + 'max-unacked-clients' => 5, + 'sync-timeout' => 60000 + ] + ] + ] + ]; + foreach ($this->ha_peers->peer->iterateItems() as $peer) { + if (!isset($record['parameters']['high-availability'][0]['peers'])) { + $record['parameters']['high-availability'][0]['peers'] = []; + } + $record['parameters']['high-availability'][0]['peers'][] = array_map( + fn($x) => (string)$x, + iterator_to_array($peer->iterateItems()) + ); + } + $cnf['Dhcp4']['hooks-libraries'][] = $record; + } + } + File::file_put_contents($target, json_encode($cnf, JSON_PRETTY_PRINT), 0600); + } }