mirror of
https://github.com/opnsense/core.git
synced 2026-06-03 13:59:25 -04:00
Services: Kea DHCPv4: Add client-id to reservations (#10288)
* Services: Kea DHCPv4: Add client-id to reservations * Should be client_id in the row * Add client_id to dhcpv4 config generator * client-id is stored differently in the running configuration and the lease endpoint, it must be normalized here so we can return a correct match in is_reserved * Fix typo in client_id * Use MAC address instead of Ether address in validation message, fix missing back reference in DHCPv6 reservation validation * Update src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php Co-authored-by: Franco Fichtner <franco@opnsense.org> * Update src/opnsense/mvc/app/models/OPNsense/Kea/KeaDhcpv4.php Co-authored-by: Franco Fichtner <franco@opnsense.org> --------- Co-authored-by: Franco Fichtner <franco@opnsense.org>
This commit is contained in:
parent
fe8c0f27ca
commit
8edd6eef67
8 changed files with 50 additions and 6 deletions
|
|
@ -17,6 +17,12 @@
|
|||
<type>text</type>
|
||||
<help>MAC/Ether address of the client in question</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>reservation.client_id</id>
|
||||
<label>Client ID</label>
|
||||
<type>text</type>
|
||||
<help>ID of the client in question</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>reservation.hostname</id>
|
||||
<label>Hostname</label>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@ class KeaDhcpv4 extends BaseModel
|
|||
if (!Util::isIPInCIDR($reservation->ip_address->getValue(), $subnet)) {
|
||||
$messages->appendMessage(new Message(gettext("Address not in specified subnet"), $key . ".ip_address"));
|
||||
}
|
||||
if (!$reservation->client_id->isEmpty() && !$reservation->hw_address->isEmpty()) {
|
||||
$messages->appendMessage(new Message(gettext("Either a client ID or a MAC address should be specified, but not both"), $key . ".hw_address"));
|
||||
} elseif ($reservation->client_id->isEmpty() && $reservation->hw_address->isEmpty()) {
|
||||
$messages->appendMessage(new Message(gettext("Either a client ID or a MAC address should be specified."), $key . ".hw_address"));
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
|
|
@ -198,6 +203,8 @@ class KeaDhcpv4 extends BaseModel
|
|||
}
|
||||
if (!$reservation->hw_address->isEmpty()) {
|
||||
$res['hw-address'] = str_replace('-', ':', $reservation->hw_address->getValue());
|
||||
} elseif (!$reservation->client_id->isEmpty()) {
|
||||
$res['client-id'] = $reservation->client_id->getValue();
|
||||
}
|
||||
|
||||
// Add DHCP option-data elements for reservations
|
||||
|
|
|
|||
|
|
@ -246,6 +246,9 @@
|
|||
<check001>
|
||||
<reference>hw_address.check001</reference>
|
||||
</check001>
|
||||
<check002>
|
||||
<reference>client_id.check001</reference>
|
||||
</check002>
|
||||
</Constraints>
|
||||
<Required>Y</Required>
|
||||
</subnet>
|
||||
|
|
@ -260,7 +263,6 @@
|
|||
</Constraints>
|
||||
</ip_address>
|
||||
<hw_address type="MacAddressField">
|
||||
<Required>Y</Required>
|
||||
<Constraints>
|
||||
<check001>
|
||||
<ValidationMessage>Duplicate entry exists.</ValidationMessage>
|
||||
|
|
@ -272,6 +274,19 @@
|
|||
</check001>
|
||||
</Constraints>
|
||||
</hw_address>
|
||||
<client_id type="TextField">
|
||||
<Mask>/^(?:[0-9A-Fa-f]{2}(?::[0-9A-Fa-f]{2})+)$/</Mask>
|
||||
<ValidationMessage>Value must be a colon-separated hexadecimal sequence (e.g., 01:02:f3).</ValidationMessage>
|
||||
<Constraints>
|
||||
<check001>
|
||||
<ValidationMessage>Duplicate entry exists.</ValidationMessage>
|
||||
<type>UniqueConstraint</type>
|
||||
<addFields>
|
||||
<field1>subnet</field1>
|
||||
</addFields>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</client_id>
|
||||
<hostname type="HostnameField">
|
||||
<IsDNSName>Y</IsDNSName>
|
||||
</hostname>
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ class KeaDhcpv6 extends BaseModel
|
|||
$messages->appendMessage(new Message(gettext("Either an IP address or a Prefix should be specified."), $key . ".ip_address"));
|
||||
}
|
||||
if (!$reservation->duid->isEmpty() && !$reservation->hw_address->isEmpty()) {
|
||||
$messages->appendMessage(new Message(gettext("Either a DUID or an Ether address should be specified, but not both"), $key . ".duid"));
|
||||
$messages->appendMessage(new Message(gettext("Either a DUID or an MAC address should be specified, but not both"), $key . ".duid"));
|
||||
} elseif ($reservation->duid->isEmpty() && $reservation->hw_address->isEmpty()) {
|
||||
$messages->appendMessage(new Message(gettext("Either a DUID or an Ether address should be specified."), $key . ".duid"));
|
||||
$messages->appendMessage(new Message(gettext("Either a DUID or an MAC address should be specified."), $key . ".duid"));
|
||||
}
|
||||
}
|
||||
// validate changed subnets
|
||||
|
|
|
|||
|
|
@ -228,6 +228,9 @@
|
|||
<check001>
|
||||
<reference>duid.check001</reference>
|
||||
</check001>
|
||||
<check002>
|
||||
<reference>hw_address.check001</reference>
|
||||
</check002>
|
||||
</Constraints>
|
||||
<Required>Y</Required>
|
||||
</subnet>
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@
|
|||
if (params.has('hostname')) $('#reservation\\.hostname').val(params.get('hostname'));
|
||||
if (params.has('ip_address')) $('#reservation\\.ip_address').val(params.get('ip_address'));
|
||||
if (params.has('hw_address')) $('#reservation\\.hw_address').val(params.get('hw_address'));
|
||||
if (params.has('client_id')) $('#reservation\\.client_id').val(params.get('client_id'));
|
||||
history.replaceState(null, null, window.location.pathname + '#reservations');
|
||||
});
|
||||
$(this).find('.command-add').trigger('click');
|
||||
|
|
|
|||
|
|
@ -103,12 +103,22 @@
|
|||
},
|
||||
"commands": function (column, row) {
|
||||
const baseUrl = `/ui/kea/dhcp/v4#reservations`;
|
||||
const searchUrl = `${baseUrl}&search=${encodeURIComponent(row.hwaddr || '')}`;
|
||||
let searchValue = '';
|
||||
|
||||
if (row.is_reserved.includes('client_id')) {
|
||||
searchValue = row.client_id || '';
|
||||
} else if (row.is_reserved.includes('hwaddr')) {
|
||||
searchValue = row.hwaddr || '';
|
||||
}
|
||||
|
||||
const addUrlParams = {
|
||||
ip_address: row.address || '',
|
||||
hw_address: row.hwaddr || '',
|
||||
client_id: row.client_id || '',
|
||||
hostname: row.hostname || ''
|
||||
};
|
||||
|
||||
const searchUrl = `${baseUrl}&search=${encodeURIComponent(searchValue)}`;
|
||||
const addUrl = `${baseUrl}?${new URLSearchParams(addUrlParams)}`;
|
||||
|
||||
let reservationBtn;
|
||||
|
|
|
|||
|
|
@ -52,9 +52,11 @@ def get_reservation_keys(record, proto):
|
|||
subnet_id = record.get('subnet-id')
|
||||
|
||||
if subnet_id is not None:
|
||||
# Reservation returns hw-address and duid like this: "01:48:90"...
|
||||
hwaddr = record.get('hw-address', '').lower()
|
||||
duid = record.get('duid', '').lower()
|
||||
client_id = record.get('client-id', '').lower()
|
||||
# ...but client_id like this: "014890"
|
||||
client_id = record.get('client-id', '').replace(':', '').lower()
|
||||
|
||||
if hwaddr:
|
||||
keys.append((subnet_id, 'hwaddr', hwaddr))
|
||||
|
|
@ -88,7 +90,7 @@ def build_reserved_matches(config, leases, proto, dhcp_key, config_key):
|
|||
for reservation in subnet.get('reservations', []):
|
||||
hwaddr = reservation.get('hw-address', '').lower()
|
||||
duid = reservation.get('duid', '').lower()
|
||||
client_id = reservation.get('client-id', '').lower()
|
||||
client_id = reservation.get('client-id', '').replace(':', '').lower()
|
||||
|
||||
if hwaddr and (subnet_id, 'hwaddr', hwaddr) in wanted:
|
||||
matches[(subnet_id, 'hwaddr', hwaddr)] = 'hwaddr'
|
||||
|
|
|
|||
Loading…
Reference in a new issue