{{ partial('layout_partials/base_bootgrid_table', formGridPeer)}}
@@ -229,4 +237,5 @@
{{ partial('layout_partials/base_apply_button', {'data_endpoint': '/api/kea/service/reconfigure', 'data_service_widget': 'kea'}) }}
{{ partial("layout_partials/base_dialog",['fields':formDialogSubnet,'id':formGridSubnet['edit_dialog_id'],'label':lang._('Edit Subnet')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogReservation,'id':formGridReservation['edit_dialog_id'],'label':lang._('Edit Reservation')])}}
+{{ partial("layout_partials/base_dialog",['fields':formDialogOption,'id':formGridOption['edit_dialog_id'],'label':lang._('Edit Option')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogPeer,'id':formGridPeer['edit_dialog_id'],'label':lang._('Edit Peer')])}}
diff --git a/src/opnsense/scripts/kea/kea_dhcp_options.py b/src/opnsense/scripts/kea/kea_dhcp_options.py
new file mode 100755
index 0000000000..c7ad0533d8
--- /dev/null
+++ b/src/opnsense/scripts/kea/kea_dhcp_options.py
@@ -0,0 +1,73 @@
+#!/usr/local/bin/python3
+
+"""
+ Copyright (c) 2026 Deciso B.V.
+ Copyright (c) 2025 Ad Schellevis
+ 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.
+
+"""
+
+import csv
+import json
+import argparse
+
+option_src = {
+ 'dhcp': 'iana/dhcpv4-options.csv', # https://www.iana.org/assignments/bootp-dhcp-parameters/
+ 'dhcp6': 'iana/dhcpv6-parameters-2.csv' # https://www.iana.org/assignments/dhcpv6-parameters/
+}
+
+parser = argparse.ArgumentParser()
+parser.add_argument("mode", nargs="?", default="dhcp", choices=["dhcp", "dhcp6"])
+args = parser.parse_args()
+
+assigned = {}
+unassigned = {}
+
+# load IANA data
+with open('/usr/local/opnsense/contrib/' + option_src[args.mode], 'r') as csvfile:
+ for r in csv.reader(csvfile, delimiter=',', quotechar='"'):
+ if not r or not r[0]:
+ continue
+ r_range = [int(x) for x in r[0].split('-') if x.isdigit()]
+ if not r_range or len(r) < 2:
+ continue
+
+ name = r[1].strip().lower()
+
+ for code in range(r_range[0], (r_range[1] if len(r_range) > 1 else r_range[0]) + 1):
+ key = str(code)
+
+ if name in ['unassigned', 'removed/unassigned']:
+ # Only track unassigned for DHCPv4 (256 total), not DHCPv6 (65535 total)
+ if args.mode == 'dhcp':
+ unassigned[key] = f"{name} [{code}]"
+
+ elif name not in ['pad', 'end']:
+ cleaned_name = name.replace('\n', ' ')
+ assigned[key] = f"{cleaned_name} [{code}]"
+
+print(json.dumps({
+ "Assigned": assigned,
+ "Unassigned": unassigned
+}))
diff --git a/src/opnsense/service/conf/actions.d/actions_kea.conf b/src/opnsense/service/conf/actions.d/actions_kea.conf
index 4a04780011..167109e2c6 100644
--- a/src/opnsense/service/conf/actions.d/actions_kea.conf
+++ b/src/opnsense/service/conf/actions.d/actions_kea.conf
@@ -23,6 +23,12 @@ parameters:
type:script_output
message:get kea daemon status
+[list.dhcp_options]
+command:/usr/local/opnsense/scripts/kea/kea_dhcp_options.py dhcp
+type:script_output
+message:request dhcp options
+cache_ttl:86400
+
[list.leases4]
command:/usr/local/opnsense/scripts/kea/get_kea_leases.py
parameters:--proto inet