diff --git a/dhcpd/CHANGELOG b/dhcpd/CHANGELOG
index 4af47551c..e83f69e98 100644
--- a/dhcpd/CHANGELOG
+++ b/dhcpd/CHANGELOG
@@ -21,3 +21,5 @@ Added a field on the Client Options page for the DHCP server identifier.
Fixed a bug that causes hosts to be deleted when searching for them!
---- Changes since 1.410 ----
Clashes between hosts with the same IP address, MAC address or hostname are no longer allowed by default - but this can be changed on the DHCP Server access control page in the Webmin User's module.
+---- Changes since 1.420 ----
+Support the new configuration file format for custom options, as used in DHCPd version 3.
diff --git a/dhcpd/edit_options.cgi b/dhcpd/edit_options.cgi
index 9a84d1d79..d9aeb4831 100755
--- a/dhcpd/edit_options.cgi
+++ b/dhcpd/edit_options.cgi
@@ -128,32 +128,13 @@ print &option_input($text{'eopt_slps'}, "slp-service-scope", \@opts, 3,
$text{'eopt_slpsonly'});
print "\n";
-# Show custom options
-print "
\n";
-@custom = grep { $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
- $_->{'values'}->[1] ne 'code' } @opts;
-push(@custom, undef);
-push(@custom, undef) if (@custom%2 == 1);
-for($i=0; $i<@custom; $i++) {
- $o = $custom[$i];
- print "\n" if ($i%2 == 0);
- print "$text{'eopt_custom'} \n";
- print "$text{'eopt_cnum'}\n";
- local ($ov, @v) = @{$o->{'values'}};
- printf " \n",
- $ov =~ /^option-(\S+)$/ ? $1 : '';
- print "$text{'eopt_cval'}\n";
- printf " \n",
- join(" ", @v);
- print " \n" if ($i%2 != 0);
- }
-
if ($config{'dhcpd_version'} >= 3) {
# Show option definitions
print " \n";
@defs = grep { $_->{'values'}->[1] eq 'code' &&
$_->{'values'}->[3] eq '=' } @opts;
push(@defs, undef);
+ %optdef = ( );
for($i=0; $i<@defs; $i++) {
$o = $defs[$i];
print "\n";
@@ -168,6 +149,49 @@ if ($config{'dhcpd_version'} >= 3) {
printf " \n",
$o->{'values'}->[4];
print " \n";
+ $optdef{$o->{'values'}->[0]} = $o if ($o->{'values'}->[0]);
+ }
+
+ # Show values for custom options
+ if (keys %optdef) {
+ @custom = grep { $optdef{$_->{'values'}->[0]} &&
+ $_->{'values'}->[1] ne 'code' } @opts;
+ push(@custom, undef);
+ push(@custom, undef) if (@custom%2 == 1);
+ for($i=0; $i<@custom; $i++) {
+ $o = $custom[$i];
+ print " $text{'eopt_custom'} \n";
+ print "$text{'eopt_cname'}\n";
+ local ($ov, @v) = @{$o->{'values'}};
+ print &ui_select("cname_$i", $ov,
+ [ [ "", " " ],
+ sort { $a cmp $b } keys %optdef ],
+ 1, 0, $ov ? 1 : 0);
+ print "$text{'eopt_cval'}\n";
+ print &ui_textbox("cval_$i", join(" ", @v), 40);
+ print " \n";
+ }
+ }
+ }
+else {
+ # Show custom numeric options
+ print " \n";
+ @custom = grep { $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
+ $_->{'values'}->[1] ne 'code' } @opts;
+ push(@custom, undef);
+ push(@custom, undef) if (@custom%2 == 1);
+ for($i=0; $i<@custom; $i++) {
+ $o = $custom[$i];
+ print "\n" if ($i%2 == 0);
+ print "$text{'eopt_custom'} \n";
+ print "$text{'eopt_cnum'}\n";
+ local ($ov, @v) = @{$o->{'values'}};
+ printf " \n",
+ $ov =~ /^option-(\S+)$/ ? $1 : '';
+ print "$text{'eopt_cval'}\n";
+ printf " \n",
+ join(" ", @v);
+ print " \n" if ($i%2 != 0);
}
}
diff --git a/dhcpd/lang/en b/dhcpd/lang/en
index d1d5023a4..4757a5bdc 100644
--- a/dhcpd/lang/en
+++ b/dhcpd/lang/en
@@ -179,6 +179,7 @@ sopt_invalidipp=is not a valid IP address pair (like 1.2.3.4,5.6.7.8)
sopt_edname='$1' is not a valid option name
sopt_ednum='$1' is not a valid option number
sopt_edtype='$1' is not a valid option type
+sopt_ecval=Missing value for custom option '$1'
sshared_faildel=Failed to delete shared network
sshared_failsave=Failed to save shared network
@@ -281,6 +282,7 @@ eopt_nbntype=NetBIOS node type
eopt_toffset=Time offset
eopt_custom=Custom option
eopt_cnum=Number
+eopt_cname=Name
eopt_cval=Value
eopt_def=Option definition
eopt_dname=Option name
diff --git a/dhcpd/save_options.cgi b/dhcpd/save_options.cgi
index 6e8b8c1d7..8910f43d7 100755
--- a/dhcpd/save_options.cgi
+++ b/dhcpd/save_options.cgi
@@ -82,30 +82,13 @@ elsif ($in{'level'} eq "shared-network") {
$ret="edit_shared.cgi?idx=$in{'idx'}";
}
-# save custom options
-@custom = grep { $_->{'name'} eq 'option' &&
- $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
- $_->{'values'}->[1] ne 'code' }
- @{$client->{'members'}};
-for($i=0; defined($in{"cnum_$i"}); $i++) {
- next if (!$in{"cnum_$i"} || !$in{"cval_$i"});
- $in{"cnum_$i"} =~ /^\d+$/ ||
- ($config{'dhcpd_version'} >= 3 && $in{"cnum_$i"} =~ /^\S+$/) ||
- &error(&text('sopt_ednum', $in{"cnum_$i"}));
- local $cv = $in{"cval_$i"};
- $cv = "\"$cv\"" if ($cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/);
- push(@newcustom, { 'name' => 'option',
- 'values' => [ 'option-'.$in{"cnum_$i"},
- $cv ] } );
- }
-&save_directive($client, \@custom, \@newcustom, $indent, 1);
-
if ($config{'dhcpd_version'} >= 3) {
- # save option definitions
+ # Save option definitions
@defs = grep { $_->{'name'} eq 'option' &&
$_->{'values'}->[1] eq 'code' &&
$_->{'values'}->[3] eq '=' }
@{$client->{'members'}};
+ %optdef = map { $_->{'values'}->[0], $_ } @defs;
for($i=0; defined($in{"dname_$i"}); $i++) {
next if (!$in{"dname_$i"} || !$in{"dnum_$i"} ||
!$in{"dtype_$i"});
@@ -122,6 +105,43 @@ if ($config{'dhcpd_version'} >= 3) {
] } );
}
&save_directive($client, \@defs, \@newdefs, $indent, 1);
+
+ # Save custom options
+ @custom = grep { $_->{'name'} eq 'option' &&
+ $optdef{$_->{'values'}->[0]} &&
+ $_->{'values'}->[1] ne 'code' }
+ @{$client->{'members'}};
+ for($i=0; defined($in{"cname_$i"}); $i++) {
+ next if ($in{"cname_$i"} eq "");
+ local $cv = $in{"cval_$i"};
+ $cv =~ /\S/ || &error(&text('sopt_ecval', $in{"cname_$i"}));
+ $cv = "\"$cv\""
+ if ($cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/);
+ push(@newcustom, { 'name' => 'option',
+ 'values' => [ $in{"cname_$i"}, $cv ] } );
+ }
+ &save_directive($client, \@custom, \@newcustom, $indent, 1);
+ }
+else {
+ # Save custom options
+ @custom = grep { $_->{'name'} eq 'option' &&
+ $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
+ $_->{'values'}->[1] ne 'code' }
+ @{$client->{'members'}};
+ for($i=0; defined($in{"cnum_$i"}); $i++) {
+ next if (!$in{"cnum_$i"} || !$in{"cval_$i"});
+ $in{"cnum_$i"} =~ /^\d+$/ ||
+ ($config{'dhcpd_version'} >= 3 &&
+ $in{"cnum_$i"} =~ /^\S+$/) ||
+ &error(&text('sopt_ednum', $in{"cnum_$i"}));
+ local $cv = $in{"cval_$i"};
+ $cv = "\"$cv\""
+ if ($cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/);
+ push(@newcustom, { 'name' => 'option',
+ 'values' => [ 'option-'.$in{"cnum_$i"},
+ $cv ] } );
+ }
+ &save_directive($client, \@custom, \@newcustom, $indent, 1);
}
&flush_file_lines();