Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/opnsense/mvc/app/models/OPNsense/Kea/KeaCtrlAgent.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

/*
* Copyright (C) 2023 Deciso B.V.
* Copyright (C) 2023-2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -37,8 +37,8 @@ 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(),
'http-host' => $this->general->http_host->getValue(),
'http-port' => (int)$this->general->http_port->getValue(),
'control-sockets' => [
'dhcp4' => [
'socket-type' => 'unix',
Expand Down
50 changes: 25 additions & 25 deletions src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

/*
* Copyright (C) 2023 Deciso B.V.
* Copyright (C) 2023-2025 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -46,12 +46,12 @@ public function setNodes($data)
{
$ifconfig = json_decode((new Backend())->configdRun('interface list ifconfig'), true) ?? [];
foreach ($this->subnets->subnet4->iterateItems() as $subnet) {
if (!empty((string)$subnet->option_data_autocollect)) {
if (!$subnet->option_data_autocollect->isEmpty()) {
// find first possible candidate to use as a gateway.
$host_ip = null;
foreach ($ifconfig as $if => $details) {
foreach ($details['ipv4'] as $net) {
if (Util::isIPInCIDR($net['ipaddr'], (string)$subnet->subnet)) {
if (Util::isIPInCIDR($net['ipaddr'], $subnet->subnet->getValue())) {
$host_ip = $net['ipaddr'];
break 2;
}
Expand Down Expand Up @@ -83,9 +83,9 @@ public function performValidation($validateFullModel = false)
$subnet = "";
$subnet_node = $this->getNodeByReference("subnets.subnet4.{$reservation->subnet}");
if ($subnet_node) {
$subnet = (string)$subnet_node->subnet;
$subnet = $subnet_node->subnet->getValue();
}
if (!Util::isIPInCIDR((string)$reservation->ip_address, $subnet)) {
if (!Util::isIPInCIDR($reservation->ip_address->getValue(), $subnet)) {
$messages->appendMessage(new Message(gettext("Address not in specified subnet"), $key . ".ip_address"));
}
}
Expand All @@ -95,7 +95,7 @@ public function performValidation($validateFullModel = false)

public function isEnabled()
{
return (string)$this->general->enabled == '1' && !empty((string)(string)$this->general->interfaces);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's a (string)(string) :)

return $this->general->enabled->isEqual('1') && !$this->general->interfaces->isEmpty();
}

/**
Expand All @@ -104,9 +104,9 @@ public function isEnabled()
*/
public function fwrulesEnabled()
{
return (string)$this->general->enabled == '1' &&
(string)$this->general->fwrules == '1' &&
!empty((string)(string)$this->general->interfaces);
return $this->general->enabled->isEqual('1') &&
$this->general->fwrules->isEqual('1') &&
!$this->general->interfaces->isEmpty();
}

