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