]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - html/cgi-bin/dhcp.cgi
suricata: Change midstream policy to "pass-flow"
[people/pmueller/ipfire-2.x.git] / html / cgi-bin / dhcp.cgi
CommitLineData
ac1cfefa 1#!/usr/bin/perl
70df8302
MT
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
60a05076 5# Copyright (C) 2007-2024 IPFire Team <info@ipfire.org> #
70df8302
MT
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
ac1cfefa 22use strict;
2de0f49f 23use experimental 'smartmatch';
ac1cfefa
MT
24
25# enable only the following on debugging purpose
cb5e9c6c
CS
26#use warnings;
27#use CGI::Carp 'fatalsToBrowser';
ac1cfefa 28
986e08d9 29require '/var/ipfire/general-functions.pl';
ac1cfefa
MT
30require "${General::swroot}/lang.pl";
31require "${General::swroot}/header.pl";
32#workaround to suppress a warning when a variable is used only once
33my @dummy = ( ${Header::colouryellow} );
34undef (@dummy);
35
36our %dhcpsettings=();
37our %netsettings=();
38my %mainsettings=();
39my %timesettings=();
40my $setting = "${General::swroot}/dhcp/settings";
41our $filename1 = "${General::swroot}/dhcp/advoptions"; # Field separator is TAB in this file (comma is standart)
d1883e28 42 # because we need commas in the some data
ac1cfefa 43our $filename2 = "${General::swroot}/dhcp/fixleases";
d1883e28 44our $filename3 = "${General::swroot}/dhcp/advoptions-list"; # Describe the allowed syntax for dhcp options
ac1cfefa
MT
45my $errormessage = '';
46my $warnNTPmessage = '';
47my @nosaved=();
fe6cda92 48my %color = ();
ac1cfefa 49
66c36198 50#Basic syntax allowed for new Option definition. Not implemented: RECORDS & array of RECORDS
60a05076 51our $OptionTypes = 'boolean|((un)?signed )?integer (8|16|32)|ip-address|text|string|encapsulate \w+|array of (ip-address|integer (8|16|32))';
ac1cfefa
MT
52
53&Header::showhttpheaders();
541d93f0
CS
54our @ITFs=('GREEN');
55if (&Header::blue_used()){push(@ITFs,'BLUE');}
ac1cfefa
MT
56
57#Settings1 for the first screen box
58foreach my $itf (@ITFs) {
59 $dhcpsettings{"ENABLE_${itf}"} = 'off';
60 $dhcpsettings{"ENABLEBOOTP_${itf}"} = 'off';
61 $dhcpsettings{"START_ADDR_${itf}"} = '';
62 $dhcpsettings{"END_ADDR_${itf}"} = '';
63 $dhcpsettings{"DOMAIN_NAME_${itf}"} = '';
64 $dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} = '';
65 $dhcpsettings{"MAX_LEASE_TIME_${itf}"} = '';
66 $dhcpsettings{"WINS1_${itf}"} = '';
67 $dhcpsettings{"WINS2_${itf}"} = '';
68 $dhcpsettings{"DNS1_${itf}"} = '';
69 $dhcpsettings{"DNS2_${itf}"} = '';
70 $dhcpsettings{"NTP1_${itf}"} = '';
71 $dhcpsettings{"NTP2_${itf}"} = '';
d1883e28
MT
72 $dhcpsettings{"NEXT_${itf}"} = '';
73 $dhcpsettings{"FILE_${itf}"} = '';
f5fb9a04
MT
74 $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} = '';
75 $dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"} = '';
76 $dhcpsettings{"DNS_UPDATE_KEY_ALGO_${itf}"} = '';
9dbf3c49 77 $dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} = 'off';
ac1cfefa
MT
78}
79
80$dhcpsettings{'SORT_FLEASELIST'} = 'FIPADDR';
81$dhcpsettings{'SORT_LEASELIST'} = 'IPADDR';
82
f5fb9a04
MT
83# DNS Update settings
84$dhcpsettings{'DNS_UPDATE_ENABLED'} = 'off';
85
ac1cfefa
MT
86#Settings2 for editing the multi-line list
87#Must not be saved with writehash !
88$dhcpsettings{'FIX_MAC'} = '';
89$dhcpsettings{'FIX_ADDR'} = '';
90$dhcpsettings{'FIX_ENABLED'} = 'off';
91$dhcpsettings{'FIX_NEXTADDR'} = '';
92$dhcpsettings{'FIX_FILENAME'} = '';
93$dhcpsettings{'FIX_ROOTPATH'} = '';
94$dhcpsettings{'FIX_REMARK'} = '';
95$dhcpsettings{'ACTION'} = '';
96$dhcpsettings{'KEY1'} = '';
97$dhcpsettings{'KEY2'} = '';
98@nosaved=('FIX_MAC','FIX_ADDR','FIX_ENABLED','FIX_NEXTADDR',
99 'FIX_FILENAME','FIX_ROOTPATH','FIX_REMARK');
100
101$dhcpsettings{'ADVOPT_ENABLED'} = '';
102$dhcpsettings{'ADVOPT_NAME'} = '';
103$dhcpsettings{'ADVOPT_DATA'} = '';
104unshift (@nosaved,'ADVOPT_ENABLED','ADVOPT_NAME','ADVOPT_DATA');
105foreach my $itf (@ITFs) {
106 $dhcpsettings{"ADVOPT_SCOPE_${itf}"} = 'off';
107 unshift (@nosaved, "ADVOPT_SCOPE_${itf}");
108}
109
110# Read Ipcop settings
111&General::readhash("${General::swroot}/ethernet/settings", \%netsettings);
112&General::readhash("${General::swroot}/main/settings", \%mainsettings);
113&General::readhash("${General::swroot}/time/settings", \%timesettings);
8186b372 114&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
ac1cfefa
MT
115
116#Get GUI values
117&Header::getcgihash(\%dhcpsettings);
118
119open(FILE, "$filename1") or die 'Unable to open dhcp advanced options file.';
120our @current1 = <FILE>;
121close(FILE);
122# Extract OptionDefinition
123foreach my $line (@current1) {
124 #chomp($line); # remove newline #don't know why, but this remove newline in @current1 .... !
125 my @temp = split(/\t/,$line);
126 AddNewOptionDefinition ($temp[1] . ' ' . $temp[2]);
127}
128
129open(FILE, "$filename2") or die 'Unable to open fixed leases file.';
130our @current2 = <FILE>;
131close(FILE);
132
2bbf1766 133# Open and read-in file which contains the list of allowed advanced options.
5410fcbc 134open(FILE, $filename3) or die "Could not open $filename3. $!\n";
2bbf1766
SS
135
136# Grab file content.
137my @advoptions_list = <FILE>;
138
139# Close file handle.
140close(FILE);
141
ac1cfefa
MT
142# Check Settings1 first because they are needed by &buildconf
143if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
144 foreach my $itf (@ITFs) {
145 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on' ) {
146 # "Start" is defined, need "End" and vice versa
147 if ($dhcpsettings{"START_ADDR_${itf}"}) {
148 if (!(&General::validip($dhcpsettings{"START_ADDR_${itf}"}))) {
149 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
150 goto ERROR;
151 }
152 if (!$dhcpsettings{"END_ADDR_${itf}"}) {
153 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
154 goto ERROR;
155 }
66c36198 156 if (! &General::IpInSubnet ( $dhcpsettings{"START_ADDR_${itf}"},
ac1cfefa
MT
157 $netsettings{"${itf}_NETADDRESS"},
158 $netsettings{"${itf}_NETMASK"})) {
159 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
160 goto ERROR;
161 }
162 }
66c36198 163
ac1cfefa
MT
164 if ($dhcpsettings{"END_ADDR_${itf}"}) {
165 if (!(&General::validip($dhcpsettings{"END_ADDR_${itf}"}))) {
166 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
167 goto ERROR;
168 }
169 if (!$dhcpsettings{"START_ADDR_${itf}"}) {
170 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
171 goto ERROR;
172 }
66c36198 173 if (! &General::IpInSubnet ( $dhcpsettings{"END_ADDR_${itf}"},
ac1cfefa 174 $netsettings{"${itf}_NETADDRESS"},
66c36198 175 $netsettings{"${itf}_NETMASK"})) {
ac1cfefa
MT
176 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
177 goto ERROR;
178 }
179 #swap if necessary! (support 255.255.0.0 range, I doubt we need more) GE
180 my @startoct = split (/\./, $dhcpsettings{"START_ADDR_${itf}"});
181 my @endoct = split (/\./, $dhcpsettings{"END_ADDR_${itf}"});
182 if ( $endoct[2]*256+$endoct[3] < $startoct[2]*256+$startoct[3] ) {
183 ($dhcpsettings{"START_ADDR_${itf}"},$dhcpsettings{"END_ADDR_${itf}"}) =
184 ($dhcpsettings{"END_ADDR_${itf}"},$dhcpsettings{"START_ADDR_${itf}"});
185 }
186 }
187
9dbf3c49
AB
188 if ($dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} eq 'on') {
189 if (($dhcpsettings{"START_ADDR_${itf}"}) eq '' && ($dhcpsettings{"END_ADDR_${itf}"}) eq '') {
190 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'dhcp valid range required when deny known clients checked'};
191 goto ERROR;
896fa74d 192 }
9dbf3c49
AB
193 }
194
ac1cfefa
MT
195 if (!($dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} =~ /^\d+$/)) {
196 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid default lease time'} . $dhcpsettings{'DEFAULT_LEASE_TIME_${itf}'};
197 goto ERROR;
198 }
199
200 if (!($dhcpsettings{"MAX_LEASE_TIME_${itf}"} =~ /^\d+$/)) {
201 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid max lease time'} . $dhcpsettings{'MAX_LEASE_TIME_${itf}'};
202 goto ERROR;
203 }
204
205 if ($dhcpsettings{"DNS1_${itf}"}) {
206 if (!(&General::validip($dhcpsettings{"DNS1_${itf}"}))) {
207 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid primary dns'};
208 goto ERROR;
209 }
210 }
211 if ($dhcpsettings{"DNS2_${itf}"}) {
212 if (!(&General::validip($dhcpsettings{"DNS2_${itf}"}))) {
213 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid secondary dns'};
214 goto ERROR;
215 }
216 if (! $dhcpsettings{"DNS1_${itf}"}) {
66c36198 217 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary dns without specifying primary'};
ac1cfefa
MT
218 goto ERROR;
219 }
220 }
221
222 if ($dhcpsettings{"WINS1_${itf}"}) {
223 if (!(&General::validip($dhcpsettings{"WINS1_${itf}"}))) {
224 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid wins address'};
225 goto ERROR;
226 }
227 }
228 if ($dhcpsettings{"WINS2_${itf}"}) {
229 if (!(&General::validip($dhcpsettings{"WINS2_${itf}"}))) {
230 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid wins address'};
231 goto ERROR;
232 }
233 if (! $dhcpsettings{"WINS1_${itf}"} ) {
234 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary wins without specifying primary'};
235 goto ERROR;
66c36198 236 }
ac1cfefa 237 }
d1883e28
MT
238 if ($dhcpsettings{"NEXT_${itf}"}) {
239 if (!(&General::validip($dhcpsettings{"NEXT_${itf}"}))) {
240 $errormessage = "next-server on ${itf}: " . $Lang::tr{'invalid ip'};
241 goto ERROR;
242 }
243 }
ac1cfefa
MT
244 if ($dhcpsettings{"NTP1_${itf}"}) {
245 if (!(&General::validip($dhcpsettings{"NTP1_${itf}"}))) {
246 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid primary ntp'};
247 goto ERROR;
248 }
249 if ($dhcpsettings{"NTP1_${itf}"} eq $netsettings{"${itf}_ADDRESS"} && ($timesettings{'ENABLECLNTP'} ne 'on')) {
250 $warnNTPmessage = "DHCP on ${itf}: " . $Lang::tr{'local ntp server specified but not enabled'};
251 #goto ERROR;
252 }
253 }
254 if ($dhcpsettings{"NTP2_${itf}"}) {
255 if (!(&General::validip($dhcpsettings{"NTP2_${itf}"}))) {
256 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid secondary ntp'};
257 goto ERROR;
258 }
259 if ($dhcpsettings{"NTP2_${itf}"} eq $netsettings{"${itf}_ADDRESS"} && ($timesettings{'ENABLECLNTP'} ne 'on')) {
260 $warnNTPmessage = "DHCP on ${itf}: " . $Lang::tr{'local ntp server specified but not enabled'};
261 #goto ERROR;
262 }
263 if (! $dhcpsettings{"NTP1_${itf}"}) {
264 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary ntp without specifying primary'};
265 goto ERROR;
266 }
267 }
268 } # enabled
269 }#loop interface verify
270
a1468f66 271 map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2','q'); # Must not be saved
ac1cfefa
MT
272 &General::writehash($setting, \%dhcpsettings); # Save good settings
273 $dhcpsettings{'ACTION'} = $Lang::tr{'save'}; # create an 'ACTION'
274 map ($dhcpsettings{$_} = '',@nosaved,'KEY1','KEY2'); # and reinit vars to empty
275 &buildconf;
276 ERROR: # Leave the faulty field untouched
277} else {
278 &General::readhash($setting, \%dhcpsettings); # Get saved settings and reset to good if needed
279}
280
281## Sorting of fixed leases
282if ($ENV{'QUERY_STRING'} =~ /^FETHER|^FIPADDR/ ) {
283 my $newsort=$ENV{'QUERY_STRING'};
284 my $act=$dhcpsettings{'SORT_FLEASELIST'};
285 #Reverse actual sort ?
286 if ($act =~ $newsort) {
287 my $Rev='';
288 if ($act !~ 'Rev') {
289 $Rev='Rev';
290 }
291 $newsort.=$Rev;
292 }
293 $dhcpsettings{'SORT_FLEASELIST'}=$newsort;
a1468f66 294 map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2', 'q'); # Must never be saved
ac1cfefa
MT
295 &General::writehash($setting, \%dhcpsettings);
296 &sortcurrent2;
297 $dhcpsettings{'ACTION'} = 'SORT'; # create an 'ACTION'
66c36198 298 map ($dhcpsettings{$_} = '',@nosaved,'KEY1','KEY2');# and reinit vars to empty
ac1cfefa
MT
299}
300
301#Sorting of allocated leases
302&Header::CheckSortOrder;
303
304
66c36198 305## Now manipulate the two multi-line list with Settings2.
ac1cfefa
MT
306# '1' suffix is for ADVANCED OPTIONS
307# '2' suffix is for FIXED LEASES
308
309# Toggle enable/disable field on specified options.
310
311if ($dhcpsettings{'ACTION'} eq $Lang::tr{'toggle enable disable'}.'1') {
312 #move out new line
313 chomp(@current1[$dhcpsettings{'KEY1'}]);
314 my @temp = split(/\t/,@current1[$dhcpsettings{'KEY1'}]); #use TAB separator !
315 $temp[0] = $temp[0] eq 'on' ? '' : 'on'; # Toggle the field
316 @current1[$dhcpsettings{'KEY1'}] = join ("\t",@temp)."\n";
317 $dhcpsettings{'KEY1'} = ''; # End edit mode
318 &General::log($Lang::tr{'dhcp advopt modified'});
319 open(FILE, ">$filename1") or die 'Unable to open dhcp advanced options file.';
320 print FILE @current1;
321 close(FILE);
66c36198 322
ac1cfefa
MT
323 #Write changes to dhcpd.conf.
324 &buildconf;
325}
326
66c36198 327
ac1cfefa
MT
328
329if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'1' &&
330 $dhcpsettings{'SUBMIT'} ne $Lang::tr{'dhcp advopt help'}) {
331 $dhcpsettings{'ADVOPT_NAME'} =~ s/[^ \w-]//g; # prevent execution of code by removing everything except letters/space
332 $dhcpsettings{'ADVOPT_DATA'} =~ s/`//g; # back tik ` ? not allowed !
333
334 if ($dhcpsettings{'ADVOPT_DATA'} eq '') {
335 $errormessage=$Lang::tr{'dhcp advopt blank value'};
336 }
66c36198 337
ac1cfefa
MT
338 # Test for a new option definition string (join field name & data)
339 if (ExistNewOptionDefinition ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
340 #only edit permitted if option definition exists
341 $errormessage = $Lang::tr{'dhcp advopt definition exists'} if ($dhcpsettings{'KEY1'} eq '');
342 $dhcpsettings{'ADVOPT_ENABLED'} = 'on'; # force active
343 map ($dhcpsettings{"ADVOPT_SCOPE_$_"} = 'off', @ITFs); # force global
344 } elsif (AddNewOptionDefinition ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
345 #was a new option definition
346 $dhcpsettings{'ADVOPT_ENABLED'} = 'on'; # force active
347 map ($dhcpsettings{"ADVOPT_SCOPE_$_"} = 'off', @ITFs); # force global
348 } elsif (ValidNewOption ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
349 #was a new option
2bbf1766 350 } elsif (! grep(/option $dhcpsettings{'ADVOPT_NAME'}/, @advoptions_list)) {
ac1cfefa
MT
351 $errormessage=$Lang::tr{'dhcp advopt unknown'}.': '.$dhcpsettings{'ADVOPT_NAME'};
352 }
353
354 unless ($errormessage) {
66c36198 355
ac1cfefa
MT
356 my $scope = '';
357 foreach my $itf (@ITFs) { # buils "RED,GREEN,ORANGE,... based on selection
358 $scope .= $dhcpsettings{"ADVOPT_SCOPE_${itf}"} eq 'on' ? "\t$itf" : "\toff" ;
359 }
360 if ($dhcpsettings{'KEY1'} eq '') { #add or edit ? TAB separator !
361 unshift (@current1, "$dhcpsettings{'ADVOPT_ENABLED'}\t$dhcpsettings{'ADVOPT_NAME'}\t$dhcpsettings{'ADVOPT_DATA'}$scope\n");
362 &General::log($Lang::tr{'dhcp advopt added'});
363 } else {
364 @current1[$dhcpsettings{'KEY1'}] = "$dhcpsettings{'ADVOPT_ENABLED'}\t$dhcpsettings{'ADVOPT_NAME'}\t$dhcpsettings{'ADVOPT_DATA'}$scope\n";
365 $dhcpsettings{'KEY1'} = ''; # End edit mode
366 &General::log($Lang::tr{'dhcp advopt modified'});
367 }
368
369 #Write changes to dhcpd.conf.
370 &sortcurrent1; # sort newly added/modified entry
371 &buildconf; # before calling buildconf which use fixed lease file !
372 }
373}
374
375if ($dhcpsettings{'ACTION'} eq $Lang::tr{'edit'}.'1') {
376 #move out new line
377 my $line = @current1[$dhcpsettings{'KEY1'}];
378 chomp($line);
379 my @temp = split(/\t/, $line);
380 $dhcpsettings{'ADVOPT_ENABLED'}=$temp[0];
381 $dhcpsettings{'ADVOPT_NAME'}=$temp[1];
382 $dhcpsettings{'ADVOPT_DATA'}=$temp[2];
383
384 # read next fields which are the name (color) of an interface if this interface is scoped
385 for (my $key=0; $key<@ITFs; $key++) {
386 my $itf = $temp[3+$key];
387 if ($itf ne 'off') # Only is an interface name is read
388 {
389 $dhcpsettings{"ADVOPT_SCOPE_${itf}"} = 'on';
66c36198 390 }
ac1cfefa
MT
391 }
392}
393
394if ($dhcpsettings{'ACTION'} eq $Lang::tr{'remove'}.'1') {
395 splice (@current1,$dhcpsettings{'KEY1'},1);
396 open(FILE, ">$filename1") or die 'Unable to open dhcp advanced options file.';
397 print FILE @current1;
398 close(FILE);
399 $dhcpsettings{'KEY1'} = ''; # End remove mode
400 &General::log($Lang::tr{'dhcp advopt removed'});
401 #Write changes to dhcpd.conf.
402 &buildconf;
403}
404#end KEY1
405
406
407# Toggle enable/disable field on specified lease.
408if ($dhcpsettings{'ACTION'} eq $Lang::tr{'toggle enable disable'}.'2') {
409 #move out new line
410 chomp(@current2[$dhcpsettings{'KEY2'}]);
411 my @temp = split(/\,/,@current2[$dhcpsettings{'KEY2'}]);
412 $temp[2] = $temp[2] eq 'on' ? '' : 'on'; # Toggle the field
413 @current2[$dhcpsettings{'KEY2'}] = join (',',@temp)."\n";
414 $dhcpsettings{'KEY2'} = ''; # End edit mode
415 &General::log($Lang::tr{'fixed ip lease modified'});
416 open(FILE, ">$filename2") or die 'Unable to open fixed leases file.';
417 print FILE @current2;
418 close(FILE);
66c36198 419
ac1cfefa
MT
420 #Write changes to dhcpd.conf.
421 &buildconf;
422}
423
424if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'2') {
425 $dhcpsettings{'FIX_MAC'} =~ tr/-/:/;
426 unless(&General::validip($dhcpsettings{'FIX_ADDR'})) { $errormessage = $Lang::tr{'invalid fixed ip address'}; }
427 unless(&General::validmac($dhcpsettings{'FIX_MAC'})) { $errormessage = $Lang::tr{'invalid fixed mac address'}; }
428 if ($dhcpsettings{'FIX_NEXTADDR'}) {
429 unless(&General::validip($dhcpsettings{'FIX_NEXTADDR'})) { $errormessage = $Lang::tr{'invalid fixed ip address'}; }
430 }
66c36198 431
ac1cfefa
MT
432 my $key = 0;
433 CHECK:foreach my $line (@current2) {
434 my @temp = split(/\,/,$line);
435 if($dhcpsettings{'KEY2'} ne $key) {
436 # same MAC is OK on different subnets. This test is not complete because
437 # if ip are not inside a known subnet, I don't warn.
438 # Also it may be needed to put duplicate fixed lease in their right subnet definition..
439 foreach my $itf (@ITFs) {
440 my $scoped = &General::IpInSubnet($dhcpsettings{'FIX_ADDR'},
66c36198 441 $netsettings{"${itf}_NETADDRESS"},
ac1cfefa
MT
442 $netsettings{"${itf}_NETMASK"}) &&
443 $dhcpsettings{"ENABLE_${itf}"} eq 'on';
444 if ( $scoped &&
445 (lc($dhcpsettings{'FIX_MAC'}) eq lc($temp[0])) &&
446 &General::IpInSubnet($temp[1],
66c36198 447 $netsettings{"${itf}_NETADDRESS"},
ac1cfefa
MT
448 $netsettings{"${itf}_NETMASK"})) {
449 $errormessage = "$Lang::tr{'mac address in use'} $dhcpsettings{'FIX_MAC'}";
450 last CHECK;
451 }
452 }
453 }
454 $key++;
455 }
456
457 unless ($errormessage) {
458 $dhcpsettings{'FIX_REMARK'} = &Header::cleanhtml($dhcpsettings{'FIX_REMARK'});
459 $dhcpsettings{'FIX_NEXTADDR'} = &Header::cleanhtml($dhcpsettings{'FIX_NEXTADDR'});
460 $dhcpsettings{'FIX_FILENAME'} = &Header::cleanhtml($dhcpsettings{'FIX_FILENAME'});
461 $dhcpsettings{'FIX_ROOTPATH'} = &Header::cleanhtml($dhcpsettings{'FIX_ROOTPATH'});
462 if ($dhcpsettings{'KEY2'} eq '') { #add or edit ?
463 unshift (@current2, "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n");
e4f9ea3c
BB
464 open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
465 print FILE @current2;
466 close(FILE);
ac1cfefa 467 &General::log($Lang::tr{'fixed ip lease added'});
91fc3030
MT
468
469 # Enter edit mode
31672dc8 470 $dhcpsettings{'KEY2'} = 0;
ac1cfefa
MT
471 } else {
472 @current2[$dhcpsettings{'KEY2'}] = "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n";
473 $dhcpsettings{'KEY2'} = ''; # End edit mode
474 &General::log($Lang::tr{'fixed ip lease modified'});
31672dc8
MT
475
476 # sort newly added/modified entry
477 &sortcurrent2;
ac1cfefa
MT
478 }
479
480 #Write changes to dhcpd.conf.
ac1cfefa
MT
481 &buildconf; # before calling buildconf which use fixed lease file !
482 }
483}
484
485if ($dhcpsettings{'ACTION_ALL'} eq '+') {
486 my $news = 0;
487 foreach (keys %dhcpsettings) {
488 if (/^(\d+\.\d+\.\d+\.\d+)-([0-9a-fA-F:]+)$/) { # checked names are index of the line
489 my $ip=$1;
490 my $mac=$2;
491 if (!grep (/$2/,@current2)) {
492 unshift (@current2, "$mac,$ip,on,,,,imported\n");
493 $news++;
494 }
495 }
496 }
497 if ($news) {
498 #Write changes to dhcpd.conf.
499 $warnNTPmessage = $Lang::tr{'fixed ip lease added'}."($news)";
500 &General::log($warnNTPmessage);
501 &sortcurrent2; # sort newly added/modified entry
502 &buildconf; # before calling buildconf which use fixed lease file !
503 }
504}
505
506if ($dhcpsettings{'ACTION'} eq $Lang::tr{'edit'}.'2') {
507 #move out new line
508 my $line = @current2[$dhcpsettings{'KEY2'}];
509 chomp($line);
510 my @temp = split(/\,/, $line);
511 $dhcpsettings{'FIX_MAC'}=$temp[0];
512 $dhcpsettings{'FIX_ADDR'}=$temp[1];
513 $dhcpsettings{'FIX_ENABLED'}=$temp[2];
514 $dhcpsettings{'FIX_NEXTADDR'}=$temp[3];
515 $dhcpsettings{'FIX_FILENAME'}=$temp[4];
516 $dhcpsettings{'FIX_ROOTPATH'}=$temp[5];
517 $dhcpsettings{'FIX_REMARK'}=$temp[6];
518}
519
520if ($dhcpsettings{'ACTION'} eq $Lang::tr{'remove'}.'2') {
521 splice (@current2,$dhcpsettings{'KEY2'},1);
522 open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
523 print FILE @current2;
524 close(FILE);
525 $dhcpsettings{'KEY2'} = ''; # End remove mode
526 &General::log($Lang::tr{'fixed ip lease removed'});
527 #Write changes to dhcpd.conf.
528 &buildconf;
529}
530#end KEY2 defined
531
532
533
534
535if ($dhcpsettings{'ACTION'} eq '' ) { # First launch from GUI
536
537 # Set default DHCP values only if blank and disabled
538 foreach my $itf (@ITFs) {
539 if ($dhcpsettings{"ENABLE_${itf}"} ne 'on' ) {
540 $dhcpsettings{"DNS1_${itf}"} = $netsettings{"${itf}_ADDRESS"};
541 $dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} = '60';
542 $dhcpsettings{"MAX_LEASE_TIME_${itf}"} = '120';
543 $dhcpsettings{"DOMAIN_NAME_${itf}"} = $mainsettings{'DOMAINNAME'};
544 }
545 }
546 $dhcpsettings{'FIX_ENABLED'} = 'on';
6fcd779c
AB
547 $dhcpsettings{'ADVOPT_ENABLED'} = 'on';
548 }
ac1cfefa 549
de4dea96
AB
550### START PAGE ###
551&Header::openpage($Lang::tr{'dhcp configuration'}, 1, $Header::extraHead);
ac1cfefa
MT
552&Header::openbigbox('100%', 'left', '', $errormessage);
553
554if ($errormessage) {
555 &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
556 print "<font class='base'>$errormessage&nbsp;</font>\n";
557 &Header::closebox();
558}
559if ($warnNTPmessage) {
560 $warnNTPmessage = "<font color=${Header::colourred}><b>$Lang::tr{'capswarning'}</b></font>: $warnNTPmessage";
561}
562
563&Header::openbox('100%', 'left', 'DHCP');
564print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>";
565
566foreach my $itf (@ITFs) {
567 my %checked=();
568 $checked{'ENABLE'}{'on'} = ( $dhcpsettings{"ENABLE_${itf}"} ne 'on') ? '' : "checked='checked'";
569 $checked{'ENABLEBOOTP'}{'on'} = ( $dhcpsettings{"ENABLEBOOTP_${itf}"} ne 'on') ? '' : "checked='checked'";
9dbf3c49 570 $checked{'DENY_KNOWN_CLIENTS'}{'on'} = ( $dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} ne 'on') ? '' : "checked='checked'";
ac1cfefa
MT
571
572 if ($netsettings{"${itf}_DEV"} ne '' ) { # Show only defined interface
573 my $lc_itf=lc($itf);
574print <<END
575<table width='100%'>
576<tr>
577 <td width='25%' class='boldbase'><b><font color='${lc_itf}'>$Lang::tr{"$lc_itf interface"}</font></b></td>
578 <td class='base'>$Lang::tr{'enabled'}
579 <input type='checkbox' name='ENABLE_${itf}' $checked{'ENABLE'}{'on'} /></td>
9c100957 580 <td width='25%' class='base'>$Lang::tr{'ip address'}<br />$Lang::tr{'netmask'}:</td><td><b>$netsettings{"${itf}_ADDRESS"}<br />$netsettings{"${itf}_NETMASK"}</b></td>
ac1cfefa 581</tr><tr>
e3edceeb 582 <td width='25%' class='base'>$Lang::tr{'start address'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 583 <td width='25%'><input type='text' name='START_ADDR_${itf}' value='$dhcpsettings{"START_ADDR_${itf}"}' /></td>
e3edceeb 584 <td width='25%' class='base'>$Lang::tr{'end address'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 585 <td width='25%'><input type='text' name='END_ADDR_${itf}' value='$dhcpsettings{"END_ADDR_${itf}"}' /></td>
9dbf3c49
AB
586</tr><tr>
587 <td class='base'>$Lang::tr{'dhcp deny known clients:'}</td>
588 <td><input type='checkbox' name='DENY_KNOWN_CLIENTS_${itf}' $checked{'DENY_KNOWN_CLIENTS'}{'on'} /></td>
ac1cfefa 589</tr><tr>
e3edceeb 590 <td class='base'>$Lang::tr{'default lease time'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 591 <td><input type='text' name='DEFAULT_LEASE_TIME_${itf}' value='$dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"}' /></td>
e3edceeb 592 <td class='base'>$Lang::tr{'max lease time'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa
MT
593 <td><input type='text' name='MAX_LEASE_TIME_${itf}' value='$dhcpsettings{"MAX_LEASE_TIME_${itf}"}' /></td>
594</tr><tr>
e3edceeb 595 <td class='base'>$Lang::tr{'domain name suffix'}</td>
ac1cfefa
MT
596 <td><input type='text' name='DOMAIN_NAME_${itf}' value='$dhcpsettings{"DOMAIN_NAME_${itf}"}' /></td>
597 <td>$Lang::tr{'dhcp allow bootp'}:</td>
598 <td><input type='checkbox' name='ENABLEBOOTP_${itf}' $checked{'ENABLEBOOTP'}{'on'} /></td>
599</tr><tr>
e3edceeb 600 <td class='base'>$Lang::tr{'primary dns'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 601 <td><input type='text' name='DNS1_${itf}' value='$dhcpsettings{"DNS1_${itf}"}' /></td>
e3edceeb 602 <td class='base'>$Lang::tr{'secondary dns'}</td>
ac1cfefa
MT
603 <td><input type='text' name='DNS2_${itf}' value='$dhcpsettings{"DNS2_${itf}"}' /></td>
604</tr><tr>
e3edceeb 605 <td class='base'>$Lang::tr{'primary ntp server'}:</td>
ac1cfefa 606 <td><input type='text' name='NTP1_${itf}' value='$dhcpsettings{"NTP1_${itf}"}' /></td>
e3edceeb 607 <td class='base'>$Lang::tr{'secondary ntp server'}:</td>
ac1cfefa
MT
608 <td><input type='text' name='NTP2_${itf}' value='$dhcpsettings{"NTP2_${itf}"}' /></td>
609</tr><tr>
e3edceeb 610 <td class='base'>$Lang::tr{'primary wins server address'}:</td>
ac1cfefa 611 <td><input type='text' name='WINS1_${itf}' value='$dhcpsettings{"WINS1_${itf}"}' /></td>
e3edceeb 612 <td class='base'>$Lang::tr{'secondary wins server address'}:</td>
ac1cfefa 613 <td><input type='text' name='WINS2_${itf}' value='$dhcpsettings{"WINS2_${itf}"}' /></td>
d1883e28 614</tr><tr>
e3edceeb 615 <td class='base'>next-server:</td>
d1883e28 616 <td><input type='text' name='NEXT_${itf}' value='$dhcpsettings{"NEXT_${itf}"}' /></td>
e3edceeb 617 <td class='base'>filename:</td>
d1883e28 618 <td><input type='text' name='FILE_${itf}' value='$dhcpsettings{"FILE_${itf}"}' /></td>
ac1cfefa
MT
619</tr>
620</table>
621<hr />
622END
623;
624 }# Show only defined interface
625}#foreach itf
626print <<END
627<table width='100%'>
628<tr>
e3edceeb 629 <td class='base' width='25%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'required field'}</td>
ac1cfefa 630 <td class='base' width='30%'>$warnNTPmessage</td>
e084eea0 631 <td width='40%' align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
ac1cfefa
MT
632</tr>
633</table>
b510e12a
SS
634END
635;
636&Header::closebox();
637
638# DHCP DNS update support (RFC2136)
639&Header::openbox('100%', 'left', $Lang::tr{'dhcp dns update'});
640
641my %checked = ();
642$checked{'DNS_UPDATE_ENABLED'}{'on'} = ( $dhcpsettings{'DNS_UPDATE_ENABLED'} ne 'on') ? '' : "checked='checked'";
643
644print <<END
645<table width='100%'>
646 <tr>
2dfbb338 647 <td width='30%' class='boldbase'>$Lang::tr{'dhcp dns enable update'}</td>
b510e12a
SS
648 <td class='base'><input type='checkbox' name='DNS_UPDATE_ENABLED' $checked{'DNS_UPDATE_ENABLED'}{'on'}>
649 </td>
650 <tr>
651</table>
652
653<table width='100%'>
654END
655;
656 my @domains = ();
657
658 # Print options for each interface.
659 foreach my $itf (@ITFs) {
660 # Check if DHCP for this interface is enabled.
661 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on') {
662 # Check for same domain name.
663 next if ($dhcpsettings{"DOMAIN_NAME_${itf}"} ~~ @domains);
664 my $lc_itf = lc($itf);
665
666 # Select previously configured update algorithm.
667 my %selected = ();
668 $selected{'DNS_UPDATE_ALGO_${inf}'}{$dhcpsettings{'DNS_UPDATE_ALGO_${inf}'}} = 'selected';
669
670print <<END
671 <tr>
672 <td colspan='6'>&nbsp;</td>
673 </tr>
674 <tr>
675 <td colspan='6' class='boldbase'><b>$dhcpsettings{"DOMAIN_NAME_${itf}"}</b></td>
676 </tr>
677 <tr>
678 <td width='10%' class='boldbase'>$Lang::tr{'dhcp dns key name'}:</td>
679 <td width='20%'><input type='text' name='DNS_UPDATE_KEY_NAME_${itf}' value='$dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"}'></td>
680 <td width='10%' class='boldbase' align='right'>$Lang::tr{'dhcp dns update secret'}:&nbsp;&nbsp;</td>
28fee676 681 <td width='20%'><input type='password' name='DNS_UPDATE_KEY_SECRET_${itf}' value='$dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"}'></td>
b510e12a
SS
682 <td width='10%' class='boldbase' align='right'>$Lang::tr{'dhcp dns update algo'}:&nbsp;&nbsp;</td>
683 <td width='20%'>
28fee676 684 <select name='DNS_UPDATE_KEY_ALGO_${itf}'>
a057a976 685 <!-- <option value='hmac-sha1' $selected{'DNS_UPDATE_KEY_ALGO_${itf}'}{'hmac-sha1'}>HMAC-SHA1</option> -->
28fee676 686 <option value='hmac-md5' $selected{'DNS_UPDATE_KEY_ALGO_${itf}'}{'hmac-md5'}>HMAC-MD5</option>
b510e12a
SS
687 </select>
688 </td>
689 </tr>
690END
691;
692 }
693
694 # Store configured domain based on the interface
695 # in the temporary variable.
696 push(@domains, $dhcpsettings{"DOMAIN_NAME_${itf}"});
697}
698print <<END
699</table>
700<hr>
701<table width='100%'>
702 <tr>
703 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
704 </tr>
705</table>
ac1cfefa
MT
706</form>
707END
708;
709
710&Header::closebox();
711
712&Header::openbox('100%', 'left', $Lang::tr{'dhcp advopt list'});
713# DHCP Advanced options settings
714my %checked=();
715$checked{'ADVOPT_ENABLED'}{'on'} = ($dhcpsettings{'ADVOPT_ENABLED'} ne 'on') ? '' : "checked='checked'";
716
717print "<form method='post' action='$ENV{'SCRIPT_NAME'}'><table width='100%'>";
718my $buttontext = $Lang::tr{'add'};
719if ($dhcpsettings{'KEY1'} ne '') {
720 $buttontext = $Lang::tr{'update'};
721 print "<tr><td class='boldbase'><b>$Lang::tr{'dhcp advopt edit'}</b></td></tr>";
722} else {
723 print "<tr><td class='boldbase'><b>$Lang::tr{'dhcp advopt add'}</b></td></tr>"
724}
725
726#search if the 'option' is in the list and print the syntax model
5410fcbc 727my $opt;
2bbf1766 728
5410fcbc
SS
729# Check if a advanced option name is set.
730if ($dhcpsettings{'ADVOPT_NAME'}) {
731 # Check if the name is part of the list and grab syntax.
732 my @opt = grep(/option $dhcpsettings{'ADVOPT_NAME'}/, @advoptions_list);
733
734 # Assign array element to variable.
735 $opt = @opt[0];
736
737 # Remove newlines.
738 chomp($opt);
739}
2bbf1766 740
ac1cfefa
MT
741if ($opt ne '') {
742 $opt =~ s/option $dhcpsettings{'ADVOPT_NAME'}/Syntax:/; # "option xyz abc" => "syntax: abc"
743 $opt =~ s/;//;
744 $opt = "<tr><td></td><td></td><td colspan='2'>$opt</td></tr>";
745}
746print <<END
747<tr>
e3edceeb 748 <td class='base'>$Lang::tr{'dhcp advopt name'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 749 <td><input type='text' name='ADVOPT_NAME' value='$dhcpsettings{'ADVOPT_NAME'}' size='18' /></td>
e3edceeb 750 <td class='base'>$Lang::tr{'dhcp advopt value'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa
MT
751 <td><input type='text' name='ADVOPT_DATA' value='$dhcpsettings{'ADVOPT_DATA'}' size='40' /></td>
752</tr>$opt<tr>
753 <td class='base'>$Lang::tr{'enabled'}</td><td><input type='checkbox' name='ADVOPT_ENABLED' $checked{'ADVOPT_ENABLED'}{'on'} /></td>
e3edceeb 754 <td class='base'>$Lang::tr{'dhcp advopt scope'}:</td>
ac1cfefa
MT
755 <td>
756END
757;
758
66c36198 759# Put a checkbox for each interface. Checkbox visible disabled if interface is disabled
ac1cfefa
MT
760foreach my $itf (@ITFs) {
761 my $lc_itf=lc($itf);
66c36198 762 $checked{'ADVOPT_SCOPE_${itf}'}{'on'} = $dhcpsettings{"ADVOPT_SCOPE_${itf}"} ne 'on' ? '' : "checked='checked'";
ac1cfefa
MT
763 print "$Lang::tr{\"${lc_itf}\"} <input type='checkbox' name='ADVOPT_SCOPE_${itf}' $checked{'ADVOPT_SCOPE_${itf}'}{'on'} ";
764 print $dhcpsettings{"ENABLE_${itf}"} eq 'on' ? "/>" : "disabled='disabled' />";
765 print "&nbsp; &nbsp;";
766}
767
768print <<END
769 </td>
770</tr>
771</table>
772<hr />
773<table width='100%'>
774<tr>
e3edceeb 775 <td class='base' width='50%'>$Lang::tr{'dhcp advopt scope help'}</td>
e084eea0 776 <td width='50%' align='right'>
ac1cfefa
MT
777 <input type='hidden' name='ACTION' value='$Lang::tr{'add'}1' />
778 <input type='submit' name='SUBMIT' value='$buttontext' />
779 <input type='submit' name='SUBMIT' value='$Lang::tr{'dhcp advopt help'}' />
780 <input type='hidden' name='KEY1' value='$dhcpsettings{'KEY1'}' />
781 </td>
782</tr>
783</table>
784</form>
785END
786;
787#Edited line number (KEY1) passed until cleared by 'save' or 'remove' or 'new sort order'
788
789# print help taken from the file describing options
790if ($dhcpsettings{'SUBMIT'} eq $Lang::tr{'dhcp advopt help'}) {
791 print "<hr />";
792 print "<table width='100%'>";
793 print "<tr><td width='30%'><b>$Lang::tr{'dhcp advopt name'}</b></td><td width='70%'><b>$Lang::tr{'dhcp advopt value'}</b></td>";
794 open(FILE, "$filename3");
795 my @current3 = <FILE>;
796 close(FILE);
797 foreach my $line (@current3) {
798 $line =~ /option ([a-z0-9-]+) (.*);/;
799 print "<tr><td>$1</td><td>$2</td></tr>\n";
800 }
801 print "<tr><td colspan='2'><hr /></td></tr>\n";
802 print '<tr><td>string type</td><td>"quoted string" or 00:01:FF...</td></tr>';
803 print '<tr><td>ip-address type </td><td>10.0.0.1 | www.dot.com</td></tr>';
31016a38 804 print '<tr><td>domain-list type </td><td>"example.com", "eng.example.com", "sales.example.com"</td></tr>';
ac1cfefa
MT
805 print '<tr><td>int,uint types</td><td>numbers</td></tr>';
806 print '<tr><td>flag type</td><td>on | off</td></tr>';
807 print '</table>';
808 print "<hr />";
809 print "<table width='100%'>";
810 print "<tr><td width='30%'><b>$Lang::tr{'dhcp advopt custom definition'}</b></td><td width='70%'><b>$Lang::tr{'dhcp advopt value'}</b></td>";
811 print "<tr><td>any-name </td><td> code NNN=$OptionTypes</td></tr>";
812 print '<tr><td>a-string</td><td>code 100=string</td></tr>';
813 print '<tr><td>a-number</td><td>code 101=signed integer 8</td></tr>';
814 print '<tr><td>wpad</td><td>code 252=text</td></tr>';
815 print '<tr><td>wpad</td><td>"http://www.server.fr/path-to/proxy.pac"</td></tr>';
816 print '</table>';
66c36198 817
ac1cfefa
MT
818}
819
820print <<END
821<hr />
822<table width='100%'>
823<tr>
824 <td width='30%' class='boldbase' align='center'><b>$Lang::tr{'dhcp advopt name'}</b></td>
825 <td width='50%' class='boldbase' align='center'><b>$Lang::tr{'dhcp advopt value'}</b></td>
826 <td width='20%' class='boldbase' align='center'><b>$Lang::tr{'dhcp advopt scope'}</b></td>
827 <td colspan='3' class='boldbase' align='center'><b>$Lang::tr{'action'}</b></td>
828</tr>
829END
830;
831my $key = 0;
832foreach my $line (@current1) {
833 my $gif = '';
834 my $gdesc = '';
835 chomp($line); # remove newline
836 my @temp = split(/\t/,$line);
837
838 if ($temp[0] eq "on") {
839 $gif = 'on.gif';
840 $gdesc = $Lang::tr{'click to disable'};
841 } else {
842 $gif = 'off.gif';
66c36198 843 $gdesc = $Lang::tr{'click to enable'};
ac1cfefa
MT
844 }
845
846 if ($dhcpsettings{'KEY1'} eq $key) {
d3aec718 847 print "<tr class='colouryellow'>";
ac1cfefa 848 } elsif ($key % 2) {
d3aec718 849 print "<tr class='color22'>";
ac1cfefa 850 } else {
d3aec718 851 print "<tr class='color20'>";
ac1cfefa
MT
852 }
853
854 print <<END
855<td align='center'>$temp[1]</td>
856<td align='center'>$temp[2]</td>
857<td align='center'>
858END
859;
860 # Prepare a global flag to make easy reading
861 my $global = '';
862 my $disabledTogle = '';
863 my $disabledEditRemove = '';
864 if ( ExistNewOptionDefinition ($temp[1] . ' ' . $temp[2]) ) {
865 $global = $Lang::tr{'dhcp advopt definition'};
866 $disabledTogle = "disabled='disabled'";
867 # Search if it is a used NewOptionDefinition to also disable edit & delete
868 $disabledEditRemove = "disabled='disabled'" if (IsUsedNewOptionDefinition ($temp[1], $temp[2]));
869 } else {
870 $global = $Lang::tr{'dhcp advopt scope global'};
871 }
66c36198
PM
872
873
ac1cfefa
MT
874 # Print each checked interface
875 for (my $key=0; $key<@ITFs; $key++) {
876 my $itf = $temp[3+$key];
877 if ($itf ne 'off') { # Only if an interface name is read
878 print "$itf";
879 $global=''; # fall to local scope !
880 }
881 }
882 print <<END
883$global</td>
884<td align='center'>
885<form method='post' action='$ENV{'SCRIPT_NAME'}'>
886<input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}1' />
887<input $disabledTogle type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
888<input type='hidden' name='KEY1' value='$key' />
889</form>
890</td>
891
892<td align='center'>
893<form method='post' action='$ENV{'SCRIPT_NAME'}'>
894<input type='hidden' name='ACTION' value='$Lang::tr{'edit'}1' />
895<input $disabledEditRemove type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
896<input type='hidden' name='KEY1' value='$key' />
897</form>
898</td>
899
900<td align='center'>
901<form method='post' action='$ENV{'SCRIPT_NAME'}'>
902<input type='hidden' name='ACTION' value='$Lang::tr{'remove'}1' />
903<input $disabledEditRemove type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
904<input type='hidden' name='KEY1' value='$key' />
905</form>
906</td>
907</tr>
908END
909;
910 $key++;
911}
912
913print "</table>";
914
915# If there are dhcp options, print Key to action icons
916if ($key) {
917print <<END
918<table>
919<tr>
920 <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
921 <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
922 <td class='base'>$Lang::tr{'click to disable'}</td>
923 <td>&nbsp;&nbsp;</td>
924 <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
925 <td class='base'>$Lang::tr{'click to enable'}</td>
926 <td>&nbsp;&nbsp;</td>
927 <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
928 <td class='base'>$Lang::tr{'edit'}</td>
929 <td>&nbsp;&nbsp;</td>
930 <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
931 <td class='base'>$Lang::tr{'remove'}</td>
932</tr>
933</table>
934END
935;
936}
937&Header::closebox();
938
939&Header::openbox('100%', 'left', $Lang::tr{'current fixed leases'});
940# Fixed leases screens
941$checked{'FIX_ENABLED'}{'on'} = ($dhcpsettings{'FIX_ENABLED'} ne 'on') ? '' : "checked='checked'";
942
943$buttontext = $Lang::tr{'add'};
944print "<form method='post' action='$ENV{'SCRIPT_NAME'}'><table width='100%'>";
945
946if ($dhcpsettings{'KEY2'} ne '') {
947 $buttontext = $Lang::tr{'update'};
948 print "<tr><td class='boldbase' colspan='3'><b>$Lang::tr{'edit an existing lease'}</b></td></tr>";
949} else {
950 print "<tr><td class='boldbase' colspan='3'><b>$Lang::tr{'add new lease'}</b></td></tr>"
951}
952print <<END
953<tr>
e3edceeb 954 <td class='base'>$Lang::tr{'mac address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 955 <td><input type='text' name='FIX_MAC' value='$dhcpsettings{'FIX_MAC'}' size='18' /></td>
e3edceeb 956 <td class='base'>$Lang::tr{'ip address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 957 <td><input type='text' name='FIX_ADDR' value='$dhcpsettings{'FIX_ADDR'}' size='18' /></td>
e3edceeb 958 <td class='base'>$Lang::tr{'remark'}:</td>
ac1cfefa
MT
959 <td><input type='text' name='FIX_REMARK' value='$dhcpsettings{'FIX_REMARK'}' size='18' /></td>
960</tr><tr>
961 <td class='base'>$Lang::tr{'enabled'}</td><td><input type='checkbox' name='FIX_ENABLED' $checked{'FIX_ENABLED'}{'on'} /></td>
962</tr><tr>
963 <td colspan = '3'><b>$Lang::tr{'dhcp bootp pxe data'}</b></td>
964</tr><tr>
e3edceeb 965 <td class='base'>next-server:</td>
ac1cfefa 966 <td><input type='text' name='FIX_NEXTADDR' value='$dhcpsettings{'FIX_NEXTADDR'}' size='18' /></td>
e3edceeb 967 <td class='base'>filename:</td>
ac1cfefa 968 <td><input type='text' name='FIX_FILENAME' value='$dhcpsettings{'FIX_FILENAME'}' size='18' /></td>
e3edceeb 969 <td class='base'>root path:</td>
ac1cfefa
MT
970 <td><input type='text' name='FIX_ROOTPATH' value='$dhcpsettings{'FIX_ROOTPATH'}' size='18' /></td>
971</tr>
972</table>
973<hr />
974<table width='100%'>
975<tr>
e3edceeb 976 <td class='base' width='50%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'required field'}</td>
e084eea0 977 <td width='50%' align='right'>
ac1cfefa
MT
978 <input type='hidden' name='ACTION' value='$Lang::tr{'add'}2' />
979 <input type='submit' name='SUBMIT' value='$buttontext' />
980 <input type='hidden' name='KEY2' value='$dhcpsettings{'KEY2'}' /></td>
981</tr>
982</table>
983</form>
984END
985;
986#Edited line number (KEY2) passed until cleared by 'save' or 'remove' or 'new sort order'
987
1554e8a3
MT
988# Search for static leases
989my $search_query = $dhcpsettings{'q'};
990
991if (scalar @current2 >= 10) {
992 print <<END;
993 <form method="POST" action="#search">
994 <a name="search"></a>
995 <table width='100%'>
996 <tr>
997 <td>
998 <input type="text" name="q" value="$search_query">
999 <input type="submit" value="$Lang::tr{'search'}">
1000 </td>
1001 </tr>
1002 </table>
1003 </form>
1004END
1005}
1006
ac1cfefa 1007print <<END
52ca3c80 1008<table width='100%' class='tbl'>
ac1cfefa 1009<tr>
70d8e3be
PM
1010 <th width='20%' align='center'><a href='$ENV{'SCRIPT_NAME'}?FETHER'><b>$Lang::tr{'mac address'}</b></a></th>
1011 <th width='20%' align='center'><a href='$ENV{'SCRIPT_NAME'}?FIPADDR'><b>$Lang::tr{'ip address'}</b></a></th>
52ca3c80
AM
1012 <th width='15%' align='center'><b>$Lang::tr{'remark'}</b></th>
1013 <th width='15%' class='boldbase' align='center'><b>next-server</b></th>
1014 <th width='15%' class='boldbase' align='center'><b>filename</b></th>
1015 <th width='15%' class='boldbase' align='center'><b>root path</b></th>
1016 <th colspan='3' class='boldbase' align='center'><b>$Lang::tr{'action'}</b></th>
ac1cfefa
MT
1017</tr>
1018END
1019;
1020my $ipdup = 0;
1021my %ipinuse = ();
1022my %macdupl = (); # Duplicate MACs have to be on different subnets
1023my %ipoutside = ();
b52a84dd 1024my %ipinrange = ();
ac1cfefa 1025
b52a84dd 1026# mark duplicate IP, duplicate MAC or IP in dynamic range
ac1cfefa
MT
1027foreach my $line (@current2) {
1028 my @temp = split(/\,/,$line);
1029 $macdupl{$temp[0]} += 1;
66c36198 1030 if ($macdupl{$temp[0]} > 1) {
ac1cfefa
MT
1031 $ipdup = 1; # Flag up duplicates for use later
1032 }
1033 $ipinuse{$temp[1]} += 1;
66c36198 1034 if ($ipinuse{$temp[1]} > 1) {
ac1cfefa
MT
1035 $ipdup = 1; # Flag up duplicates for use later
1036 }
ac1cfefa 1037 $ipoutside{$temp[1]} = 1;
b52a84dd 1038 $ipinrange{$temp[1]} = 0;
ac1cfefa 1039 foreach my $itf (@ITFs) {
b52a84dd
AB
1040 # Mark IP addresses outwith known subnets
1041 if ( &General::IpInSubnet($temp[1],
1042 $netsettings{"${itf}_NETADDRESS"},
1043 $netsettings{"${itf}_NETMASK"})) {
1044 $ipoutside{$temp[1]} = 0;
1045 }
1046 # Mark IP addresses that overlap with dynamic range
1047 if (&Network::ip_address_in_range($temp[1],
1048 $dhcpsettings{"START_ADDR_${itf}"},
1049 $dhcpsettings{"END_ADDR_${itf}"})) {
1050 $ipinrange{$temp[1]} = 1;
1051 }
ac1cfefa
MT
1052 }
1053}
1054
1055$key = 0;
52ca3c80 1056my $col="";
ac1cfefa
MT
1057foreach my $line (@current2) {
1058 my $gif = '';
1059 my $gdesc = '';
1060 chomp($line); # remove newline
1061 my @temp = split(/\,/,$line);
1062
1063 if ($temp[2] eq "on") {
1064 $gif = 'on.gif';
1065 $gdesc = $Lang::tr{'click to disable'};
1066 } else {
1067 $gif = 'off.gif';
66c36198 1068 $gdesc = $Lang::tr{'click to enable'};
ac1cfefa
MT
1069 }
1070
1554e8a3
MT
1071 # Skip all entries that do not match the search query
1072 if ($search_query ne "") {
e353470a
MT
1073 if (!grep(/$search_query/, @temp)) {
1074 $key++;
1075 next;
1076 }
1554e8a3
MT
1077 }
1078
ac1cfefa 1079 if ($dhcpsettings{'KEY2'} eq $key) {
52ca3c80 1080 print "<tr>";
d3aec718 1081 $col="class='colouryellow'";
ac1cfefa 1082 } elsif ($key % 2) {
52ca3c80 1083 print "<tr>";
d3aec718 1084 $col="class='color20'";
ac1cfefa 1085 } else {
52ca3c80 1086 print "<tr>";
d3aec718 1087 $col="class='color22'";
ac1cfefa
MT
1088 }
1089 my $TAG0 = '';
1090 my $TAG1 = '';
1091 my $TAG2 = '';
1092 my $TAG3 = '';
1093 my $TAG4 = '';
66c36198 1094 if ($ipinuse{$temp[1]} > 1) {
ac1cfefa
MT
1095 $TAG0 = '<b>';
1096 $TAG1 = '</b>';
1097 }
66c36198 1098 if ($macdupl{$temp[0]} > 1) {
ac1cfefa
MT
1099 $TAG2 = '<b>';
1100 $TAG3 = '</b>';
1101 }
66c36198 1102 if ($ipoutside{$temp[1]} > 0) {
d3aec718 1103 $TAG4 = "class='orange'" if ($dhcpsettings{'KEY2'} ne $key);
ac1cfefa 1104 }
b52a84dd 1105 if ($ipinrange{$temp[1]} > 0) {
d3aec718 1106 $TAG4 = "class='red'" if ($dhcpsettings{'KEY2'} ne $key);
b52a84dd 1107 }
ac1cfefa
MT
1108
1109 print <<END
52ca3c80 1110<td align='center' $col>$TAG2$temp[0]$TAG3</td>
de4dea96 1111<td align='center' $TAG4 $col>$TAG0$temp[1]$TAG1</td>
52ca3c80
AM
1112<td align='center' $col>$temp[6]&nbsp;</td>
1113<td align='center' $col>$temp[3]&nbsp;</td>
1114<td align='center' $col>$temp[4]&nbsp;</td>
1115<td align='center' $col>$temp[5]&nbsp;</td>
1116
1117<td align='center' $col>
ac1cfefa
MT
1118<form method='post' action='$ENV{'SCRIPT_NAME'}'>
1119<input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}2' />
1120<input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
1121<input type='hidden' name='KEY2' value='$key' />
1122</form>
1123</td>
1124
52ca3c80 1125<td align='center' $col>
ac1cfefa
MT
1126<form method='post' action='$ENV{'SCRIPT_NAME'}'>
1127<input type='hidden' name='ACTION' value='$Lang::tr{'edit'}2' />
1128<input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
1129<input type='hidden' name='KEY2' value='$key' />
1130</form>
1131</td>
1132
52ca3c80 1133<td align='center' $col>
ac1cfefa
MT
1134<form method='post' action='$ENV{'SCRIPT_NAME'}'>
1135<input type='hidden' name='ACTION' value='$Lang::tr{'remove'}2' />
1136<input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
1137<input type='hidden' name='KEY2' value='$key' />
1138</form>
1139</td>
1140</tr>
1141END
1142;
1143 $key++;
1144}
1145print "</table>";
1146
1147# If the fixed lease file contains entries, print Key to action icons
1148if ($key) {
1149my $dup = $ipdup ? "<td class='base'>$Lang::tr{'duplicate ip bold'}</td>" :'';
1150print <<END
1151<table>
1152<tr>
1153 <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
1154 <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
1155 <td class='base'>$Lang::tr{'click to disable'}</td>
ac1cfefa
MT
1156 <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
1157 <td class='base'>$Lang::tr{'click to enable'}</td>
1158 <td>&nbsp;&nbsp;</td>
1159 <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
1160 <td class='base'>$Lang::tr{'edit'}</td>
1161 <td>&nbsp;&nbsp;</td>
1162 <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
1163 <td class='base'>$Lang::tr{'remove'}</td>
1164</tr>
1165<tr>
1166 <td>&nbsp;</td>
f16eeae0
AB
1167 <td class='base orange'>&nbsp;</td>
1168 <td class='base'>&nbsp;$Lang::tr{'ip address outside subnets'}&emsp;</td>
1169 <td class='base red'>&nbsp;</td>
1170 <td class='base'>&nbsp;$Lang::tr{'dhcp fixed ip address in dynamic range'}</td>
ac1cfefa
MT
1171 <td>&nbsp;</td>
1172 <td>&nbsp;</td>
1173 $dup
1174</tr>
1175</table>
1176END
1177;
1178}
1179
1180&Header::closebox();
1181
ac1cfefa
MT
1182foreach my $itf (@ITFs) {
1183 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on') {
1184 # display leases with a list of actions to do with the global select checkbox.
1185 &Header::PrintActualLeases("+"); # "+" => create fixed leases from nodeaddress
1186 last; #Print one time only for all interfaces
1187 };
1188}
1189
1190&Header::closebigbox();
1191&Header::closepage();
1192
1193## Ouf it's the end !
1194
1195sub sortcurrent1 # by now, do not sort, just write
1196{
1197 open(FILE, ">$filename1") or die 'Unable to open dhcp advanced options file.';
1198 print FILE @current1;
1199 close(FILE);
1200}
1201
1202
1203# Sort the "current2" array according to choices
1204sub sortcurrent2
1205{
1206 our %entries = ();
1207
1208 sub fixedleasesort {
1209 my $qs='';
1210 if (rindex ($dhcpsettings{'SORT_FLEASELIST'},'Rev') != -1) {
1211 $qs=substr ($dhcpsettings{'SORT_FLEASELIST'},0,length($dhcpsettings{'SORT_FLEASELIST'})-3);
1212 if ($qs eq 'FIPADDR') {
1213 my @a = split(/\./,$entries{$a}->{$qs});
1214 my @b = split(/\./,$entries{$b}->{$qs});
1215 ($b[0]<=>$a[0]) ||
1216 ($b[1]<=>$a[1]) ||
1217 ($b[2]<=>$a[2]) ||
1218 ($b[3]<=>$a[3]);
1219 } else {
1220 $entries{$b}->{$qs} cmp $entries{$a}->{$qs};
1221 }
1222 } else { #not reverse
1223 $qs=$dhcpsettings{'SORT_FLEASELIST'};
1224 if ($qs eq 'FIPADDR') {
1225 my @a = split(/\./,$entries{$a}->{$qs});
1226 my @b = split(/\./,$entries{$b}->{$qs});
1227 ($a[0]<=>$b[0]) ||
1228 ($a[1]<=>$b[1]) ||
1229 ($a[2]<=>$b[2]) ||
1230 ($a[3]<=>$b[3]);
1231 } else {
1232 $entries{$a}->{$qs} cmp $entries{$b}->{$qs};
1233 }
1234 }
1235 }
1236
1237 #Use an associative array (%entries)
1238 foreach my $line (@current2) {
1239 chomp( $line); #remove newline because can be on field 5 or 6 (addition of REMARK)
1240 my @temp = split (',',$line);
1241 my @record = ('FETHER',$temp[0],'FIPADDR',$temp[1],'DATA',join(',',@temp[2..6]));
1242 my $record = {}; # create a reference to empty hash
1243 %{$record} = @record; # populate that hash with @record
1244 # use combination of ether & IP as key to allow duplicates in either but not both
1245 $entries{$record->{FETHER} . $record->{FIPADDR}} = $record; # add this to a hash of hashes
1246 }
66c36198 1247
ac1cfefa
MT
1248 open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
1249 foreach my $entry ( sort fixedleasesort keys %entries) {
1250 print FILE "$entries{$entry}->{FETHER},$entries{$entry}->{FIPADDR},$entries{$entry}->{DATA}\n";
1251 }
1252 close(FILE);
1253
1254 # Reload sorted @current2
1255 open (FILE, "$filename2");
1256 @current2 = <FILE>;
1257 close (FILE);
1258 undef (%entries); #This array is reused latter. Clear it.
1259}
66c36198 1260
ac1cfefa
MT
1261# Build the configuration file mixing settings, fixed leases and advanced options
1262sub buildconf {
1263 open(FILE, ">/${General::swroot}/dhcp/dhcpd.conf") or die "Unable to write dhcpd.conf file";
1264 flock(FILE, 2);
1265
1266 # Global settings
ac1cfefa
MT
1267 print FILE "deny bootp; #default\n";
1268 print FILE "authoritative;\n";
f5fb9a04
MT
1269
1270 # DNS Update settings
1271 if ($dhcpsettings{'DNS_UPDATE_ENABLED'} eq 'on') {
1272 print FILE "ddns-updates on;\n";
1273 print FILE "ddns-update-style interim;\n";
5fd7e84c 1274 print FILE "ddns-ttl 60; # 1 min\n";
f5fb9a04
MT
1275 print FILE "ignore client-updates;\n";
1276 print FILE "update-static-leases on;\n";
1277 } else {
1278 print FILE "ddns-update-style none;\n";
1279 }
66c36198 1280
ac1cfefa
MT
1281 # Write first new option definition
1282 foreach my $line (@current1) {
1283 chomp($line); # remove newline
1284 my @temp = split(/\t/,$line);
1285 if (ExistNewOptionDefinition ($temp[1] . ' ' . $temp[2])) {
1286 print FILE "option $temp[1] $temp[2];\n";
1287 }
1288 }
1289 # Write other global options
1290 foreach my $line (@current1) {
1291 chomp($line); # remove newline
1292 my @temp = split(/\t/,$line);
66c36198 1293
ac1cfefa
MT
1294 if ($temp[0] eq 'on' && !ExistNewOptionDefinition ($temp[1] . ' ' . $temp[2])){ # active & !definition
1295 my $global=1;
1296 for (my $key=0; $key<@ITFs; $key++) {
1297 my $itf = $temp[3+$key];
1298 if ($itf ne 'off') # Only if an interface name is read
1299 {
1300 $global=0;
1301 }
1302 }
1303 if ($global) {
1304 print FILE "option $temp[1] $temp[2];\n";
1305 }
66c36198 1306 }# on
ac1cfefa 1307 }# foreach line
28fee676 1308 print FILE "\n";
ac1cfefa
MT
1309
1310 #Subnet range definition
1311 foreach my $itf (@ITFs) {
1312 my $lc_itf=lc($itf);
1313 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on' ){
28fee676 1314 print FILE "subnet " . $netsettings{"${itf}_NETADDRESS"} . " netmask ". $netsettings{"${itf}_NETMASK"} . " #$itf\n";
ac1cfefa 1315 print FILE "{\n";
9dbf3c49
AB
1316 if ($dhcpsettings{"START_ADDR_${itf}"}) {
1317 print FILE "pool {\n";
1318 print FILE "\trange " . $dhcpsettings{"START_ADDR_${itf}"} . ' ' . $dhcpsettings{"END_ADDR_${itf}"}.";\n";
1319 print FILE "\tdeny known-clients;\n" if ($dhcpsettings{"DENY_KNOWN_CLIENTS_${itf}"} eq 'on');
1320 print FILE " }\n"; # pool
1321 }
ac1cfefa
MT
1322 print FILE "\toption subnet-mask " . $netsettings{"${itf}_NETMASK"} . ";\n";
1323 print FILE "\toption domain-name \"" . $dhcpsettings{"DOMAIN_NAME_${itf}"} . "\";\n";
1324 print FILE "\toption routers " . $netsettings{"${itf}_ADDRESS"} . ";\n";
1325 print FILE "\toption domain-name-servers " . $dhcpsettings{"DNS1_${itf}"} if ($dhcpsettings{"DNS1_${itf}"});
1326 print FILE ", " . $dhcpsettings{"DNS2_${itf}"} if ($dhcpsettings{"DNS2_${itf}"});
1327 print FILE ";\n" if ($dhcpsettings{"DNS1_${itf}"});
1328 print FILE "\toption ntp-servers " . $dhcpsettings{"NTP1_${itf}"} if ($dhcpsettings{"NTP1_${itf}"});
1329 print FILE ", " . $dhcpsettings{"NTP2_${itf}"} if ($dhcpsettings{"NTP2_${itf}"});
1330 print FILE ";\n" if ($dhcpsettings{"NTP1_${itf}"});
1331 print FILE "\toption netbios-name-servers " . $dhcpsettings{"WINS1_${itf}"} if ($dhcpsettings{"WINS1_${itf}"});
1332 print FILE ", " . $dhcpsettings{"WINS2_${itf}"} if ($dhcpsettings{"WINS2_${itf}"});
1333 print FILE ";\n" if ($dhcpsettings{"WINS1_${itf}"});
d1883e28 1334 print FILE "\tnext-server " . $dhcpsettings{"NEXT_${itf}"} . ";\n" if ($dhcpsettings{"NEXT_${itf}"});
820ab96c 1335 print FILE "\tfilename \"" . &EscapeFilename($dhcpsettings{"FILE_${itf}"}) . "\";\n" if ($dhcpsettings{"FILE_${itf}"});
ac1cfefa
MT
1336 print FILE "\tdefault-lease-time " . ($dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} * 60). ";\n";
1337 print FILE "\tmax-lease-time " . ($dhcpsettings{"MAX_LEASE_TIME_${itf}"} * 60) . ";\n";
1338 print FILE "\tallow bootp;\n" if ($dhcpsettings{"ENABLEBOOTP_${itf}"} eq 'on');
1339
1340
1341
1342 # Write scoped options
1343 foreach my $line (@current1) {
1344 chomp($line); # remove newline
1345 my @temp = split(/\t/,$line); # Use TAB separator !
66c36198 1346
ac1cfefa
MT
1347 if ($temp[0] eq 'on'){
1348 for (my $key=0; $key<@ITFs; $key++) {
1349 if ($itf eq $temp[3+$key]) # Only is an interface name is read
1350 {
1351 print FILE "\toption $temp[1] $temp[2];\n";
1352 }
1353 }
66c36198 1354 }# on
ac1cfefa 1355 }# foreach line
28fee676 1356 print FILE "} #$itf\n\n";
ac1cfefa 1357
f5fb9a04 1358 if (($dhcpsettings{"DNS_UPDATE_ENABLED"} eq "on") && ($dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} ne "")) {
28fee676 1359 print FILE "key " . $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} . " {\n";
f5fb9a04
MT
1360 print FILE "\talgorithm " . $dhcpsettings{"DNS_UPDATE_KEY_ALGO_${itf}"} . ";\n";
1361 print FILE "\tsecret \"" . $dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"} . "\";\n";
1362 print FILE "};\n\n";
1363
1364 print FILE "zone " . $dhcpsettings{"DOMAIN_NAME_${itf}"} . ". {\n";
1365 print FILE "\tkey " . $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} . ";\n";
1366 print FILE "}\n\n";
1367 }
ac1cfefa 1368
dfdf076d 1369 &General::system('/usr/bin/touch', "${General::swroot}/dhcp/enable_${lc_itf}");
ac1cfefa
MT
1370 &General::log("DHCP on ${itf}: " . $Lang::tr{'dhcp server enabled'})
1371 } else {
1372 unlink "${General::swroot}/dhcp/enable_${lc_itf}";
1373 &General::log("DHCP on ${itf}: " . $Lang::tr{'dhcp server disabled'})
1374 }
1375 }
1376
1377 #write fixed leases if any. Does not handle duplicates to write them elsewhere than the global scope.
1378 my $key = 0;
1379 foreach my $line (@current2) {
1380 chomp($line);
1381 my @temp = split(/\,/,$line);
1382 if ($temp[2] eq "on") {
1383 print FILE "\nhost fix$key # $temp[6]\n";
1384 print FILE "{\n";
1385 print FILE "\thardware ethernet $temp[0];\n";
1386 print FILE "\tfixed-address $temp[1];\n";
1387 print FILE "\tnext-server $temp[3];\n" if ($temp[3]);
820ab96c 1388 print FILE "\tfilename \"" . &EscapeFilename($temp[4]) . "\";\n" if ($temp[4]);
ac1cfefa
MT
1389 print FILE "\toption root-path \"$temp[5]\";\n" if ($temp[5]);
1390 print FILE "}\n";
1391 $key++;
1392 }
1393 }
55b2f2eb 1394 print FILE "include \"${General::swroot}/dhcp/dhcpd.conf.local\";\n";
ac1cfefa 1395 close FILE;
dfdf076d
MT
1396 if ( $dhcpsettings{"ENABLE_GREEN"} eq 'on' || $dhcpsettings{"ENABLE_BLUE"} eq 'on' ) {&General::system('/usr/local/bin/dhcpctrl', 'enable');}
1397 else {&General::system('/usr/local/bin/dhcpctrl', 'disable');}
1398 &General::system_background('/usr/local/bin/dhcpctrl', 'restart');
ac1cfefa
MT
1399}
1400
1401#
1402# Receive a string and if it match model for a new option,
1403# add it to the list %newOptions
1404#
1405my %NewOptions = ();
1406
1407sub AddNewOptionDefinition {
1408 my ($line) = @_;
1409 if ( $line =~ /^([-\w]+)( code \d+=($OptionTypes))/ ) {
1410 $NewOptions{$1} = $2;
1411 #&General::log ("new:<$1><$2>");
1412 return 1;
1413 }
1414 return 0;
1415}
1416
1417#
1418# Check existence of definition for a new option
1419#
1420sub ExistNewOptionDefinition {
1421 my ($line) = @_;
1422
1423 if ( $line =~ /^([-\w]+)( code \d+=($OptionTypes))/ ) {
1424 return defined $NewOptions{$1};
1425 }
1426 return 0;
1427}
1428
1429#
1430# Check if it is a new option (definition must exist)
1431# "code=" test eliminate a false response when definition exists
1432# but this string is a definition with bad $OptionTypes.
1433sub ValidNewOption {
1434 my ($line) = @_;
1435 if ($line =~ /^([-\w]+) (.*)/ ) {
1436 return defined ( $NewOptions{$1} ) && $2 !~ /code=/;
1437 }
1438 return 0;
1439}
1440
1441#
1442# Check if the new option $opt is used, except the definition of itself!
1443#
1444sub IsUsedNewOptionDefinition {
1445 my ($opt,$val) = @_;
1446
1447 foreach my $line (@current1) {
1448 #chomp($line); # remove newline #don't know why, but this remove newline in @current1 .... !
1449 my @temp = split(/\t/,$line);
1450 # if we find something "opt value" & value != "code nnn=" it's ok.
1451 return 1 if ( ($opt eq $temp[1]) && ($temp[2] !~ /code \d+=/) );
1452 }
1453 return 0;
1454}
820ab96c
MT
1455
1456sub EscapeFilename($) {
1457 my $filename = shift;
1458
1459 # Replace all single / by \/
1460 $filename =~ s/\//\\\//g;
1461
1462 return $filename;
1463}