Files
webmin/kea-dhcp/edit_options.cgi
Ilia Ross 184887d365
Some checks failed
Tests / prove (push) Has been cancelled
Build / build (push) Has been cancelled
Close inactive / close-inactive (push) Has been cancelled
Fix to use direct ACL checks in Kea DHCP module
*Note: Removes Kea-specific ACL wrapper helpers and switches ACL editor/runtime checks to standard Webmin handling with direct supplied ACL values and get_module_acl checks.
2026-05-30 02:53:48 +02:00

248 lines
10 KiB
Perl
Executable File

#!/usr/local/bin/perl
# Edit global Kea DHCP options for DHCPv4 or DHCPv6.
use strict;
use warnings;
require './kea-dhcp-lib.pl'; ## no critic
&ReadParse();
our (%in, %text);
&error_setup($text{'eacl_aviol'});
my $ver = $in{'version'} == 6 ? 6 : 4;
my %access = &get_module_acl();
&error("$text{'eacl_np'} $text{'eacl_pedit'.$ver}")
if (!$access{'edit'.$ver});
my ($c, $root, $data, $err) = &kea_read_dhcp_config($ver);
&error($err) if ($err);
# Render one global settings form for either Dhcp4 or Dhcp6. Each tab writes
# back to the same JSON root object, so the save handler can update all fields
# in one pass without losing hidden tab values.
&ui_print_header(undef, &text('options_title', $ver), "", undef, 1, 1);
print &kea_comment_loss_warning($c);
print &ui_alert_box($text{'dhcp6_ra_warn'}, "warn", undef, undef, "")
if ($ver == 6);
print &ui_form_start("save_options.cgi", "post");
print &ui_hidden("version", $ver);
my @tabs = (
[ 'interfaces', $text{'tab_interfaces'} ],
[ 'storage', $text{'tab_storage'} ],
[ 'logging', $text{'tab_logging'} ],
[ 'ddns_sender', $text{'tab_ddns_sender'} ],
[ 'timers', $text{'tab_timers'} ],
[ 'options', $text{'tab_options'} ],
[ 'advanced', $text{'tab_advanced'} ],
);
print &ui_tabs_start(\@tabs, "mode", $in{'mode'} || "interfaces", 1);
# Interfaces decide whether Kea listens at all. The DHCPv4 socket mode is kept
# beside the interface list because it only affects packet capture on DHCPv4.
print &ui_tabs_start_tab("mode", "interfaces");
print &ui_div($text{'interfaces_desc'});
my $ifconf = ref($root->{'interfaces-config'}) eq 'HASH' ?
$root->{'interfaces-config'} : { };
my $ifaces = ref($ifconf->{'interfaces'}) eq 'ARRAY' ?
join(" ", @{$ifconf->{'interfaces'}}) : "";
print &ui_table_start($text{'interfaces_title'}, "width=100%", 4);
print &ui_table_row(&kea_field_hlink('interfaces', $text{'interfaces_list'}),
&ui_textbox("interfaces", $ifaces, 60));
if ($ver == 4) {
print &ui_table_row(&kea_field_hlink('dhcp-socket-type',
$text{'interfaces_socket'}),
&ui_select("dhcp-socket-type", $ifconf->{'dhcp-socket-type'} || "",
[ [ "", $text{'socket_default'} ],
[ "raw", $text{'socket_raw'} ],
[ "udp", $text{'socket_udp'} ] ]));
}
print &ui_table_end();
print &ui_tabs_end_tab("mode", "interfaces");
# Storage and control sockets are global daemon settings, not subnet settings.
print &ui_tabs_start_tab("mode", "storage");
print &ui_div($text{'storage_desc'});
my $lease = ref($root->{'lease-database'}) eq 'HASH' ?
$root->{'lease-database'} : { };
print &ui_table_start($text{'lease_database'}, "width=100%", 4);
print &ui_table_row(&kea_field_hlink('lease-database-type', $text{'lease_type'}),
&ui_textbox("lease_type", $lease->{'type'} || "", 20));
print &ui_table_row(&kea_field_hlink('lfc-interval',
$text{'lease_lfc_interval'}),
&ui_textbox("lease_lfc_interval", $lease->{'lfc-interval'} || "", 12));
print &ui_table_row(&kea_field_hlink('lease-database-name',
$text{'lease_name'}),
&ui_textbox("lease_name", $lease->{'name'} || "", 30));
print &ui_table_row(&kea_field_hlink('lease-database-host',
$text{'lease_host'}),
&ui_textbox("lease_host", $lease->{'host'} || "", 30));
print &ui_table_row(&kea_field_hlink('lease-database-port',
$text{'lease_port'}),
&ui_textbox("lease_port", $lease->{'port'} || "", 8));
print &ui_table_row(&kea_field_hlink('lease-database-user',
$text{'lease_user'}),
&ui_textbox("lease_user", $lease->{'user'} || "", 24));
my $password_note = $lease->{'password'} ?
" ".&ui_tag('small', $text{'secret_keep_blank'}, {
'style' => 'color:var(--text-color-light, #777)' }) : "";
print &ui_table_row(&kea_field_hlink('lease-database-password',
$text{'lease_password'}),
&ui_password("lease_password", "", 24).$password_note);
print &ui_table_end();
my $socket = ref($root->{'control-socket'}) eq 'HASH' ?
$root->{'control-socket'} : { };
print &ui_table_start($text{'control_socket'}, "width=100%", 4);
print &ui_table_row(&kea_field_hlink('control-socket-type',
$text{'control_socket_type'}),
&ui_select("control_socket_type", $socket->{'socket-type'} || "",
[ [ "", $text{'socket_default'} ],
[ "unix", "Unix" ] ]));
print &ui_table_row(&kea_field_hlink('control-socket-name',
$text{'control_socket_name'}),
&ui_textbox("control_socket_name", $socket->{'socket-name'} || "", 50));
print &ui_table_end();
print &ui_tabs_end_tab("mode", "storage");
# Logger settings live at the daemon root, beside lease database and timers.
print &ui_tabs_start_tab("mode", "logging");
print &ui_div($text{'logging_desc'});
print &ui_subheading($text{'logging_loggers'});
&kea_logger_rows($root->{'loggers'}, "log_");
print &ui_tabs_end_tab("mode", "logging");
# DHCP-DDNS sender settings control whether this daemon submits name-change
# requests to the standalone D2 daemon. They are distinct from D2's own
# listener/zones/keys settings.
print &ui_tabs_start_tab("mode", "ddns_sender");
print &ui_div(&text('ddns_sender_settings_desc', $ver));
my $ddns = ref($root->{'dhcp-ddns'}) eq 'HASH' ?
$root->{'dhcp-ddns'} : { };
my $bool_opts = [
[ "", $text{'inherit_default'} ],
[ "true", $text{'yes'} ],
[ "false", $text{'no'} ],
];
print &ui_table_start($text{'ddns_sender_connectivity'}, "width=100%", 4);
print &ui_table_row(&kea_field_hlink('ddns-enable-updates',
$text{'ddns_enable_updates'}),
&ui_select("ddns_enable_updates",
&kea_bool_value($ddns->{'enable-updates'}), $bool_opts));
print &ui_table_row(&kea_field_hlink('ddns-server-ip',
$text{'ddns_server_ip'}),
&ui_textbox("ddns_server_ip", $ddns->{'server-ip'} || "", 24));
print &ui_table_row(&kea_field_hlink('ddns-server-port',
$text{'ddns_server_port'}),
&ui_textbox("ddns_server_port",
defined($ddns->{'server-port'}) ? $ddns->{'server-port'} : "",
8));
print &ui_table_row(&kea_field_hlink('ddns-sender-ip',
$text{'ddns_sender_ip'}),
&ui_textbox("ddns_sender_ip", $ddns->{'sender-ip'} || "", 24));
print &ui_table_row(&kea_field_hlink('ddns-sender-port',
$text{'ddns_sender_port'}),
&ui_textbox("ddns_sender_port",
defined($ddns->{'sender-port'}) ? $ddns->{'sender-port'} : "",
8));
print &ui_table_row(&kea_field_hlink('ddns-max-queue-size',
$text{'ddns_max_queue_size'}),
&ui_textbox("ddns_max_queue_size",
defined($ddns->{'max-queue-size'}) ?
$ddns->{'max-queue-size'} : "", 10));
print &ui_table_row(&kea_field_hlink('ncr-protocol',
$text{'ddns_ncr_protocol'}),
&ui_select("ddns_ncr_protocol", $ddns->{'ncr-protocol'} || "",
&kea_select_options($ddns->{'ncr-protocol'},
$text{'socket_default'}, 'UDP')));
print &ui_table_row(&kea_field_hlink('ncr-format',
$text{'ddns_ncr_format'}),
&ui_select("ddns_ncr_format", $ddns->{'ncr-format'} || "",
&kea_select_options($ddns->{'ncr-format'},
$text{'socket_default'}, 'JSON')));
print &ui_table_end();
print &ui_table_start($text{'ddns_sender_behavior'}, "width=100%", 4);
my %ddns_bool_labels = (
'ddns-send-updates' => $text{'ddns_send_updates'},
'ddns-override-no-update' => $text{'ddns_override_no_update'},
'ddns-override-client-update' => $text{'ddns_override_client_update'},
'ddns-update-on-renew' => $text{'ddns_update_on_renew'},
);
foreach my $k ('ddns-send-updates', 'ddns-override-no-update',
'ddns-override-client-update', 'ddns-update-on-renew') {
print &ui_table_row(&kea_field_hlink($k, $ddns_bool_labels{$k}),
&ui_select($k, &kea_bool_value($root->{$k}), $bool_opts));
}
print &ui_table_row(&kea_field_hlink('ddns-replace-client-name',
$text{'ddns_replace_client_name'}),
&ui_select("ddns-replace-client-name",
$root->{'ddns-replace-client-name'} || "",
&kea_select_options($root->{'ddns-replace-client-name'},
$text{'socket_default'},
'never', 'when-present',
'when-not-present', 'always')));
my %ddns_text_labels = (
'ddns-generated-prefix' => $text{'ddns_generated_prefix'},
'ddns-qualifying-suffix' => $text{'ddns_qualifying_suffix'},
'ddns-conflict-resolution-mode' => $text{'ddns_conflict_resolution_mode'},
'hostname-char-set' => $text{'hostname_char_set'},
'hostname-char-replacement' => $text{'hostname_char_replacement'},
);
foreach my $k ('ddns-generated-prefix', 'ddns-qualifying-suffix',
'ddns-conflict-resolution-mode', 'hostname-char-set',
'hostname-char-replacement') {
print &ui_table_row(&kea_field_hlink($k, $ddns_text_labels{$k}),
&ui_textbox($k, defined($root->{$k}) ? $root->{$k} : "", 32));
}
print &ui_table_end();
print &ui_tabs_end_tab("mode", "ddns_sender");
# Timer defaults apply only when shared networks or subnets do not override.
print &ui_tabs_start_tab("mode", "timers");
print &ui_div($text{'timers_desc'});
print &ui_table_start($text{'options_timers'}, "width=100%", 4);
foreach my $k ('renew-timer', 'rebind-timer', 'valid-lifetime',
'min-valid-lifetime', 'max-valid-lifetime') {
print &ui_table_row(&kea_field_hlink($k),
&ui_textbox($k, defined($root->{$k}) ? $root->{$k} : "", 12));
}
print &ui_table_row(&kea_field_hlink('preferred-lifetime'),
&ui_textbox("preferred-lifetime",
defined($root->{'preferred-lifetime'}) ? $root->{'preferred-lifetime'} : "", 12))
if ($ver == 6);
print &ui_table_end();
print &ui_tabs_end_tab("mode", "timers");
# Common options get named fields; everything else remains editable in the
# additional option-data table below them.
print &ui_tabs_start_tab("mode", "options");
print &ui_div($text{'options_desc'});
&kea_common_option_rows($root->{'option-data'}, $ver, "common_");
&kea_option_data_section($root->{'option-data'}, "opt_", $ver, 1);
print &ui_tabs_end_tab("mode", "options");
# Advanced fields are valid Kea globals but are easy to misuse, so keep them
# away from the everyday options page.
print &ui_tabs_start_tab("mode", "advanced");
print &ui_div(&text('global_advanced_desc', $ver));
print &ui_table_start($text{'global_advanced'}, "width=100%", 4);
if ($ver == 4) {
print &ui_table_row(&kea_field_hlink('authoritative'),
&ui_select("authoritative", &kea_bool_value($root->{'authoritative'}),
[ [ "", $text{'inherit_default'} ],
[ "true", $text{'yes'} ],
[ "false", $text{'no'} ] ]));
}
&kea_advanced_option_rows($root->{'option-data'}, $ver, "adv_");
if ($ver == 4) {
foreach my $k ('next-server', 'server-hostname', 'boot-file-name') {
print &ui_table_row(&kea_field_hlink($k),
&ui_textbox($k, defined($root->{$k}) ? $root->{$k} : "", 40));
}
}
print &ui_table_end();
print &ui_tabs_end_tab("mode", "advanced");
print &ui_tabs_end();
print &ui_form_end([ [ "save", $text{'save'} ] ]);
&ui_print_footer("index.cgi?mode=dhcp$ver", $text{'index_return'});