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