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