Gro├čes Update:
[ipfire-2.x.git] / html / cgi-bin / portfw.cgi
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 # Copyright (c) 2002/04/13 Steve Bootes - Add source IP support
9 #
10 # $Id: portfw.cgi,v 1.5.2.18 2005/05/02 16:19:49 eoberlander Exp $
11 #
12 #
13 # Darren Critchley February 2003 - I added the multiple external access rules for each port forward
14 # A couple of things to remember when reading the code
15 #       There are two kinds of records in the config file, those with a number in the first field, and then 0,
16 #               these are port forward rules, these records will have a 0 or 0.0.0.0 in position 9 (ORIG_IP)
17 #               If there is a 0, it means that there are external access rules, otherwise the port is open to ALL.
18 #       The second type of record is a number followed by a number which indicates that it is an external access
19 #       rule. The first number indicates which Portfw rule it belongs to, and the second is just a unique key.
20 #
21 # Darren Critchley - March 5, 2003 - if you come along after me and work on this page, please comment your
22 #               work. Put your name, and date and then your comment - it helps the person that comes along after you
23 #               to figure out why and how things have changed, and it is considered good coding practice
24 # Thanks . . . 
25 #
26
27 use strict;
28
29 # enable only the following on debugging purpose
30 #use warnings;
31 #use CGI::Carp 'fatalsToBrowser';
32
33 require 'CONFIG_ROOT/general-functions.pl';
34 require "${General::swroot}/lang.pl";
35 require "${General::swroot}/header.pl";
36
37 #workaround to suppress a warning when a variable is used only once
38 my @dummy = ( ${Header::colouryellow} );
39 undef (@dummy);
40
41 my %cgiparams=();
42 my %selected=();
43 my %checked=();
44 my $prtrange1=0;
45 my $prtrange2=0;
46 my $errormessage = '';
47 my $filename = "${General::swroot}/portfw/config";
48 my $aliasfile = "${General::swroot}/ethernet/aliases";
49
50 &Header::showhttpheaders();
51
52 $cgiparams{'ENABLED'} = 'off';
53 $cgiparams{'KEY1'} = '0';
54 $cgiparams{'KEY2'} = '0';
55 $cgiparams{'PROTOCOL'} = '';
56 $cgiparams{'SRC_PORT'} = '';
57 $cgiparams{'DEST_IP'} = '';
58 $cgiparams{'DEST_PORT'} = '';
59 $cgiparams{'SRC_IP'} = '';
60 $cgiparams{'ORIG_IP'} = '';
61 $cgiparams{'REMARK'} = '';
62 $cgiparams{'OVERRIDE'} = 'off';
63 $cgiparams{'ACTION'} = '';
64
65 &Header::getcgihash(\%cgiparams);
66
67 my $disable_all = "0";
68 my $enable_all = "0";
69
70 if ($cgiparams{'ACTION'} eq $Lang::tr{'add'})
71 {
72         &valaddupdate();
73         
74         # Darren Critchley - if there is an error, don't waste any more time processing
75         if ($errormessage) { goto ERROR; }
76         
77         open(FILE, $filename) or die 'Unable to open config file.';
78         my @current = <FILE>;
79         close(FILE);
80         my $key1 = 0; # used for finding last sequence number used 
81         foreach my $line (@current)
82         {
83                 my @temp = split(/\,/,$line);
84
85                 chomp ($temp[8]);
86                 if ($cgiparams{'KEY2'} eq "0"){ # if key2 is 0 then it is a portfw addition
87                         if ( $cgiparams{'SRC_PORT'} eq $temp[3] &&
88                                 $cgiparams{'PROTOCOL'} eq $temp[2] &&
89                                 $cgiparams{'SRC_IP'} eq $temp[7])
90                         {
91                                  $errormessage =  
92                                         "$Lang::tr{'source port in use'} $cgiparams{'SRC_PORT'}";
93                         }
94                         # Check if key2 = 0, if it is then it is a port forward entry and we want the sequence number
95                         if ( $temp[1] eq "0") {
96                                 $key1=$temp[0];
97                         }
98                         # Darren Critchley - Duplicate or overlapping Port range check
99                         if ($temp[1] eq "0" && 
100                                 $cgiparams{'PROTOCOL'} eq $temp[2] &&
101                                 $cgiparams{'SRC_IP'} eq $temp[7] &&
102                                 $errormessage eq '') 
103                         {
104                                 &portchecks($temp[3], $temp[5]);
105                         }
106                 } else {
107                         if ( $cgiparams{'KEY1'} eq $temp[0] &&
108                                 $cgiparams{'ORIG_IP'} eq $temp[8])
109                         {
110                                  $errormessage =  
111                                         "$Lang::tr{'source ip in use'} $cgiparams{'ORIG_IP'}";
112                         }
113                 }
114         }
115
116 ERROR:
117         unless ($errormessage)
118         {
119                 # Darren Critchley - we only want to store ranges with Colons
120                 $cgiparams{'SRC_PORT'} =~ tr/-/:/; 
121                 $cgiparams{'DEST_PORT'} =~ tr/-/:/;
122
123                 if ($cgiparams{'KEY1'} eq "0") { # 0 in KEY1 indicates it is a portfw add
124                         $key1++; # Add one to last sequence number
125                         open(FILE,">>$filename") or die 'Unable to open config file.';
126                         flock FILE, 2;
127                                 if ($cgiparams{'ORIG_IP'} eq '0.0.0.0/0') {
128                                         # if the default/all is taken, then write it to the rule
129                                                 print FILE "$key1,0,$cgiparams{'PROTOCOL'},$cgiparams{'SRC_PORT'},$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},$cgiparams{'SRC_IP'},$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";
130                         } else { # else create an extra record so it shows up 
131                                         print FILE "$key1,0,$cgiparams{'PROTOCOL'},$cgiparams{'SRC_PORT'},$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},$cgiparams{'SRC_IP'},0,$cgiparams{'REMARK'}\n";
132                                                 print FILE "$key1,1,$cgiparams{'PROTOCOL'},0,$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},0,$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";
133                                         }                       
134                         close(FILE);
135                         undef %cgiparams;
136                         &General::log($Lang::tr{'forwarding rule added'});
137                         system('/usr/local/bin/setportfw');
138                 } else { # else key1 eq 0
139                         my $insertpoint = ($cgiparams{'KEY2'} - 1);
140                         open(FILE, ">$filename") or die 'Unable to open config file.';
141                         flock FILE, 2;
142                         foreach my $line (@current) {
143                                 chomp($line);
144                                 my @temp = split(/\,/,$line);
145                                 if ($cgiparams{'KEY1'} eq $temp[0] && $insertpoint eq $temp[1]) {
146                                         if ($temp[1] eq "0") { # this is the first xtaccess rule, therefore modify the portfw rule
147                                                 $temp[8] = '0';
148                                         }
149                                         print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
150                                         print FILE "$cgiparams{'KEY1'},$cgiparams{'KEY2'},$cgiparams{'PROTOCOL'},0,$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},0,$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";
151                                 } else {
152                                         print FILE "$line\n";
153                                 }
154                         }
155                         close(FILE);
156                         undef %cgiparams;
157                         &General::log($Lang::tr{'external access rule added'});
158                         system('/usr/local/bin/setportfw');
159                 } # end if if KEY1 eq 0
160         } # end unless($errormessage)
161 }
162
163 if ($cgiparams{'ACTION'} eq $Lang::tr{'update'})
164 {
165         &valaddupdate();
166         
167         # Darren Critchley - If there is an error don't waste any more processing time
168         if ($errormessage) { $cgiparams{'ACTION'} = $Lang::tr{'edit'}; goto UPD_ERROR; }
169
170         open(FILE, $filename) or die 'Unable to open config file.';
171         my @current = <FILE>;
172         close(FILE);
173         my $disabledpfw = '0';
174         my $lastpfw = '';
175         my $xtaccessdel = '0';
176         
177         foreach my $line (@current)
178         {
179                 my @temp = split(/\,/,$line);
180                 if ( $temp[1] eq "0" ) { # keep track of the last portfw and if it is enabled
181                         $disabledpfw = $temp[6];
182                         $lastpfw = $temp[0];
183                 }               
184                 chomp ($temp[8]);
185                 if ( $cgiparams{'SRC_PORT'} eq $temp[3] &&
186                         $cgiparams{'PROTOCOL'} eq $temp[2] &&
187                         $cgiparams{'SRC_IP'} eq $temp[7])
188                 {
189                          if ($cgiparams{'KEY1'} ne $temp[0] && $cgiparams{'KEY2'} eq "0")
190                          { 
191                          $errormessage =  
192                                 "$Lang::tr{'source port in use'} $cgiparams{'SRC_PORT'}";
193                          }
194                 }
195                 if ($cgiparams{'ORIG_IP'} eq $temp[8]) 
196                 {
197                          if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} ne $temp[1])
198                          # If we have the same source ip within a portfw group, then we have a problem!
199                          {
200                                 $errormessage =  "$Lang::tr{'source ip in use'} $cgiparams{'ORIG_IP'}";
201                                 $cgiparams{'ACTION'} = $Lang::tr{'edit'};
202                          }
203                 }
204                 
205                 # Darren Critchley - Flag when a user disables an xtaccess
206                 if ($cgiparams{'KEY1'} eq $temp[0] &&
207                                 $cgiparams{'KEY2'} eq $temp[1] &&
208                                 $cgiparams{'KEY2'} ne "0" && # if KEY2 is 0 then it is a portfw
209                                 $cgiparams{'ENABLED'} eq "off" &&
210                                 $temp[6] eq "on") { # we have determined that someone has turned an xtaccess off
211                         $xtaccessdel = "1";             
212                 }
213                 
214                 # Darren Critchley - Portfw enabled, then enable xtaccess for all associated xtaccess records
215                 if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'KEY2'} eq "0" && $cgiparams{'ENABLED'} ne $temp[6]) 
216                 {
217                         $enable_all = "1";
218                 } else {
219                         $enable_all = "0";
220                 }
221                 # Darren Critchley - Portfw disabled, then disable xtaccess for all associated xtaccess records
222                 if ($cgiparams{'ENABLED'} eq "off" && $cgiparams{'KEY2'} eq "0") 
223                 {
224                         $disable_all = "1";
225                 } else {
226                         $disable_all = "0";
227                 }
228
229                 # Darren Critchley - if we are enabling an xtaccess, only allow if the associated Portfw is enabled
230                 if ($cgiparams{'KEY1'} eq $lastpfw && $cgiparams{'KEY2'} ne "0") { # identifies an xtaccess record in the group
231                         if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'ENABLED'} ne $temp[6] ){ # a change has been made
232                                 if ($disabledpfw eq "off")
233                                 { 
234                                         $errormessage =  "$Lang::tr{'cant enable xtaccess'}";
235                                         $cgiparams{'ACTION'} = $Lang::tr{'edit'};
236                                 }
237                         }
238                 }
239                 
240                 # Darren Critchley - rule to stop someone from entering ALL into a external access rule, 
241                 # the portfw is the only place that ALL can be specified
242                 if ($cgiparams{'KEY2'} ne "0" && $cgiparams{'ORIG_IP'} eq "0.0.0.0/0") {
243                         $errormessage =  "$Lang::tr{'xtaccess all error'}";
244                         $cgiparams{'ACTION'} = $Lang::tr{'edit'};
245                 }
246                 
247                 # Darren Critchley - Duplicate or overlapping Port range check
248                 if ($temp[1] eq "0" &&
249                         $cgiparams{'KEY1'} ne $temp[0] && 
250                         $cgiparams{'PROTOCOL'} eq $temp[2] &&
251                         $cgiparams{'SRC_IP'} eq $temp[7] &&
252                         $errormessage eq '') 
253                 {
254                                 &portchecks($temp[3], $temp[5]);
255                 } # end port testing
256                 
257         }
258         
259         # Darren Critchley - if an xtaccess was disabled, now we need to check to see if it was the only xtaccess
260         if($xtaccessdel eq "1") {
261                 my $xctr = 0;
262                 foreach my $line (@current)
263                 {
264                         my @temp = split(/\,/,$line);
265                         if($temp[0] eq $cgiparams{'KEY1'} &&
266                                 $temp[6] eq "on") { # we only want to count the enabled xtaccess's
267                                 $xctr++;
268                         }
269                 }
270                 if ($xctr == 2){
271                         $disable_all = "1";
272                 }
273         }
274
275 UPD_ERROR:
276         unless ($errormessage)
277         {
278                 # Darren Critchley - we only want to store ranges with Colons
279                 $cgiparams{'SRC_PORT'} =~ tr/-/:/; 
280                 $cgiparams{'DEST_PORT'} =~ tr/-/:/;
281
282                 open(FILE, ">$filename") or die 'Unable to open config file.';
283                 flock FILE, 2;
284                 foreach my $line (@current) {
285                         chomp($line);
286                         my @temp = split(/\,/,$line);
287                         if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1]) {
288                 print FILE "$cgiparams{'KEY1'},$cgiparams{'KEY2'},$cgiparams{'PROTOCOL'},$cgiparams{'SRC_PORT'},$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},$cgiparams{'SRC_IP'},$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";
289                         } else {
290                                 # Darren Critchley - If it is a port forward record, then chances are good that a change was made to 
291                                 # Destination Ip or Port, and we need to update all the associated external access records
292                                 if ($cgiparams{'KEY2'} eq "0" && $cgiparams{'KEY1'} eq $temp[0]) {
293                                         $temp[4] = $cgiparams{'DEST_IP'};
294                                         $temp[5] = $cgiparams{'DEST_PORT'};
295                                         $temp[2] = $cgiparams{'PROTOCOL'};
296                                 }
297                                 
298                                 # Darren Critchley - If a Portfw has been disabled, then set all associated xtaccess as disabled
299                                 if ( $disable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
300                                         $temp[6] = 'off';
301                                 }
302                                 if ( $enable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
303                                         $temp[6] = 'on';
304                                 }
305                                 # Darren Critchley - Deal with the override to allow ALL
306                                 if ( $cgiparams{'OVERRIDE'} eq "on" && $temp[1] ne "0" && $cgiparams{'KEY1'} eq $temp[0] ) {
307                                         $temp[6] = 'off';
308                                 }
309                         print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
310                         }
311                 }
312                 close(FILE);
313                 undef %cgiparams;
314                 &General::log($Lang::tr{'forwarding rule updated'});
315                 system('/usr/local/bin/setportfw');
316         } 
317         if ($errormessage) {
318         $cgiparams{'ACTION'} = $Lang::tr{'edit'};
319         }
320 }
321
322 # Darren Critchley - Allows rules to be enabled and disabled
323 if ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'})
324 {
325         open(FILE, $filename) or die 'Unable to open config file.';
326         my @current = <FILE>;
327         close(FILE);
328         my $disabledpfw = '0';
329         my $lastpfw = '';
330         my $xtaccessdel = '0';
331         
332         foreach my $line (@current)
333         {
334                 my @temp = split(/\,/,$line);
335                 if ( $temp[1] eq "0" ) { # keep track of the last portfw and if it is enabled
336                         $disabledpfw = $temp[6];
337                         $lastpfw = $temp[0];
338                 }               
339                 # Darren Critchley - Flag when a user disables an xtaccess
340                 if ($cgiparams{'KEY1'} eq $temp[0] &&
341                                 $cgiparams{'KEY2'} eq $temp[1] &&
342                                 $cgiparams{'KEY2'} ne "0" && # if KEY2 is 0 then it is a portfw
343                                 $cgiparams{'ENABLED'} eq "off" &&
344                                 $temp[6] eq "on") { # we have determined that someone has turned an xtaccess off
345                         $xtaccessdel = "1";             
346                 }
347                 
348                 # Darren Critchley - Portfw enabled, then enable xtaccess for all associated xtaccess records
349                 if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'KEY2'} eq "0" && $cgiparams{'ENABLED'} ne $temp[6]) 
350                 {
351                         $enable_all = "1";
352                 } else {
353                         $enable_all = "0";
354                 }
355                 # Darren Critchley - Portfw disabled, then disable xtaccess for all associated xtaccess records
356                 if ($cgiparams{'ENABLED'} eq "off" && $cgiparams{'KEY2'} eq "0") 
357                 {
358                         $disable_all = "1";
359                 } else {
360                         $disable_all = "0";
361                 }
362
363                 # Darren Critchley - if we are enabling an xtaccess, only allow if the associated Portfw is enabled
364                 if ($cgiparams{'KEY1'} eq $lastpfw && $cgiparams{'KEY2'} ne "0") { # identifies an xtaccess record in the group
365                         if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'ENABLED'} ne $temp[6] ){ # a change has been made
366                                 if ($disabledpfw eq "off")
367                                 { 
368                                         $errormessage =  "$Lang::tr{'cant enable xtaccess'}";
369                                         goto TOGGLEEXIT;
370                                 }
371                         }
372                 }
373         }
374         
375         # Darren Critchley - if an xtaccess was disabled, now we need to check to see if it was the only xtaccess
376         if($xtaccessdel eq "1") {
377                 my $xctr = 0;
378                 foreach my $line (@current)
379                 {
380                         my @temp = split(/\,/,$line);
381                         if($temp[0] eq $cgiparams{'KEY1'} &&
382                                 $temp[6] eq "on") { # we only want to count the enabled xtaccess's
383                                 $xctr++;
384                         }
385                 }
386                 if ($xctr == 2){
387                         $disable_all = "1";
388                 }
389         }
390
391         open(FILE, ">$filename") or die 'Unable to open config file.';
392         flock FILE, 2;
393         foreach my $line (@current) {
394                 chomp($line);
395                 my @temp = split(/\,/,$line);
396                 if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1]) {
397                 print FILE "$cgiparams{'KEY1'},$cgiparams{'KEY2'},$temp[2],$temp[3],$temp[4],$temp[5],$cgiparams{'ENABLED'},$temp[7],$temp[8],$temp[9]\n";
398                 } else {
399                         # Darren Critchley - If a Portfw has been disabled, then set all associated xtaccess as disabled
400                         if ( $disable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
401                                 $temp[6] = 'off';
402                         }
403                         if ( $enable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
404                                 $temp[6] = 'on';
405                         }
406                 print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
407                 }
408         }
409         close(FILE);
410         &General::log($Lang::tr{'forwarding rule updated'});
411         system('/usr/local/bin/setportfw');
412 TOGGLEEXIT:
413         undef %cgiparams;
414
415
416
417 # Darren Critchley - broke out Edit routine from the delete routine - Edit routine now just puts values in fields
418 if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'})
419 {
420         open(FILE, "$filename") or die 'Unable to open config file.';
421         my @current = <FILE>;
422         close(FILE);
423
424         unless ($errormessage)
425         {
426                 foreach my $line (@current)
427                 {
428                         chomp($line);
429                         my @temp = split(/\,/,$line);
430                         if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) {
431                                 $cgiparams{'PROTOCOL'} = $temp[2];
432                                 $cgiparams{'SRC_PORT'} = $temp[3];
433                                 $cgiparams{'DEST_IP'} = $temp[4];
434                                 $cgiparams{'DEST_PORT'} = $temp[5];
435                                 $cgiparams{'ENABLED'} = $temp[6];
436                                 $cgiparams{'SRC_IP'} = $temp[7];
437                                 $cgiparams{'ORIG_IP'} = $temp[8];
438                                 $cgiparams{'REMARK'} = $temp[9];
439                         }
440                         
441                 }
442         }
443 }
444
445 # Darren Critchley - broke out Remove routine as the logic is getting too complex to be combined with the Edit
446 if ($cgiparams{'ACTION'} eq $Lang::tr{'remove'})
447 {
448         open(FILE, "$filename") or die 'Unable to open config file.';
449         my @current = <FILE>;
450         close(FILE);
451         
452         # If the record being deleted is an xtaccess record, and it is the only one for a portfw record
453         # then we need to adjust the portfw record to be open to ALL ip addressess or an error will occur
454         # in setportfw.c
455         my $fixportfw = '0';
456         if ($cgiparams{'KEY2'} ne "0") {
457                 my $counter = 0;
458                 foreach my $line (@current)
459                 {
460                         chomp($line);
461                         my @temp = split(/\,/,$line);
462                         if ($temp[0] eq $cgiparams{'KEY1'}) {
463                                 $counter++;
464                         }
465                 } 
466                 if ($counter eq 2) {
467                         $fixportfw = '1';
468                 }
469         }
470         
471         unless ($errormessage)
472         {
473                 open(FILE, ">$filename") or die 'Unable to open config file.';
474                 flock FILE, 2;
475                 my $linedeleted = 0;
476                 foreach my $line (@current)
477                 {
478                         chomp($line);
479                         my @temp = split(/\,/,$line);
480
481                         if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ||
482                                 $cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq "0" ) 
483                         {
484                                 $linedeleted = 1;
485                         } else {
486                                 if ($temp[0] eq $cgiparams{'KEY1'} && $temp[1] eq "0" && $fixportfw eq "1") {
487                                         $temp[8] = '0.0.0.0/0';
488                                 }
489                         print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
490 #                               print FILE "$line\n";
491                         }
492                 }
493                 close(FILE);
494                 if ($linedeleted == 1) {
495                         &General::log($Lang::tr{'forwarding rule removed'});
496                         undef %cgiparams;
497                 }
498                 system('/usr/local/bin/setportfw');
499         }
500 }
501
502 # Darren Critchley - Added routine to allow external access rules to be added
503 if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'})
504 {
505         open(FILE, $filename) or die 'Unable to open config file.';
506         my @current = <FILE>;
507         close(FILE);
508         my $key = 0; # used for finding last sequence number used 
509         foreach my $line (@current)
510         {
511                 my @temp = split(/\,/,$line);
512                 if ($temp[0] eq $cgiparams{'KEY1'}) {
513                         $key = $temp[1]
514                 }
515                 if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) {
516                         $cgiparams{'PROTOCOL'} = $temp[2];
517                         $cgiparams{'SRC_PORT'} = $temp[3];
518                         $cgiparams{'DEST_IP'} = $temp[4];
519                         $cgiparams{'DEST_PORT'} = $temp[5];
520                         $cgiparams{'ENABLED'} = $temp[6];
521                         $cgiparams{'SRC_IP'} = $temp[7];
522                         $cgiparams{'ORIG_IP'} = '';
523                         $cgiparams{'REMARK'} = $temp[9];
524                 }
525         }
526         $key++;
527         $cgiparams{'KEY2'} = $key;
528         # Until the ADD button is hit, there needs to be no change to portfw rules
529 }
530
531 if ($cgiparams{'ACTION'} eq $Lang::tr{'reset'})
532 {
533         undef %cgiparams;
534 }
535
536 if ($cgiparams{'ACTION'} eq '')
537 {
538         $cgiparams{'PROTOCOL'} = 'tcp';
539         $cgiparams{'ENABLED'} = 'on';
540         $cgiparams{'SRC_IP'} = '0.0.0.0';
541 }
542
543 $selected{'PROTOCOL'}{'udp'} = '';
544 $selected{'PROTOCOL'}{'tcp'} = '';
545 $selected{'PROTOCOL'}{'gre'} = '';
546 $selected{'PROTOCOL'}{$cgiparams{'PROTOCOL'}} = "selected='selected'";
547
548 $selected{'SRC_IP'}{$cgiparams{'SRC_IP'}} = "selected='selected'";
549
550 $checked{'ENABLED'}{'off'} = '';
551 $checked{'ENABLED'}{'on'} = '';  
552 $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'";
553
554 &Header::openpage($Lang::tr{'port forwarding configuration'}, 1, '');
555
556 &Header::openbigbox('100%', 'left', '', $errormessage);
557
558 if ($errormessage) {
559         &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
560         print "<class name='base'><font color='${Header::colourred}'>$errormessage\n</font>";
561         print "&nbsp;</class>\n";
562         &Header::closebox();
563 }
564
565 print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>\n";
566
567 if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){
568         &Header::openbox('100%', 'left', $Lang::tr{'edit a rule'});
569 } else {
570         &Header::openbox('100%', 'left', $Lang::tr{'add a new rule'});
571 }
572
573 if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'KEY2'} ne "0" || $cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}){ 
574 # if it is not a port forward record, don't validate as the fields are disabled
575         my $PROT = "\U$cgiparams{'PROTOCOL'}\E";
576         # Darren Critchley - Format the source and destination ports
577         my $dstprt = $cgiparams{'DEST_PORT'};
578         $dstprt =~ s/-/ - /;
579         $dstprt =~ s/:/ - /;
580
581 print <<END
582 <table>
583         <tr>
584                 <td class='base'>$Lang::tr{'protocol'}: <b>$PROT</b></td>
585                 <td width='20'>&nbsp;</td>
586                 <td class='base' align='right'>$Lang::tr{'destination ip'}:&nbsp;</td>
587                 <td><b>$cgiparams{'DEST_IP'}</b></td>
588                 <td width='20'>&nbsp;</td>
589                 <td class='base' align='right'>$Lang::tr{'destination port'}:&nbsp;</td>
590                 <td><b>$dstprt</b></td>
591         </tr>
592 </table>
593
594 <input type='hidden' name='PROTOCOL' value='$cgiparams{'PROTOCOL'}' />
595 <input type='hidden' name='SRC_IP' value='$cgiparams{'SRC_IP'}' />
596 <input type='hidden' name='SRC_PORT' value='$cgiparams{'SRC_PORT'}' />
597 <input type='hidden' name='DEST_IP' value='$cgiparams{'DEST_IP'}' />
598 <input type='hidden' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' />
599 END
600 ;
601 } else {
602 print <<END
603 <table width='100%'>
604         <tr>
605                 <td width='10%'>$Lang::tr{'protocol'}:&nbsp;</td>
606                 <td width='15%'> 
607                 <select name='PROTOCOL'>
608                         <option value='tcp' $selected{'PROTOCOL'}{'tcp'}>TCP</option>
609                         <option value='udp' $selected{'PROTOCOL'}{'udp'}>UDP</option>
610                         <option value='gre' $selected{'PROTOCOL'}{'gre'}>GRE</option>
611                 </select>
612                 </td>
613                 <td class='base' width='20%'><font color='${Header::colourred}'>$Lang::tr{'alias ip'}:</font></td>
614                 <td>
615                         <select name='SRC_IP'>
616                         <option value='0.0.0.0' $selected{'SRC_IP'}{'0.0.0.0'}>DEFAULT IP</option>
617 END
618 ;
619 open(ALIASES, "$aliasfile") or die 'Unable to open aliases file.';
620 while (<ALIASES>)
621 {
622         chomp($_);
623         my @temp = split(/\,/,$_);
624         if ($temp[1] eq 'on') {
625                 print "<option value='$temp[0]' $selected{'SRC_IP'}{$temp[0]}>$temp[0]";
626                 if (defined $temp[2] and ($temp[2] ne '')) { print " ($temp[2])"; }
627                 print "</option>\n";
628         }
629 }
630 close(ALIASES);
631 print <<END
632                         </select>
633                 </td>
634                 <td class='base' width='20%'><font color='${Header::colourred}'>$Lang::tr{'source port'}:</font></td>
635                 <td width='10%'><input type='text' name='SRC_PORT' value='$cgiparams{'SRC_PORT'}' size='8' /></td>
636         </tr>
637         <tr>
638                 <td class='base'>&nbsp;</td>
639                 <td>&nbsp;</td>
640                 <td class='base'>$Lang::tr{'destination ip'}:</td>
641                 <td><input type='text' name='DEST_IP' value='$cgiparams{'DEST_IP'}' size='15' /></td>
642                 <td class='base'>$Lang::tr{'destination port'}:</td>
643                 <td><input type='text' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' size='8' /></td>
644         </tr>
645 </table>
646 END
647 ;
648 }
649
650 print <<END
651 <table>
652         <tr>
653                 <td class='base'>$Lang::tr{'remark title'}&nbsp;<img src='/blob.gif' alt='*' />&nbsp;</td>
654                 <td><input type='text' name='REMARK' value='$cgiparams{'REMARK'}' size='55' maxlength='50' /></td>
655 END
656 ;
657 unless ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'} && $cgiparams{'ENABLED'} eq "off") {
658         print "<td width='20'>&nbsp;</td>";
659         print "<td>$Lang::tr{'enabled'}&nbsp;</td><td><input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} /></td>\n";
660 }
661 print <<END
662         </tr>
663 </table>
664 END
665 ;
666
667 if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'KEY2'} eq "0" && ($cgiparams{'ORIG_IP'} eq "0" || $cgiparams{'ORIG_IP'} eq "0.0.0.0/0")){ 
668 # if it is a port forward rule with a 0 in the orig_port field, this means there are xtaccess records, and we
669 # don't want to allow a person to change the orig_ip field as it will mess other logic up
670         print "<input type='hidden' name='ORIG_IP' value='$cgiparams{'ORIG_IP'}' />\n";
671 } else {
672 print <<END
673 <table>
674         <tr>
675                 <td class='base'><font class='boldbase' color='${Header::colourred}'>$Lang::tr{'source network'}</font>&nbsp;<img src='/blob.gif' alt='*' />&nbsp;</td>
676                 <td><input type='text' name='ORIG_IP' value='$cgiparams{'ORIG_IP'}' size='15' /></td>
677         </tr>
678 </table>
679 END
680 ;
681 }
682
683 print <<END
684 <table width='100%'>
685         <hr />
686         <tr>
687                 <td class='base' width='25%'><img src='/blob.gif' alt ='*' align='top' />&nbsp;<font class='base'>$Lang::tr{'this field may be blank'}</font></td>
688 END
689 ;
690
691
692 if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){
693         if($cgiparams{'KEY2'} eq "0"){
694                 print "<td width='35%' align='right'>$Lang::tr{'open to all'}:&nbsp;</td><td width='5%'><input type='checkbox' name='OVERRIDE' $checked{'OVERRIDE'}{'on'} /></td>\n";
695         } else {
696                 print "<td width='40%'>&nbsp;</td>\n";
697         }
698         print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' />";
699         print "<input type='hidden' name='KEY1' value='$cgiparams{'KEY1'}' />";
700         print "<input type='hidden' name='KEY2' value='$cgiparams{'KEY2'}' /></TD>";
701         print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
702         # on an edit and an xtaccess add, for some reason the "Reset" button stops working, so I make it a submit button
703 } else {
704         print "<td width='30%'>&nbsp;</td>\n";
705         print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td>";
706         if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}) {
707                 print "<td align='center' width='15%'><input type='hidden' name='KEY1' value='$cgiparams{'KEY1'}' />";
708                 print "<input type='hidden' name='KEY2' value='$cgiparams{'KEY2'}' />";
709                 print "<input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
710         } elsif ($errormessage ne '') {
711                 print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
712         } else {
713                 print "<td align='center' width='15%'><input type='reset' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
714         }
715 }
716 print <<END
717         <td width='5%' align='right'>
718                 <a href='${General::adminmanualurl}/section-firewall.html#section-port-forwarding' target='_blank'>
719                 <img src='/images/web-support.png' alt='$Lang::tr{'online help en'}' title='$Lang::tr{'online help en'}' /></a></td>
720         </tr>
721 </table>
722 END
723 ;
724 &Header::closebox();
725
726 print "</form>\n";
727
728 &Header::openbox('100%', 'left', $Lang::tr{'current rules'});
729 print <<END
730 <table width='100%'>
731 <tr>
732 <td width='7%' class='boldbase' align='center'><b>$Lang::tr{'proto'}</b></td>
733 <td width='31%' class='boldbase' align='center'><b>$Lang::tr{'source'}</b></td>
734 <td width='2%' class='boldbase' align='center'>&nbsp;</td>
735 <td width='31%' class='boldbase' align='center'><b>$Lang::tr{'destination'}</b></td>
736 <td width='24%' class='boldbase' align='center'><b>$Lang::tr{'remark'}</b></td>
737 <td width='4%' class='boldbase' colspan='4' align='center'><b>$Lang::tr{'action'}</b></td>
738 </tr>
739 END
740 ;
741
742 my $id = 0;
743 my $xtaccesscolor = '#F6F4F4';
744 open(RULES, "$filename") or die 'Unable to open config file.';
745 while (<RULES>)
746 {
747         my $protocol = '';
748         my $gif = '';
749         my $gdesc = '';
750         my $toggle = '';
751         chomp($_);
752         my @temp = split(/\,/,$_);
753         $temp[9] ='' unless defined $temp[9];# Glles ESpinasse : suppress warning on page init
754         if ($temp[2] eq 'udp') {
755                 $protocol = 'UDP'; }
756         elsif ($temp[2] eq 'gre') {
757                 $protocol = 'GRE' }
758         else {
759                 $protocol = 'TCP' }
760         # Change bgcolor when a new portfw rule is added
761         if ($temp[1] eq "0"){
762                 $id++;
763         }
764         # Darren Critchley highlight the row we are editing
765         if ( $cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) { 
766                 print "<tr bgcolor='${Header::colouryellow}'>\n";
767         } else {
768                 if ($id % 2) {
769                         print "<tr bgcolor='${Header::table1colour}'>\n"; 
770                 }
771                 else {
772                         print "<tr bgcolor='${Header::table2colour}'>\n";
773                 }
774         }
775         
776         if ($temp[6] eq 'on') { $gif = 'on.gif'; $toggle='off'; $gdesc=$Lang::tr{'click to disable'};}
777                 else { $gif = 'off.gif'; $toggle='on'; $gdesc=$Lang::tr{'click to enable'}; }
778
779                 # Darren Critchley - this code no longer works - should we remove?
780         # catch for 'old-style' rules file - assume default ip if
781         # none exists
782         if (!&General::validip($temp[7]) || $temp[7] eq '0.0.0.0') {
783                 $temp[7] = 'DEFAULT IP'; }
784                 if ($temp[1] eq '0') { # Port forwarding entry
785
786                 # Darren Critchley - Format the source and destintation ports
787                 my $srcprt = $temp[3];
788                 $srcprt =~ s/-/ - /;
789                 $srcprt =~ s/:/ - /;
790                 my $dstprt = $temp[5];
791                 $dstprt =~ s/-/ - /;
792                 $dstprt =~ s/:/ - /;
793
794                 # Darren Critchley - Get Port Service Name if we can - code borrowed from firewalllog.dat
795                 $_=$temp[3];
796                 if (/^\d+$/) {
797                         my $servi = uc(getservbyport($temp[3], lc($temp[2])));
798                         if ($servi ne '' && $temp[3] < 1024) {
799                                 $srcprt = "$srcprt($servi)"; }
800                 }
801                 $_=$temp[5];
802                 if (/^\d+$/) {
803                         my $servi = uc(getservbyport($temp[5], lc($temp[2])));
804                         if ($servi ne '' && $temp[5] < 1024) {
805                                 $dstprt = "$dstprt($servi)"; }
806                 }
807
808                 # Darren Critchley - If the line is too long, wrap the port numbers
809                 my $srcaddr = "$temp[7] : $srcprt";
810                 if (length($srcaddr) > 22) {
811                         $srcaddr = "$temp[7] :<br /> $srcprt";
812                 }
813                 my $dstaddr = "$temp[4] : $dstprt";
814                 if (length($dstaddr) > 26) {
815                         $dstaddr = "$temp[4] :<br /> $dstprt";
816                 }
817 print <<END
818 <td align='center'>$protocol</td>
819 <td align='center'>$srcaddr</td>
820 <td align='center'><img src='/images/forward.gif' alt='=&gt;' /></td>
821 <td align='center'>$dstaddr</td>
822 <td align='left'>&nbsp;$temp[9]</td>
823 <td align='center'>
824         <form method='post' name='frm$temp[0]c' action='$ENV{'SCRIPT_NAME'}'>
825         <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
826         <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
827         <input type='hidden' name='KEY1' value='$temp[0]' />
828         <input type='hidden' name='KEY2' value='$temp[1]' />
829         <input type='hidden' name='ENABLED' value='$toggle' />
830         </form>
831 </td>
832
833 <td align='center'>
834         <form method='post' name='frm$temp[0]' action='$ENV{'SCRIPT_NAME'}'>
835         <input type='hidden' name='ACTION' value='$Lang::tr{'add xtaccess'}' />
836         <input type='image' name='$Lang::tr{'add xtaccess'}' src='/images/add.gif' alt='$Lang::tr{'add xtaccess'}' title='$Lang::tr{'add xtaccess'}' />
837         <input type='hidden' name='KEY1' value='$temp[0]' />
838         <input type='hidden' name='KEY2' value='$temp[1]' />
839         </form>
840 </td>
841
842 <td align='center'>
843         <form method='post' name='frm$temp[0]' action='$ENV{'SCRIPT_NAME'}'>
844         <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
845         <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
846         <input type='hidden' name='KEY1' value='$temp[0]' />
847         <input type='hidden' name='KEY2' value='$temp[1]' />
848         </form>
849 </td>
850
851 <td align='center'>
852         <form method='post' name='frm$temp[0]b' action='$ENV{'SCRIPT_NAME'}'>
853         <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
854         <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
855         <input type='hidden' name='KEY1' value='$temp[0]' />
856         <input type='hidden' name='KEY2' value='$temp[1]' />
857         </form>
858 </td>
859
860 </tr>
861 END
862         ;
863         } else { # external access entry
864 print <<END
865 <td align='center'>&nbsp;</td>
866
867 <td align='left' colspan='4'>&nbsp;<font color='${Header::colourred}'>$Lang::tr{'access allowed'}</font> $temp[8]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;($temp[9])</td>
868
869 <td align='center'>
870         <form method='post' name='frm$temp[0]$temp[1]t' action='$ENV{'SCRIPT_NAME'}'>
871         <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
872         <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
873         <input type='hidden' name='KEY1' value='$temp[0]' />
874         <input type='hidden' name='KEY2' value='$temp[1]' />
875         <input type='hidden' name='ENABLED' value='$toggle' />
876         </form>
877 </td>
878
879 <td align='center'>&nbsp;</td>
880
881 <td align='center'>
882         <form method='post' name='frm$temp[0]$temp[1]' action='$ENV{'SCRIPT_NAME'}'>
883         <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
884         <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
885         <input type='hidden' name='KEY1' value='$temp[0]' />
886         <input type='hidden' name='KEY2' value='$temp[1]' />
887         </form>
888 </td>
889
890 <td align='center'>
891         <form method='post' name='frm$temp[0]b$temp[1]b' action='$ENV{'SCRIPT_NAME'}'>
892         <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
893         <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
894         <input type='hidden' name='KEY1' value='$temp[0]' />
895         <input type='hidden' name='KEY2' value='$temp[1]' />
896         </form>
897 </td>
898
899 </tr>
900 END
901         ;
902         }
903 }
904
905 close(RULES);
906
907 print "</table>";
908
909 # If the fixed lease file contains entries, print Key to action icons
910 if ( ! -z "$filename") {
911 print <<END
912 <table>
913 <tr>
914         <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
915         <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
916         <td class='base'>$Lang::tr{'click to disable'}</td>
917         <td>&nbsp;&nbsp;</td>
918         <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
919         <td class='base'>$Lang::tr{'click to enable'}</td>
920         <td>&nbsp;&nbsp;</td>
921         <td><img src='/images/add.gif' alt='$Lang::tr{'add xtaccess'}' /></td>
922         <td class='base'>$Lang::tr{'add xtaccess'}</td>
923         <td>&nbsp;&nbsp;</td>
924         <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
925         <td class='base'>$Lang::tr{'edit'}</td>
926         <td>&nbsp;&nbsp;</td>
927         <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
928         <td class='base'>$Lang::tr{'remove'}</td>
929 </tr>
930 </table>
931 END
932 ;
933 }
934
935 &Header::closebox();
936
937 &Header::closebigbox();
938
939 &Header::closepage();
940
941 # Validate Field Entries
942 sub validateparams 
943 {
944         # Darren Critchley - Get rid of dashes in port ranges
945         $cgiparams{'DEST_PORT'}=~ tr/-/:/;
946         $cgiparams{'SRC_PORT'}=~ tr/-/:/;
947         
948         # Darren Critchley - code to substitue wildcards
949         if ($cgiparams{'SRC_PORT'} eq "*") {
950                 $cgiparams{'SRC_PORT'} = "1:65535";
951         }
952         if ($cgiparams{'SRC_PORT'} =~ /^(\D)\:(\d+)$/) {
953                 $cgiparams{'SRC_PORT'} = "1:$2";
954         }
955         if ($cgiparams{'SRC_PORT'} =~ /^(\d+)\:(\D)$/) {
956                 $cgiparams{'SRC_PORT'} = "$1:65535";
957         }
958         if ($cgiparams{'DEST_PORT'} eq "*") {
959                 $cgiparams{'DEST_PORT'} = "1:65535";
960         }
961         if ($cgiparams{'DEST_PORT'} =~ /^(\D)\:(\d+)$/) {
962                 $cgiparams{'DEST_PORT'} = "1:$2";
963         }
964         if ($cgiparams{'DEST_PORT'} =~ /^(\d+)\:(\D)$/) {
965                 $cgiparams{'DEST_PORT'} = "$1:65535";
966         }
967
968         # Darren Critchley - Add code for GRE protocol - we want to ignore ports, but we need a place holder
969         if ($cgiparams{'PROTOCOL'} eq 'gre') {
970                 $cgiparams{'SRC_PORT'} = "GRE";
971                 $cgiparams{'DEST_PORT'} = "GRE";
972         }
973
974         unless($cgiparams{'PROTOCOL'} =~ /^(tcp|udp|gre)$/) { $errormessage = $Lang::tr{'invalid input'}; }
975         # Darren Critchley - Changed how the error routine works a bit - for the validportrange check, we need to 
976         # pass in src or dest to determine which side we are working with.
977         # the routine returns the complete error or ''
978         if ($cgiparams{'PROTOCOL'} ne 'gre') {
979                 $errormessage = &General::validportrange($cgiparams{'SRC_PORT'}, 'src');
980         }
981         if( ($cgiparams{'ORIG_IP'} ne "0" && $cgiparams{'KEY2'} ne "0") || $cgiparams{'ACTION'} eq $Lang::tr{'add'}) { 
982         # if it is a port forward record with 0 in orig_ip then ignore checking this field
983                 unless(&General::validipormask($cgiparams{'ORIG_IP'}))
984                 {
985                         if ($cgiparams{'ORIG_IP'} ne '') {
986                                 $errormessage = $Lang::tr{'source ip bad'}; }
987                         else {
988                                 $cgiparams{'ORIG_IP'} = '0.0.0.0/0'; }
989                 }
990         }
991         # Darren Critchey - New rule that sets destination same as source if dest_port is blank.
992         if ($cgiparams{'DEST_PORT'} eq ''){
993                 $cgiparams{'DEST_PORT'} = $cgiparams{'SRC_PORT'};
994         }
995         # Darren Critchey - Just in case error message is already set, this routine would wipe it out if
996         # we don't do a test here
997         if ($cgiparams{'PROTOCOL'} ne 'gre') {
998                 unless($errormessage) {$errormessage = &General::validportrange($cgiparams{'DEST_PORT'}, 'dest');}
999         }
1000         unless(&General::validip($cgiparams{'DEST_IP'})) { $errormessage = $Lang::tr{'destination ip bad'}; }
1001         return;
1002 }
1003
1004 # Darren Critchley - we want to make sure that a port range does not overlap another port range
1005 sub checkportoverlap
1006 {
1007         my $portrange1 = $_[0]; # New port range
1008         my $portrange2 = $_[1]; # existing port range
1009         my @tempr1 = split(/\:/,$portrange1);
1010         my @tempr2 = split(/\:/,$portrange2);
1011
1012         unless (&checkportinc($tempr1[0], $portrange2)){ return 0;}
1013         unless (&checkportinc($tempr1[1], $portrange2)){ return 0;}
1014         
1015         unless (&checkportinc($tempr2[0], $portrange1)){ return 0;}
1016         unless (&checkportinc($tempr2[1], $portrange1)){ return 0;}
1017
1018         return 1; # Everything checks out!
1019 }
1020
1021 # Darren Critchley - we want to make sure that a port entry is not within an already existing range
1022 sub checkportinc
1023 {
1024         my $port1 = $_[0]; # Port
1025         my $portrange2 = $_[1]; # Port range
1026         my @tempr1 = split(/\:/,$portrange2);
1027
1028         if ($port1 < $tempr1[0] || $port1 > $tempr1[1]) {
1029                 return 1; 
1030         } else {
1031                 return 0; 
1032         }
1033 }
1034
1035 # Darren Critchley - certain ports are reserved for Ipcop 
1036 # TCP 67,68,81,222,445
1037 # UDP 67,68
1038 # Params passed in -> port, rangeyn, protocol
1039 sub disallowreserved
1040 {
1041         # port 67 and 68 same for tcp and udp, don't bother putting in an array
1042         my $msg = "";
1043         my @tcp_reserved = (81,222,444);
1044         my $prt = $_[0]; # the port or range
1045         my $ryn = $_[1]; # tells us whether or not it is a port range
1046         my $prot = $_[2]; # protocol
1047         my $srcdst = $_[3]; # source or destination
1048         
1049         if ($ryn) { # disect port range
1050                 if ($srcdst eq "src") {
1051                         $msg = "$Lang::tr{'rsvd src port overlap'}";
1052                 } else {
1053                         $msg = "$Lang::tr{'rsvd dst port overlap'}";
1054                 }
1055                 my @tmprng = split(/\:/,$prt);
1056                 unless (67 < $tmprng[0] || 67 > $tmprng[1]) { $errormessage="$msg 67"; return; }
1057                 unless (68 < $tmprng[0] || 68 > $tmprng[1]) { $errormessage="$msg 68"; return; }
1058                 if ($prot eq "tcp") {
1059                         foreach my $prange (@tcp_reserved) {
1060                                 unless ($prange < $tmprng[0] || $prange > $tmprng[1]) { $errormessage="$msg $prange"; return; }
1061                         }
1062                 }
1063         } else {
1064                 if ($srcdst eq "src") {
1065                         $msg = "$Lang::tr{'reserved src port'}";
1066                 } else {
1067                         $msg = "$Lang::tr{'reserved dst port'}";
1068                 }
1069                 if ($prt == 67) { $errormessage="$msg 67"; return; }
1070                 if ($prt == 68) { $errormessage="$msg 68"; return; }
1071                 if ($prot eq "tcp") {
1072                         foreach my $prange (@tcp_reserved) {
1073                                 if ($prange == $prt) { $errormessage="$msg $prange"; return; }
1074                         }
1075                 }
1076         }
1077         return;
1078 }
1079
1080 # Darren Critchley - Attempt to combine Add/Update validation as they are almost the same
1081 sub valaddupdate
1082 {
1083         if ($cgiparams{'KEY2'} eq "0"){ # if it is a port forward rule, then validate properly
1084                 &validateparams();
1085         } else { # it is an xtaccess rule, just check for a valid ip
1086                 unless(&General::validipormask($cgiparams{'ORIG_IP'}))
1087                 {
1088                         if ($cgiparams{'ORIG_IP'} ne '') {
1089                                 $errormessage = $Lang::tr{'source ip bad'}; }
1090                         else { # this rule stops someone from adding an ALL xtaccess record
1091                                 $errormessage = $Lang::tr{'xtaccess all error'}; 
1092                                 $cgiparams{'ACTION'} = $Lang::tr{'add xtaccess'};
1093                         }
1094                 }
1095                 # Darren Critchley - check for 0.0.0.0/0 - not allowed for xtaccess
1096                 if ($cgiparams{'ORIG_IP'} eq "0.0.0.0/0" || $cgiparams{'ORIG_IP'} eq "0.0.0.0") {
1097                         $errormessage = $Lang::tr{'xtaccess all error'}; 
1098                         $cgiparams{'ACTION'} = $Lang::tr{'add xtaccess'};
1099                 }
1100         }
1101         # Darren Critchley - Remove commas from remarks
1102         $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'});
1103
1104         # Darren Critchley - Check to see if we are working with port ranges
1105         our ($prtrange1, $prtrange2);
1106         $_ = $cgiparams{'SRC_PORT'};
1107         if ($cgiparams{'KEY2'} eq "0" && m/:/){
1108                 $prtrange1 = 1;
1109         }
1110         if ($cgiparams{'SRC_IP'} eq '0.0.0.0') { # Dave Roberts - only check if using DEFAULT IP
1111                 if ($prtrange1 == 1){ # check for source ports reserved for Ipcop
1112                         &disallowreserved($cgiparams{'SRC_PORT'},1,$cgiparams{'PROTOCOL'},"src");
1113                         if ($errormessage) { goto EXITSUB; }
1114                 } else { # check for source port reserved for Ipcop
1115                         &disallowreserved($cgiparams{'SRC_PORT'},0,$cgiparams{'PROTOCOL'},"src");
1116                         if ($errormessage) { goto EXITSUB; }
1117                 }
1118         }
1119         
1120         $_ = $cgiparams{'DEST_PORT'};
1121         if ($cgiparams{'KEY2'} eq "0" && m/:/){
1122                 $prtrange2 = 1;
1123         }
1124         if ($cgiparams{'SRC_IP'} eq '0.0.0.0') { # Dave Roberts - only check if using DEFAULT IP
1125                 if ($prtrange2 == 1){ # check for destination ports reserved for IPFire
1126                         &disallowreserved($cgiparams{'DEST_PORT'},1,$cgiparams{'PROTOCOL'},"dst");
1127                         if ($errormessage) { goto EXITSUB; }
1128                 } else { # check for destination port reserved for IPFire
1129                         &disallowreserved($cgiparams{'DEST_PORT'},0,$cgiparams{'PROTOCOL'},"dst");
1130                         if ($errormessage) { goto EXITSUB; }
1131                 }
1132         }
1133         
1134
1135 EXITSUB:
1136         return;
1137 }
1138
1139 # Darren Critchley - Duplicate or overlapping Port range check
1140 sub portchecks
1141 {
1142         $_ = $_[0];
1143         our ($prtrange1, $prtrange2);
1144         if (m/:/ && $prtrange1 == 1) { # comparing two port ranges
1145                 unless (&checkportoverlap($cgiparams{'SRC_PORT'},$_[0])) {
1146                         $errormessage = "$Lang::tr{'source port overlaps'} $_[0]";
1147                 }
1148         }
1149         if (m/:/ && $prtrange1 == 0 && $errormessage eq '') { # compare one port to a range
1150                 unless (&checkportinc($cgiparams{'SRC_PORT'}, $_[0])) {
1151                         $errormessage = "$Lang::tr{'srcprt within existing'} $_[0]";
1152                 }
1153         }
1154         if (! m/:/ && $prtrange1 == 1 && $errormessage eq '') { # compare one port to a range
1155                 unless (&checkportinc($_[0], $cgiparams{'SRC_PORT'})) {
1156                         $errormessage = "$Lang::tr{'srcprt range overlaps'} $_[0]";
1157                 }
1158         }
1159
1160         if ($errormessage eq ''){
1161                 $_ = $_[1];
1162                 if (m/:/ && $prtrange2 == 1) { # if true then there is a port range
1163                         unless (&checkportoverlap($cgiparams{'DEST_PORT'},$_[1])) {
1164                                 $errormessage = "$Lang::tr{'destination port overlaps'} $_[1]";
1165                         }
1166                 }
1167                 if (m/:/ && $prtrange2 == 0 && $errormessage eq '') { # compare one port to a range
1168                         unless (&checkportinc($cgiparams{'DEST_PORT'}, $_[1])) {
1169                                 $errormessage = "$Lang::tr{'dstprt within existing'} $_[1]";
1170                         }
1171                 }
1172                 if (! m/:/ && $prtrange2 == 1 && $errormessage eq '') { # compare one port to a range
1173                         unless (&checkportinc($_[1], $cgiparams{'DEST_PORT'})) {
1174                                 $errormessage = "$Lang::tr{'dstprt range overlaps'} $_[1]";
1175                         }
1176                 }
1177         }
1178         return;
1179 }