/**
Expand All @@ -116,7 +116,7 @@ private function getConfigPhysicalInterfaces()
{
$result = [];
$cfg = Config::getInstance()->object();
foreach (explode(',', $this->general->interfaces) as $if) {
foreach ($this->general->interfaces->getValues() as $if) {
if (isset($cfg->interfaces->$if) && !empty($cfg->interfaces->$if->if)) {
$result[] = (string)$cfg->interfaces->$if->if;
}
Expand All @@ -126,7 +126,7 @@ private function getConfigPhysicalInterfaces()

private function getConfigThisServerHostname()
{
$hostname = (string)$this->ha->this_server_name;
$hostname = $this->ha->this_server_name->getValue();
if (empty($hostname)) {
$hostname = (string)Config::getInstance()->object()->system->hostname;
}
Expand All @@ -143,9 +143,9 @@ private function collectOptionData($node, $defaults = false)
$result = [];
foreach ($node->iterateItems() as $key => $value) {
$target_fieldname = str_replace('_', '-', $key);
if ((string)$value != '') {
if (!$value->isEqual('')) {
if ($key == 'static_routes') {
$value = implode(',', array_map('trim', explode(',', $value)));
$value = implode(',', array_map('trim', explode(',', $value->getValue())));
}
$result[] = [
'name' => $target_fieldname,
Expand All @@ -168,15 +168,15 @@ private function getConfigSubnets()
foreach ($this->subnets->subnet4->iterateItems() as $subnet_uuid => $subnet) {
$record = [
'id' => $subnet_id++,
'subnet' => (string)$subnet->subnet,
'next-server' => (string)$subnet->next_server,
'match-client-id' => !empty((string)$subnet->{'match-client-id'}),
'subnet' => $subnet->subnet->getValue(),
'next-server' => $subnet->next_server->getValue(),
'match-client-id' => !$subnet->{'match-client-id'}->isEmpty(),
'option-data' => $this->collectOptionData($subnet->option_data, true),
'pools' => [],
'reservations' => []
];
/* add pools */
foreach (array_filter(explode("\n", $subnet->pools)) as $pool) {
foreach (array_filter(explode("\n", $subnet->pools->getValue())) as $pool) {
$record['pools'][] = ['pool' => $pool];
}
/* static reservations */
Expand All @@ -186,12 +186,12 @@ private function getConfigSubnets()
}
$res = [];
foreach (['ip_address', 'hostname'] as $key) {
if (!empty((string)$reservation->$key)) {
$res[str_replace('_', '-', $key)] = (string)$reservation->$key;
if (!$reservation->$key->isEmpty()) {
$res[str_replace('_', '-', $key)] = $reservation->$key->getValue();
}
}
if (!$reservation->hw_address->isEmpty()) {
$res['hw-address'] = str_replace('-', ':', $reservation->hw_address);
$res['hw-address'] = str_replace('-', ':', $reservation->hw_address->getValue());
}

// Add DHCP option-data elements for reservations
Expand Down Expand Up @@ -224,10 +224,10 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp4.conf')
{
$cnf = [
'Dhcp4' => [
'valid-lifetime' => (int)$this->general->valid_lifetime->__toString(),
'valid-lifetime' => (int)$this->general->valid_lifetime->getValue(),
'interfaces-config' => [
'interfaces' => $this->getConfigPhysicalInterfaces(),
'dhcp-socket-type' => (string)$this->general->dhcp_socket_type
'dhcp-socket-type' => $this->general->dhcp_socket_type->getValue()
],
'lease-database' => [
'type' => 'memfile',
Expand Down Expand Up @@ -260,7 +260,7 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp4.conf')
$cnf['Dhcp4']['hooks-libraries'][] = [
'library' => '/usr/local/lib/kea/hooks/libdhcp_lease_cmds.so'
];
if (!empty((string)$this->ha->enabled)) {
if (!$this->ha->enabled->isEmpty()) {
Copy link

@ruifung ruifung Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity (and for my open PR) is there a specific case where you'd want to use !(field->isEmpty()) vs field->isEqual('1') when checking if a boolean field is checked?

Because I've seen both being used and it's mildly confusing as to which is the preferred method for checking if a checkbox is checked.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isEqual is a newer than isEmpty. isEqual(‘1’) or isEqual(1) is always safe, but isEqual(‘0’) had some issues in the past but is now always safe too. Though for booleans the best check to support perhaps would be isOn() and isOff() but that requires more brain smarts as it doesn’t really fit the base field. Just a tangent here since you asked 😊

$record = [
'library' => '/usr/local/lib/kea/hooks/libdhcp_ha.so',
'parameters' => [
Expand All @@ -271,7 +271,7 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp4.conf')
'heartbeat-delay' => 10000,
'max-response-delay' => 60000,
'max-ack-delay' => 5000,
'max-unacked-clients' => (int)((string)$this->ha->max_unacked_clients),
'max-unacked-clients' => (int)$this->ha->max_unacked_clients->getValue(),
'sync-timeout' => 60000,
]
]
Expand All @@ -282,7 +282,7 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp4.conf')
$record['parameters']['high-availability'][0]['peers'] = [];
}
$record['parameters']['high-availability'][0]['peers'][] = array_map(
fn($x) => (string)$x,
fn($x) => $x->getValue(),
iterator_to_array($peer->iterateItems())
);
}
Expand Down
51 changes: 25 additions & 26 deletions src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv6.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ public function performValidation($validateFullModel = false)
$subnet = "";
$subnet_node = $this->getNodeByReference("subnets.subnet6.{$reservation->subnet}");
if ($subnet_node) {
$subnet = (string)$subnet_node->subnet;
$subnet = $subnet_node->subnet->getValue();
}
if (!Util::isIPInCIDR((string)$reservation->ip_address, $subnet)) {
if (!Util::isIPInCIDR($reservation->ip_address->getValue(), $subnet)) {
$messages->appendMessage(new Message(gettext("Address not in specified subnet"), $key . ".ip_address"));
}
}
Expand All @@ -65,7 +65,7 @@ public function performValidation($validateFullModel = false)
continue;
}
$key = $subnet->__reference;
if (!in_array((string)$subnet->interface, $this_interfaces)) {
if (!in_array($subnet->interface->getValue(), $this_interfaces)) {
$messages->appendMessage(
new Message(gettext("Interface not configured in general settings"), $key . ".interface")
);
Expand All @@ -77,7 +77,7 @@ public function performValidation($validateFullModel = false)

public function isEnabled()
{
return (string)$this->general->enabled == '1' && !empty((string)(string)$this->general->interfaces);
return $this->general->enabled->isEqual('1') && !$this->general->interfaces->isEmpty();
}

/**
Expand All @@ -86,9 +86,9 @@ public function isEnabled()
*/
public function fwrulesEnabled()
{
return (string)$this->general->enabled == '1' &&
(string)$this->general->fwrules == '1' &&
!empty((string)$this->general->interfaces);
return $this->general->enabled->isEqual('1') &&
$this->general->fwrules->isEqual('1') &&
!$this->general->interfaces->isEmpty();
}

/**
Expand All @@ -98,7 +98,7 @@ private function getConfigPhysicalInterfaces()
{
$result = [];
$cfg = Config::getInstance()->object();
foreach (explode(',', $this->general->interfaces) as $if) {
foreach ($this->general->interfaces->getValues() as $if) {
if (isset($cfg->interfaces->$if) && !empty($cfg->interfaces->$if->if)) {
$result[] = (string)$cfg->interfaces->$if->if;
}
Expand All @@ -108,7 +108,7 @@ private function getConfigPhysicalInterfaces()

private function getConfigThisServerHostname()
{
$hostname = (string)$this->ha->this_server_name;
$hostname = $this->ha->this_server_name->getValue();
if (empty($hostname)) {
$hostname = (string)Config::getInstance()->object()->system->hostname;
}
Expand All @@ -123,26 +123,26 @@ private function getConfigSubnets()
foreach ($this->subnets->subnet6->iterateItems() as $subnet_uuid => $subnet) {
$record = [
'id' => $subnet_id++,
'subnet' => (string)$subnet->subnet,
'subnet' => $subnet->subnet->getValue(),
'option-data' => [],
'pools' => [],
'pd-pools' => [],
'reservations' => []
];
$if = (string)$subnet->interface;
$if = $subnet->interface->getValue();
if (isset($cfg->interfaces->$if) && !empty($cfg->interfaces->$if->if)) {
$record['interface'] = (string)$cfg->interfaces->$if->if;
}
if (!$subnet->{'pd-allocator'}->isEmpty()) {
$record['pd-allocator'] = (string)$subnet->{'pd-allocator'};
$record['pd-allocator'] = $subnet->{'pd-allocator'}->getValue();
}
if (!$subnet->allocator->isEmpty()) {
$record['allocator'] = (string)$subnet->allocator;
$record['allocator'] = $subnet->allocator->getValue();
}
/* standard option-data elements */
foreach ($subnet->option_data->iterateItems() as $key => $value) {
$target_fieldname = str_replace('_', '-', $key);
if ((string)$value != '') {
if (!$value->isEqual('')) {
$record['option-data'][] = [
'name' => $target_fieldname,
'data' => (string)$value
Expand All @@ -155,7 +155,7 @@ private function getConfigSubnets()
}
}
/* add pools */
foreach (array_filter(explode("\n", $subnet->pools)) as $pool) {
foreach (array_filter(explode("\n", $subnet->pools->getValue())) as $pool) {
$record['pools'][] = ['pool' => $pool];
}
/* add pd-pools */
Expand All @@ -164,27 +164,27 @@ private function getConfigSubnets()
continue;
}
$record['pd-pools'][] = [
'prefix' => (string)$pdpool->prefix,
'prefix' => $pdpool->prefix->getValue(),
'prefix-len' => (int)$pdpool->prefix_len->getValue(),
'delegated-len' => (int)$pdpool->delegated_len->getValue()
];
}
/* static reservations */
foreach ($this->reservations->reservation->iterateItems() as $key => $reservation) {
if ($reservation->subnet != $subnet_uuid) {
if (!$reservation->subnet->isEqual($subnet_uuid)) {
continue;
}
$res = ['option-data' => []];
foreach (['duid', 'hostname'] as $key) {
if (!empty((string)$reservation->$key)) {
$res[str_replace('_', '-', $key)] = (string)$reservation->$key;
if (!$reservation->$key->isEmpty()) {
$res[str_replace('_', '-', $key)] = $reservation->$key->getValue();
}
}
$res['ip-addresses'] = explode(',', (string)$reservation->ip_address);
$res['ip-addresses'] = explode(',', $reservation->ip_address->getValue());
if (!$reservation->domain_search->isEmpty()) {
$res['option-data'][] = [
'name' => 'domain-search',
'data' => (string)$reservation->domain_search
'data' => $reservation->domain_search->getValue()
];
}
$record['reservations'][] = $res;
Expand All @@ -199,7 +199,6 @@ private function getExpiredLeasesProcessingConfig()
$config = [];
$lexpireFields = iterator_to_array($this->lexpire->iterateItems());
foreach ($lexpireFields as $fieldName => $fieldValue) {
$value = $fieldValue->__toString();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be unused.

if (!$fieldValue->isEqual('')) {
$keaFieldName = str_replace('_', '-', $fieldName);
$config[$keaFieldName] = (int)$fieldValue->getValue();
Expand All @@ -212,7 +211,7 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp6.conf')
{
$cnf = [
'Dhcp6' => [
'valid-lifetime' => (int)$this->general->valid_lifetime->__toString(),
'valid-lifetime' => (int)$this->general->valid_lifetime->getValue(),
'interfaces-config' => [
'interfaces' => $this->getConfigPhysicalInterfaces()
],
Expand Down Expand Up @@ -247,7 +246,7 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp6.conf')
$cnf['Dhcp6']['hooks-libraries'][] = [
'library' => '/usr/local/lib/kea/hooks/libdhcp_lease_cmds.so'
];
if (!empty((string)$this->ha->enabled)) {
if (!$this->ha->enabled->isEmpty()) {
$record = [
'library' => '/usr/local/lib/kea/hooks/libdhcp_ha.so',
'parameters' => [
Expand All @@ -258,7 +257,7 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp6.conf')
'heartbeat-delay' => 10000,
'max-response-delay' => 60000,
'max-ack-delay' => 5000,
'max-unacked-clients' => (int)((string)$this->ha->max_unacked_clients),
'max-unacked-clients' => (int)$this->ha->max_unacked_clients->getValue(),
'sync-timeout' => 60000,
]
]
Expand All @@ -269,7 +268,7 @@ public function generateConfig($target = '/usr/local/etc/kea/kea-dhcp6.conf')
$record['parameters']['high-availability'][0]['peers'] = [];
}
$record['parameters']['high-availability'][0]['peers'][] = array_map(
fn($x) => (string)$x,
fn($x) => $x->getValue(),
iterator_to_array($peer->iterateItems())
);
}
Expand Down