]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - html/cgi-bin/portfw.cgi
Großes Update:
[ipfire-2.x.git] / html / cgi-bin / portfw.cgi
index bfa9e99e7118b1ade4ceb5da3deec2bcd986bec8..fcd77e5483093935000b067a53bfca0a6366139c 100644 (file)
-#!/usr/bin/perl\r
-#\r
-# SmoothWall CGIs\r
-#\r
-# This code is distributed under the terms of the GPL\r
-#\r
-# (c) The SmoothWall Team\r
-# Copyright (c) 2002/04/13 Steve Bootes - Add source IP support\r
-#\r
-# $Id: portfw.cgi,v 1.5.2.18 2005/05/02 16:19:49 eoberlander Exp $\r
-#\r
-#\r
-# Darren Critchley February 2003 - I added the multiple external access rules for each port forward\r
-# A couple of things to remember when reading the code\r
-#      There are two kinds of records in the config file, those with a number in the first field, and then 0,\r
-#              these are port forward rules, these records will have a 0 or 0.0.0.0 in position 9 (ORIG_IP)\r
-#              If there is a 0, it means that there are external access rules, otherwise the port is open to ALL.\r
-#      The second type of record is a number followed by a number which indicates that it is an external access\r
-#      rule. The first number indicates which Portfw rule it belongs to, and the second is just a unique key.\r
-#\r
-# Darren Critchley - March 5, 2003 - if you come along after me and work on this page, please comment your\r
-#              work. Put your name, and date and then your comment - it helps the person that comes along after you\r
-#              to figure out why and how things have changed, and it is considered good coding practice\r
-# Thanks . . . \r
-#\r
-\r
-use strict;\r
-\r
-# enable only the following on debugging purpose\r
-#use warnings;\r
-#use CGI::Carp 'fatalsToBrowser';\r
-\r
-require 'CONFIG_ROOT/general-functions.pl';\r
-require "${General::swroot}/lang.pl";\r
-require "${General::swroot}/header.pl";\r
-\r
-#workaround to suppress a warning when a variable is used only once\r
-my @dummy = ( ${Header::colouryellow} );\r
-undef (@dummy);\r
-\r
-my %cgiparams=();\r
-my %selected=();\r
-my %checked=();\r
-my $prtrange1=0;\r
-my $prtrange2=0;\r
-my $errormessage = '';\r
-my $filename = "${General::swroot}/portfw/config";\r
-my $aliasfile = "${General::swroot}/ethernet/aliases";\r
-\r
-&Header::showhttpheaders();\r
-\r
-$cgiparams{'ENABLED'} = 'off';\r
-$cgiparams{'KEY1'} = '0';\r
-$cgiparams{'KEY2'} = '0';\r
-$cgiparams{'PROTOCOL'} = '';\r
-$cgiparams{'SRC_PORT'} = '';\r
-$cgiparams{'DEST_IP'} = '';\r
-$cgiparams{'DEST_PORT'} = '';\r
-$cgiparams{'SRC_IP'} = '';\r
-$cgiparams{'ORIG_IP'} = '';\r
-$cgiparams{'REMARK'} = '';\r
-$cgiparams{'OVERRIDE'} = 'off';\r
-$cgiparams{'ACTION'} = '';\r
-\r
-&Header::getcgihash(\%cgiparams);\r
-\r
-my $disable_all = "0";\r
-my $enable_all = "0";\r
-\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'add'})\r
-{\r
-       &valaddupdate();\r
-       \r
-       # Darren Critchley - if there is an error, don't waste any more time processing\r
-       if ($errormessage) { goto ERROR; }\r
-       \r
-       open(FILE, $filename) or die 'Unable to open config file.';\r
-       my @current = <FILE>;\r
-       close(FILE);\r
-       my $key1 = 0; # used for finding last sequence number used \r
-       foreach my $line (@current)\r
-       {\r
-               my @temp = split(/\,/,$line);\r
-\r
-               chomp ($temp[8]);\r
-               if ($cgiparams{'KEY2'} eq "0"){ # if key2 is 0 then it is a portfw addition\r
-                       if ( $cgiparams{'SRC_PORT'} eq $temp[3] &&\r
-                               $cgiparams{'PROTOCOL'} eq $temp[2] &&\r
-                               $cgiparams{'SRC_IP'} eq $temp[7])\r
-                       {\r
-                                $errormessage =  \r
-                                       "$Lang::tr{'source port in use'} $cgiparams{'SRC_PORT'}";\r
-                       }\r
-                       # Check if key2 = 0, if it is then it is a port forward entry and we want the sequence number\r
-                       if ( $temp[1] eq "0") {\r
-                               $key1=$temp[0];\r
-                       }\r
-                       # Darren Critchley - Duplicate or overlapping Port range check\r
-                       if ($temp[1] eq "0" && \r
-                               $cgiparams{'PROTOCOL'} eq $temp[2] &&\r
-                               $cgiparams{'SRC_IP'} eq $temp[7] &&\r
-                               $errormessage eq '') \r
-                       {\r
-                               &portchecks($temp[3], $temp[5]);\r
-                       }\r
-               } else {\r
-                       if ( $cgiparams{'KEY1'} eq $temp[0] &&\r
-                               $cgiparams{'ORIG_IP'} eq $temp[8])\r
-                       {\r
-                                $errormessage =  \r
-                                       "$Lang::tr{'source ip in use'} $cgiparams{'ORIG_IP'}";\r
-                       }\r
-               }\r
-       }\r
-\r
-ERROR:\r
-       unless ($errormessage)\r
-       {\r
-               # Darren Critchley - we only want to store ranges with Colons\r
-               $cgiparams{'SRC_PORT'} =~ tr/-/:/; \r
-               $cgiparams{'DEST_PORT'} =~ tr/-/:/;\r
-\r
-               if ($cgiparams{'KEY1'} eq "0") { # 0 in KEY1 indicates it is a portfw add\r
-                       $key1++; # Add one to last sequence number\r
-                       open(FILE,">>$filename") or die 'Unable to open config file.';\r
-                       flock FILE, 2;\r
-                               if ($cgiparams{'ORIG_IP'} eq '0.0.0.0/0') {\r
-                                       # if the default/all is taken, then write it to the rule\r
-                                               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";\r
-                       } else { # else create an extra record so it shows up \r
-                                       print FILE "$key1,0,$cgiparams{'PROTOCOL'},$cgiparams{'SRC_PORT'},$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},$cgiparams{'SRC_IP'},0,$cgiparams{'REMARK'}\n";\r
-                                               print FILE "$key1,1,$cgiparams{'PROTOCOL'},0,$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},0,$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";\r
-                                       }                       \r
-                       close(FILE);\r
-                       undef %cgiparams;\r
-                       &General::log($Lang::tr{'forwarding rule added'});\r
-                       system('/usr/local/bin/setportfw');\r
-               } else { # else key1 eq 0\r
-                       my $insertpoint = ($cgiparams{'KEY2'} - 1);\r
-                       open(FILE, ">$filename") or die 'Unable to open config file.';\r
-                       flock FILE, 2;\r
-                       foreach my $line (@current) {\r
-                               chomp($line);\r
-                               my @temp = split(/\,/,$line);\r
-                               if ($cgiparams{'KEY1'} eq $temp[0] && $insertpoint eq $temp[1]) {\r
-                                       if ($temp[1] eq "0") { # this is the first xtaccess rule, therefore modify the portfw rule\r
-                                               $temp[8] = '0';\r
-                                       }\r
-                                       print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";\r
-                                       print FILE "$cgiparams{'KEY1'},$cgiparams{'KEY2'},$cgiparams{'PROTOCOL'},0,$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},0,$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";\r
-                               } else {\r
-                                       print FILE "$line\n";\r
-                               }\r
-                       }\r
-                       close(FILE);\r
-                       undef %cgiparams;\r
-                       &General::log($Lang::tr{'external access rule added'});\r
-                       system('/usr/local/bin/setportfw');\r
-               } # end if if KEY1 eq 0\r
-       } # end unless($errormessage)\r
-}\r
-\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'update'})\r
-{\r
-       &valaddupdate();\r
-       \r
-       # Darren Critchley - If there is an error don't waste any more processing time\r
-       if ($errormessage) { $cgiparams{'ACTION'} = $Lang::tr{'edit'}; goto UPD_ERROR; }\r
-\r
-       open(FILE, $filename) or die 'Unable to open config file.';\r
-       my @current = <FILE>;\r
-       close(FILE);\r
-       my $disabledpfw = '0';\r
-       my $lastpfw = '';\r
-       my $xtaccessdel = '0';\r
-       \r
-       foreach my $line (@current)\r
-       {\r
-               my @temp = split(/\,/,$line);\r
-               if ( $temp[1] eq "0" ) { # keep track of the last portfw and if it is enabled\r
-                       $disabledpfw = $temp[6];\r
-                       $lastpfw = $temp[0];\r
-               }               \r
-               chomp ($temp[8]);\r
-               if ( $cgiparams{'SRC_PORT'} eq $temp[3] &&\r
-                       $cgiparams{'PROTOCOL'} eq $temp[2] &&\r
-                       $cgiparams{'SRC_IP'} eq $temp[7])\r
-               {\r
-                        if ($cgiparams{'KEY1'} ne $temp[0] && $cgiparams{'KEY2'} eq "0")\r
-                        { \r
-                        $errormessage =  \r
-                               "$Lang::tr{'source port in use'} $cgiparams{'SRC_PORT'}";\r
-                        }\r
-               }\r
-               if ($cgiparams{'ORIG_IP'} eq $temp[8]) \r
-               {\r
-                        if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} ne $temp[1])\r
-                        # If we have the same source ip within a portfw group, then we have a problem!\r
-                        {\r
-                               $errormessage =  "$Lang::tr{'source ip in use'} $cgiparams{'ORIG_IP'}";\r
-                               $cgiparams{'ACTION'} = $Lang::tr{'edit'};\r
-                        }\r
-               }\r
-               \r
-               # Darren Critchley - Flag when a user disables an xtaccess\r
-               if ($cgiparams{'KEY1'} eq $temp[0] &&\r
-                               $cgiparams{'KEY2'} eq $temp[1] &&\r
-                               $cgiparams{'KEY2'} ne "0" && # if KEY2 is 0 then it is a portfw\r
-                               $cgiparams{'ENABLED'} eq "off" &&\r
-                               $temp[6] eq "on") { # we have determined that someone has turned an xtaccess off\r
-                       $xtaccessdel = "1";             \r
-               }\r
-               \r
-               # Darren Critchley - Portfw enabled, then enable xtaccess for all associated xtaccess records\r
-               if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'KEY2'} eq "0" && $cgiparams{'ENABLED'} ne $temp[6]) \r
-               {\r
-                       $enable_all = "1";\r
-               } else {\r
-                       $enable_all = "0";\r
-               }\r
-               # Darren Critchley - Portfw disabled, then disable xtaccess for all associated xtaccess records\r
-               if ($cgiparams{'ENABLED'} eq "off" && $cgiparams{'KEY2'} eq "0") \r
-               {\r
-                       $disable_all = "1";\r
-               } else {\r
-                       $disable_all = "0";\r
-               }\r
-\r
-               # Darren Critchley - if we are enabling an xtaccess, only allow if the associated Portfw is enabled\r
-               if ($cgiparams{'KEY1'} eq $lastpfw && $cgiparams{'KEY2'} ne "0") { # identifies an xtaccess record in the group\r
-                       if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'ENABLED'} ne $temp[6] ){ # a change has been made\r
-                               if ($disabledpfw eq "off")\r
-                               { \r
-                                       $errormessage =  "$Lang::tr{'cant enable xtaccess'}";\r
-                                       $cgiparams{'ACTION'} = $Lang::tr{'edit'};\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               # Darren Critchley - rule to stop someone from entering ALL into a external access rule, \r
-               # the portfw is the only place that ALL can be specified\r
-               if ($cgiparams{'KEY2'} ne "0" && $cgiparams{'ORIG_IP'} eq "0.0.0.0/0") {\r
-                       $errormessage =  "$Lang::tr{'xtaccess all error'}";\r
-                       $cgiparams{'ACTION'} = $Lang::tr{'edit'};\r
-               }\r
-               \r
-               # Darren Critchley - Duplicate or overlapping Port range check\r
-               if ($temp[1] eq "0" &&\r
-                       $cgiparams{'KEY1'} ne $temp[0] && \r
-                       $cgiparams{'PROTOCOL'} eq $temp[2] &&\r
-                       $cgiparams{'SRC_IP'} eq $temp[7] &&\r
-                       $errormessage eq '') \r
-               {\r
-                               &portchecks($temp[3], $temp[5]);\r
-               } # end port testing\r
-               \r
-       }\r
-       \r
-       # Darren Critchley - if an xtaccess was disabled, now we need to check to see if it was the only xtaccess\r
-       if($xtaccessdel eq "1") {\r
-               my $xctr = 0;\r
-               foreach my $line (@current)\r
-               {\r
-                       my @temp = split(/\,/,$line);\r
-                       if($temp[0] eq $cgiparams{'KEY1'} &&\r
-                               $temp[6] eq "on") { # we only want to count the enabled xtaccess's\r
-                               $xctr++;\r
-                       }\r
-               }\r
-               if ($xctr == 2){\r
-                       $disable_all = "1";\r
-               }\r
-       }\r
-\r
-UPD_ERROR:\r
-       unless ($errormessage)\r
-       {\r
-               # Darren Critchley - we only want to store ranges with Colons\r
-               $cgiparams{'SRC_PORT'} =~ tr/-/:/; \r
-               $cgiparams{'DEST_PORT'} =~ tr/-/:/;\r
-\r
-               open(FILE, ">$filename") or die 'Unable to open config file.';\r
-               flock FILE, 2;\r
-               foreach my $line (@current) {\r
-                       chomp($line);\r
-                       my @temp = split(/\,/,$line);\r
-                       if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1]) {\r
-               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";\r
-                       } else {\r
-                               # Darren Critchley - If it is a port forward record, then chances are good that a change was made to \r
-                               # Destination Ip or Port, and we need to update all the associated external access records\r
-                               if ($cgiparams{'KEY2'} eq "0" && $cgiparams{'KEY1'} eq $temp[0]) {\r
-                                       $temp[4] = $cgiparams{'DEST_IP'};\r
-                                       $temp[5] = $cgiparams{'DEST_PORT'};\r
-                                       $temp[2] = $cgiparams{'PROTOCOL'};\r
-                               }\r
-                               \r
-                               # Darren Critchley - If a Portfw has been disabled, then set all associated xtaccess as disabled\r
-                               if ( $disable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {\r
-                                       $temp[6] = 'off';\r
-                               }\r
-                               if ( $enable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {\r
-                                       $temp[6] = 'on';\r
-                               }\r
-                               # Darren Critchley - Deal with the override to allow ALL\r
-                               if ( $cgiparams{'OVERRIDE'} eq "on" && $temp[1] ne "0" && $cgiparams{'KEY1'} eq $temp[0] ) {\r
-                                       $temp[6] = 'off';\r
-                               }\r
-                       print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";\r
-                       }\r
-               }\r
-               close(FILE);\r
-               undef %cgiparams;\r
-               &General::log($Lang::tr{'forwarding rule updated'});\r
-               system('/usr/local/bin/setportfw');\r
-       } \r
-       if ($errormessage) {\r
-       $cgiparams{'ACTION'} = $Lang::tr{'edit'};\r
-       }\r
-}\r
-\r
-# Darren Critchley - Allows rules to be enabled and disabled\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'})\r
-{\r
-       open(FILE, $filename) or die 'Unable to open config file.';\r
-       my @current = <FILE>;\r
-       close(FILE);\r
-       my $disabledpfw = '0';\r
-       my $lastpfw = '';\r
-       my $xtaccessdel = '0';\r
-       \r
-       foreach my $line (@current)\r
-       {\r
-               my @temp = split(/\,/,$line);\r
-               if ( $temp[1] eq "0" ) { # keep track of the last portfw and if it is enabled\r
-                       $disabledpfw = $temp[6];\r
-                       $lastpfw = $temp[0];\r
-               }               \r
-               # Darren Critchley - Flag when a user disables an xtaccess\r
-               if ($cgiparams{'KEY1'} eq $temp[0] &&\r
-                               $cgiparams{'KEY2'} eq $temp[1] &&\r
-                               $cgiparams{'KEY2'} ne "0" && # if KEY2 is 0 then it is a portfw\r
-                               $cgiparams{'ENABLED'} eq "off" &&\r
-                               $temp[6] eq "on") { # we have determined that someone has turned an xtaccess off\r
-                       $xtaccessdel = "1";             \r
-               }\r
-               \r
-               # Darren Critchley - Portfw enabled, then enable xtaccess for all associated xtaccess records\r
-               if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'KEY2'} eq "0" && $cgiparams{'ENABLED'} ne $temp[6]) \r
-               {\r
-                       $enable_all = "1";\r
-               } else {\r
-                       $enable_all = "0";\r
-               }\r
-               # Darren Critchley - Portfw disabled, then disable xtaccess for all associated xtaccess records\r
-               if ($cgiparams{'ENABLED'} eq "off" && $cgiparams{'KEY2'} eq "0") \r
-               {\r
-                       $disable_all = "1";\r
-               } else {\r
-                       $disable_all = "0";\r
-               }\r
-\r
-               # Darren Critchley - if we are enabling an xtaccess, only allow if the associated Portfw is enabled\r
-               if ($cgiparams{'KEY1'} eq $lastpfw && $cgiparams{'KEY2'} ne "0") { # identifies an xtaccess record in the group\r
-                       if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'ENABLED'} ne $temp[6] ){ # a change has been made\r
-                               if ($disabledpfw eq "off")\r
-                               { \r
-                                       $errormessage =  "$Lang::tr{'cant enable xtaccess'}";\r
-                                       goto TOGGLEEXIT;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       # Darren Critchley - if an xtaccess was disabled, now we need to check to see if it was the only xtaccess\r
-       if($xtaccessdel eq "1") {\r
-               my $xctr = 0;\r
-               foreach my $line (@current)\r
-               {\r
-                       my @temp = split(/\,/,$line);\r
-                       if($temp[0] eq $cgiparams{'KEY1'} &&\r
-                               $temp[6] eq "on") { # we only want to count the enabled xtaccess's\r
-                               $xctr++;\r
-                       }\r
-               }\r
-               if ($xctr == 2){\r
-                       $disable_all = "1";\r
-               }\r
-       }\r
-\r
-       open(FILE, ">$filename") or die 'Unable to open config file.';\r
-       flock FILE, 2;\r
-       foreach my $line (@current) {\r
-               chomp($line);\r
-               my @temp = split(/\,/,$line);\r
-               if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1]) {\r
-               print FILE "$cgiparams{'KEY1'},$cgiparams{'KEY2'},$temp[2],$temp[3],$temp[4],$temp[5],$cgiparams{'ENABLED'},$temp[7],$temp[8],$temp[9]\n";\r
-               } else {\r
-                       # Darren Critchley - If a Portfw has been disabled, then set all associated xtaccess as disabled\r
-                       if ( $disable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {\r
-                               $temp[6] = 'off';\r
-                       }\r
-                       if ( $enable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {\r
-                               $temp[6] = 'on';\r
-                       }\r
-               print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";\r
-               }\r
-       }\r
-       close(FILE);\r
-       &General::log($Lang::tr{'forwarding rule updated'});\r
-       system('/usr/local/bin/setportfw');\r
-TOGGLEEXIT:\r
-       undef %cgiparams;\r
-} \r
-\r
-\r
-# Darren Critchley - broke out Edit routine from the delete routine - Edit routine now just puts values in fields\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'})\r
-{\r
-       open(FILE, "$filename") or die 'Unable to open config file.';\r
-       my @current = <FILE>;\r
-       close(FILE);\r
-\r
-       unless ($errormessage)\r
-       {\r
-               foreach my $line (@current)\r
-               {\r
-                       chomp($line);\r
-                       my @temp = split(/\,/,$line);\r
-                       if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) {\r
-                               $cgiparams{'PROTOCOL'} = $temp[2];\r
-                               $cgiparams{'SRC_PORT'} = $temp[3];\r
-                               $cgiparams{'DEST_IP'} = $temp[4];\r
-                               $cgiparams{'DEST_PORT'} = $temp[5];\r
-                               $cgiparams{'ENABLED'} = $temp[6];\r
-                               $cgiparams{'SRC_IP'} = $temp[7];\r
-                               $cgiparams{'ORIG_IP'} = $temp[8];\r
-                               $cgiparams{'REMARK'} = $temp[9];\r
-                       }\r
-                       \r
-               }\r
-       }\r
-}\r
-\r
-# Darren Critchley - broke out Remove routine as the logic is getting too complex to be combined with the Edit\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'remove'})\r
-{\r
-       open(FILE, "$filename") or die 'Unable to open config file.';\r
-       my @current = <FILE>;\r
-       close(FILE);\r
-       \r
-       # If the record being deleted is an xtaccess record, and it is the only one for a portfw record\r
-       # then we need to adjust the portfw record to be open to ALL ip addressess or an error will occur\r
-       # in setportfw.c\r
-       my $fixportfw = '0';\r
-       if ($cgiparams{'KEY2'} ne "0") {\r
-               my $counter = 0;\r
-               foreach my $line (@current)\r
-               {\r
-                       chomp($line);\r
-                       my @temp = split(/\,/,$line);\r
-                       if ($temp[0] eq $cgiparams{'KEY1'}) {\r
-                               $counter++;\r
-                       }\r
-               } \r
-               if ($counter eq 2) {\r
-                       $fixportfw = '1';\r
-               }\r
-       }\r
-       \r
-       unless ($errormessage)\r
-       {\r
-               open(FILE, ">$filename") or die 'Unable to open config file.';\r
-               flock FILE, 2;\r
-               my $linedeleted = 0;\r
-               foreach my $line (@current)\r
-               {\r
-                       chomp($line);\r
-                       my @temp = split(/\,/,$line);\r
-\r
-                       if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ||\r
-                               $cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq "0" ) \r
-                       {\r
-                               $linedeleted = 1;\r
-                       } else {\r
-                               if ($temp[0] eq $cgiparams{'KEY1'} && $temp[1] eq "0" && $fixportfw eq "1") {\r
-                                       $temp[8] = '0.0.0.0/0';\r
-                               }\r
-                       print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";\r
-#                              print FILE "$line\n";\r
-                       }\r
-               }\r
-               close(FILE);\r
-               if ($linedeleted == 1) {\r
-                       &General::log($Lang::tr{'forwarding rule removed'});\r
-                       undef %cgiparams;\r
-               }\r
-               system('/usr/local/bin/setportfw');\r
-       }\r
-}\r
-\r
-# Darren Critchley - Added routine to allow external access rules to be added\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'})\r
-{\r
-       open(FILE, $filename) or die 'Unable to open config file.';\r
-       my @current = <FILE>;\r
-       close(FILE);\r
-       my $key = 0; # used for finding last sequence number used \r
-       foreach my $line (@current)\r
-       {\r
-               my @temp = split(/\,/,$line);\r
-               if ($temp[0] eq $cgiparams{'KEY1'}) {\r
-                       $key = $temp[1]\r
-               }\r
-               if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) {\r
-                       $cgiparams{'PROTOCOL'} = $temp[2];\r
-                       $cgiparams{'SRC_PORT'} = $temp[3];\r
-                       $cgiparams{'DEST_IP'} = $temp[4];\r
-                       $cgiparams{'DEST_PORT'} = $temp[5];\r
-                       $cgiparams{'ENABLED'} = $temp[6];\r
-                       $cgiparams{'SRC_IP'} = $temp[7];\r
-                       $cgiparams{'ORIG_IP'} = '';\r
-                       $cgiparams{'REMARK'} = $temp[9];\r
-               }\r
-       }\r
-       $key++;\r
-       $cgiparams{'KEY2'} = $key;\r
-       # Until the ADD button is hit, there needs to be no change to portfw rules\r
-}\r
-\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'reset'})\r
-{\r
-       undef %cgiparams;\r
-}\r
-\r
-if ($cgiparams{'ACTION'} eq '')\r
-{\r
-       $cgiparams{'PROTOCOL'} = 'tcp';\r
-       $cgiparams{'ENABLED'} = 'on';\r
-       $cgiparams{'SRC_IP'} = '0.0.0.0';\r
-}\r
-\r
-$selected{'PROTOCOL'}{'udp'} = '';\r
-$selected{'PROTOCOL'}{'tcp'} = '';\r
-$selected{'PROTOCOL'}{'gre'} = '';\r
-$selected{'PROTOCOL'}{$cgiparams{'PROTOCOL'}} = "selected='selected'";\r
-\r
-$selected{'SRC_IP'}{$cgiparams{'SRC_IP'}} = "selected='selected'";\r
-\r
-$checked{'ENABLED'}{'off'} = '';\r
-$checked{'ENABLED'}{'on'} = '';  \r
-$checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'";\r
-\r
-&Header::openpage($Lang::tr{'port forwarding configuration'}, 1, '');\r
-\r
-&Header::openbigbox('100%', 'left', '', $errormessage);\r
-\r
-if ($errormessage) {\r
-       &Header::openbox('100%', 'left', $Lang::tr{'error messages'});\r
-       print "<class name='base'><font color='${Header::colourred}'>$errormessage\n</font>";\r
-       print "&nbsp;</class>\n";\r
-       &Header::closebox();\r
-}\r
-\r
-print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>\n";\r
-\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){\r
-       &Header::openbox('100%', 'left', $Lang::tr{'edit a rule'});\r
-} else {\r
-       &Header::openbox('100%', 'left', $Lang::tr{'add a new rule'});\r
-}\r
-\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'KEY2'} ne "0" || $cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}){ \r
-# if it is not a port forward record, don't validate as the fields are disabled\r
-       my $PROT = "\U$cgiparams{'PROTOCOL'}\E";\r
-       # Darren Critchley - Format the source and destination ports\r
-       my $dstprt = $cgiparams{'DEST_PORT'};\r
-       $dstprt =~ s/-/ - /;\r
-       $dstprt =~ s/:/ - /;\r
-\r
-print <<END\r
-<table>\r
-       <tr>\r
-               <td class='base'>$Lang::tr{'protocol'}: <b>$PROT</b></td>\r
-               <td width='20'>&nbsp;</td>\r
-               <td class='base' align='right'>$Lang::tr{'destination ip'}:&nbsp;</td>\r
-               <td><b>$cgiparams{'DEST_IP'}</b></td>\r
-               <td width='20'>&nbsp;</td>\r
-               <td class='base' align='right'>$Lang::tr{'destination port'}:&nbsp;</td>\r
-               <td><b>$dstprt</b></td>\r
-       </tr>\r
-</table>\r
-\r
-<input type='hidden' name='PROTOCOL' value='$cgiparams{'PROTOCOL'}' />\r
-<input type='hidden' name='SRC_IP' value='$cgiparams{'SRC_IP'}' />\r
-<input type='hidden' name='SRC_PORT' value='$cgiparams{'SRC_PORT'}' />\r
-<input type='hidden' name='DEST_IP' value='$cgiparams{'DEST_IP'}' />\r
-<input type='hidden' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' />\r
-END\r
-;\r
-} else {\r
-print <<END\r
-<table width='100%'>\r
-       <tr>\r
-               <td width='10%'>$Lang::tr{'protocol'}:&nbsp;</td>\r
-               <td width='15%'> \r
-               <select name='PROTOCOL'>\r
-                       <option value='tcp' $selected{'PROTOCOL'}{'tcp'}>TCP</option>\r
-                       <option value='udp' $selected{'PROTOCOL'}{'udp'}>UDP</option>\r
-                       <option value='gre' $selected{'PROTOCOL'}{'gre'}>GRE</option>\r
-               </select>\r
-               </td>\r
-               <td class='base' width='20%'><font color='${Header::colourred}'>$Lang::tr{'alias ip'}:</font></td>\r
-               <td>\r
-                       <select name='SRC_IP'>\r
-                       <option value='0.0.0.0' $selected{'SRC_IP'}{'0.0.0.0'}>DEFAULT IP</option>\r
-END\r
-;\r
-open(ALIASES, "$aliasfile") or die 'Unable to open aliases file.';\r
-while (<ALIASES>)\r
-{\r
-       chomp($_);\r
-       my @temp = split(/\,/,$_);\r
-       if ($temp[1] eq 'on') {\r
-               print "<option value='$temp[0]' $selected{'SRC_IP'}{$temp[0]}>$temp[0]";\r
-               if (defined $temp[2] and ($temp[2] ne '')) { print " ($temp[2])"; }\r
-               print "</option>\n";\r
-       }\r
-}\r
-close(ALIASES);\r
-print <<END\r
-                       </select>\r
-               </td>\r
-               <td class='base' width='20%'><font color='${Header::colourred}'>$Lang::tr{'source port'}:</font></td>\r
-               <td width='10%'><input type='text' name='SRC_PORT' value='$cgiparams{'SRC_PORT'}' size='8' /></td>\r
-       </tr>\r
-       <tr>\r
-               <td class='base'>&nbsp;</td>\r
-               <td>&nbsp;</td>\r
-               <td class='base'>$Lang::tr{'destination ip'}:</td>\r
-               <td><input type='text' name='DEST_IP' value='$cgiparams{'DEST_IP'}' size='15' /></td>\r
-               <td class='base'>$Lang::tr{'destination port'}:</td>\r
-               <td><input type='text' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' size='8' /></td>\r
-       </tr>\r
-</table>\r
-END\r
-;\r
-}\r
-\r
-print <<END\r
-<table>\r
-       <tr>\r
-               <td class='base'>$Lang::tr{'remark title'}&nbsp;<img src='/blob.gif' alt='*' />&nbsp;</td>\r
-               <td><input type='text' name='REMARK' value='$cgiparams{'REMARK'}' size='55' maxlength='50' /></td>\r
-END\r
-;\r
-unless ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'} && $cgiparams{'ENABLED'} eq "off") {\r
-       print "<td width='20'>&nbsp;</td>";\r
-       print "<td>$Lang::tr{'enabled'}&nbsp;</td><td><input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} /></td>\n";\r
-}\r
-print <<END\r
-       </tr>\r
-</table>\r
-END\r
-;\r
-\r
-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")){ \r
-# if it is a port forward rule with a 0 in the orig_port field, this means there are xtaccess records, and we\r
-# don't want to allow a person to change the orig_ip field as it will mess other logic up\r
-       print "<input type='hidden' name='ORIG_IP' value='$cgiparams{'ORIG_IP'}' />\n";\r
-} else {\r
-print <<END\r
-<table>\r
-       <tr>\r
-               <td class='base'><font class='boldbase' color='${Header::colourred}'>$Lang::tr{'source network'}</font>&nbsp;<img src='/blob.gif' alt='*' />&nbsp;</td>\r
-               <td><input type='text' name='ORIG_IP' value='$cgiparams{'ORIG_IP'}' size='15' /></td>\r
-       </tr>\r
-</table>\r
-END\r
-;\r
-}\r
-\r
-print <<END\r
-<table width='100%'>\r
-       <hr />\r
-       <tr>\r
-               <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>\r
-END\r
-;\r
-\r
-\r
-if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){\r
-       if($cgiparams{'KEY2'} eq "0"){\r
-               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";\r
-       } else {\r
-               print "<td width='40%'>&nbsp;</td>\n";\r
-       }\r
-       print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' />";\r
-       print "<input type='hidden' name='KEY1' value='$cgiparams{'KEY1'}' />";\r
-       print "<input type='hidden' name='KEY2' value='$cgiparams{'KEY2'}' /></TD>";\r
-       print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";\r
-       # on an edit and an xtaccess add, for some reason the "Reset" button stops working, so I make it a submit button\r
-} else {\r
-       print "<td width='30%'>&nbsp;</td>\n";\r
-       print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td>";\r
-       if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}) {\r
-               print "<td align='center' width='15%'><input type='hidden' name='KEY1' value='$cgiparams{'KEY1'}' />";\r
-               print "<input type='hidden' name='KEY2' value='$cgiparams{'KEY2'}' />";\r
-               print "<input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";\r
-       } elsif ($errormessage ne '') {\r
-               print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";\r
-       } else {\r
-               print "<td align='center' width='15%'><input type='reset' name='ACTION' value='$Lang::tr{'reset'}' /></td>";\r
-       }\r
-}\r
-print <<END\r
-       <td width='5%' align='right'>\r
-               <a href='${General::adminmanualurl}/section-firewall.html#section-port-forwarding' target='_blank'>\r
-               <img src='/images/web-support.png' alt='$Lang::tr{'online help en'}' title='$Lang::tr{'online help en'}' /></a></td>\r
-       </tr>\r
-</table>\r
-END\r
-;\r
-&Header::closebox();\r
-\r
-print "</form>\n";\r
-\r
-&Header::openbox('100%', 'left', $Lang::tr{'current rules'});\r
-print <<END\r
-<table width='100%'>\r
-<tr>\r
-<td width='7%' class='boldbase' align='center'><b>$Lang::tr{'proto'}</b></td>\r
-<td width='31%' class='boldbase' align='center'><b>$Lang::tr{'source'}</b></td>\r
-<td width='2%' class='boldbase' align='center'>&nbsp;</td>\r
-<td width='31%' class='boldbase' align='center'><b>$Lang::tr{'destination'}</b></td>\r
-<td width='24%' class='boldbase' align='center'><b>$Lang::tr{'remark'}</b></td>\r
-<td width='4%' class='boldbase' colspan='4' align='center'><b>$Lang::tr{'action'}</b></td>\r
-</tr>\r
-END\r
-;\r
-\r
-my $id = 0;\r
-my $xtaccesscolor = '#F6F4F4';\r
-open(RULES, "$filename") or die 'Unable to open config file.';\r
-while (<RULES>)\r
-{\r
-       my $protocol = '';\r
-       my $gif = '';\r
-       my $gdesc = '';\r
-       my $toggle = '';\r
-       chomp($_);\r
-       my @temp = split(/\,/,$_);\r
-       $temp[9] ='' unless defined $temp[9];# Glles ESpinasse : suppress warning on page init\r
-       if ($temp[2] eq 'udp') {\r
-               $protocol = 'UDP'; }\r
-       elsif ($temp[2] eq 'gre') {\r
-               $protocol = 'GRE' }\r
-       else {\r
-               $protocol = 'TCP' }\r
-       # Change bgcolor when a new portfw rule is added\r
-       if ($temp[1] eq "0"){\r
-               $id++;\r
-       }\r
-       # Darren Critchley highlight the row we are editing\r
-       if ( $cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) { \r
-               print "<tr bgcolor='${Header::colouryellow}'>\n";\r
-       } else {\r
-               if ($id % 2) {\r
-                       print "<tr bgcolor='${Header::table1colour}'>\n"; \r
-               }\r
-               else {\r
-                       print "<tr bgcolor='${Header::table2colour}'>\n";\r
-               }\r
-       }\r
-       \r
-       if ($temp[6] eq 'on') { $gif = 'on.gif'; $toggle='off'; $gdesc=$Lang::tr{'click to disable'};}\r
-               else { $gif = 'off.gif'; $toggle='on'; $gdesc=$Lang::tr{'click to enable'}; }\r
-\r
-               # Darren Critchley - this code no longer works - should we remove?\r
-       # catch for 'old-style' rules file - assume default ip if\r
-       # none exists\r
-       if (!&General::validip($temp[7]) || $temp[7] eq '0.0.0.0') {\r
-               $temp[7] = 'DEFAULT IP'; }\r
-               if ($temp[1] eq '0') { # Port forwarding entry\r
-\r
-               # Darren Critchley - Format the source and destintation ports\r
-               my $srcprt = $temp[3];\r
-               $srcprt =~ s/-/ - /;\r
-               $srcprt =~ s/:/ - /;\r
-               my $dstprt = $temp[5];\r
-               $dstprt =~ s/-/ - /;\r
-               $dstprt =~ s/:/ - /;\r
-\r
-               # Darren Critchley - Get Port Service Name if we can - code borrowed from firewalllog.dat\r
-               $_=$temp[3];\r
-               if (/^\d+$/) {\r
-                       my $servi = uc(getservbyport($temp[3], lc($temp[2])));\r
-                       if ($servi ne '' && $temp[3] < 1024) {\r
-                               $srcprt = "$srcprt($servi)"; }\r
-               }\r
-               $_=$temp[5];\r
-               if (/^\d+$/) {\r
-                       my $servi = uc(getservbyport($temp[5], lc($temp[2])));\r
-                       if ($servi ne '' && $temp[5] < 1024) {\r
-                               $dstprt = "$dstprt($servi)"; }\r
-               }\r
-\r
-               # Darren Critchley - If the line is too long, wrap the port numbers\r
-               my $srcaddr = "$temp[7] : $srcprt";\r
-               if (length($srcaddr) > 22) {\r
-                       $srcaddr = "$temp[7] :<br /> $srcprt";\r
-               }\r
-               my $dstaddr = "$temp[4] : $dstprt";\r
-               if (length($dstaddr) > 26) {\r
-                       $dstaddr = "$temp[4] :<br /> $dstprt";\r
-               }\r
-print <<END\r
-<td align='center'>$protocol</td>\r
-<td align='center'>$srcaddr</td>\r
-<td align='center'><img src='/images/forward.gif' alt='=&gt;' /></td>\r
-<td align='center'>$dstaddr</td>\r
-<td align='left'>&nbsp;$temp[9]</td>\r
-<td align='center'>\r
-       <form method='post' name='frm$temp[0]c' action='$ENV{'SCRIPT_NAME'}'>\r
-       <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />\r
-       <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />\r
-       <input type='hidden' name='KEY1' value='$temp[0]' />\r
-       <input type='hidden' name='KEY2' value='$temp[1]' />\r
-       <input type='hidden' name='ENABLED' value='$toggle' />\r
-       </form>\r
-</td>\r
-\r
-<td align='center'>\r
-       <form method='post' name='frm$temp[0]' action='$ENV{'SCRIPT_NAME'}'>\r
-       <input type='hidden' name='ACTION' value='$Lang::tr{'add xtaccess'}' />\r
-       <input type='image' name='$Lang::tr{'add xtaccess'}' src='/images/add.gif' alt='$Lang::tr{'add xtaccess'}' title='$Lang::tr{'add xtaccess'}' />\r
-       <input type='hidden' name='KEY1' value='$temp[0]' />\r
-       <input type='hidden' name='KEY2' value='$temp[1]' />\r
-       </form>\r
-</td>\r
-\r
-<td align='center'>\r
-       <form method='post' name='frm$temp[0]' action='$ENV{'SCRIPT_NAME'}'>\r
-       <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />\r
-       <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />\r
-       <input type='hidden' name='KEY1' value='$temp[0]' />\r
-       <input type='hidden' name='KEY2' value='$temp[1]' />\r
-       </form>\r
-</td>\r
-\r
-<td align='center'>\r
-       <form method='post' name='frm$temp[0]b' action='$ENV{'SCRIPT_NAME'}'>\r
-       <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />\r
-       <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />\r
-       <input type='hidden' name='KEY1' value='$temp[0]' />\r
-       <input type='hidden' name='KEY2' value='$temp[1]' />\r
-       </form>\r
-</td>\r
-\r
-</tr>\r
-END\r
-       ;\r
-       } else { # external access entry\r
-print <<END\r
-<td align='center'>&nbsp;</td>\r
-\r
-<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>\r
-\r
-<td align='center'>\r
-       <form method='post' name='frm$temp[0]$temp[1]t' action='$ENV{'SCRIPT_NAME'}'>\r
-       <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />\r
-       <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />\r
-       <input type='hidden' name='KEY1' value='$temp[0]' />\r
-       <input type='hidden' name='KEY2' value='$temp[1]' />\r
-       <input type='hidden' name='ENABLED' value='$toggle' />\r
-       </form>\r
-</td>\r
-\r
-<td align='center'>&nbsp;</td>\r
-\r
-<td align='center'>\r
-       <form method='post' name='frm$temp[0]$temp[1]' action='$ENV{'SCRIPT_NAME'}'>\r
-       <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />\r
-       <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />\r
-       <input type='hidden' name='KEY1' value='$temp[0]' />\r
-       <input type='hidden' name='KEY2' value='$temp[1]' />\r
-       </form>\r
-</td>\r
-\r
-<td align='center'>\r
-       <form method='post' name='frm$temp[0]b$temp[1]b' action='$ENV{'SCRIPT_NAME'}'>\r
-       <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />\r
-       <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />\r
-       <input type='hidden' name='KEY1' value='$temp[0]' />\r
-       <input type='hidden' name='KEY2' value='$temp[1]' />\r
-       </form>\r
-</td>\r
-\r
-</tr>\r
-END\r
-       ;\r
-       }\r
-}\r
-\r
-close(RULES);\r
-\r
-print "</table>";\r
-\r
-# If the fixed lease file contains entries, print Key to action icons\r
-if ( ! -z "$filename") {\r
-print <<END\r
-<table>\r
-<tr>\r
-       <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>\r
-       <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>\r
-       <td class='base'>$Lang::tr{'click to disable'}</td>\r
-       <td>&nbsp;&nbsp;</td>\r
-       <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>\r
-       <td class='base'>$Lang::tr{'click to enable'}</td>\r
-       <td>&nbsp;&nbsp;</td>\r
-       <td><img src='/images/add.gif' alt='$Lang::tr{'add xtaccess'}' /></td>\r
-       <td class='base'>$Lang::tr{'add xtaccess'}</td>\r
-       <td>&nbsp;&nbsp;</td>\r
-       <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>\r
-       <td class='base'>$Lang::tr{'edit'}</td>\r
-       <td>&nbsp;&nbsp;</td>\r
-       <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>\r
-       <td class='base'>$Lang::tr{'remove'}</td>\r
-</tr>\r
-</table>\r
-END\r
-;\r
-}\r
-\r
-&Header::closebox();\r
-\r
-&Header::closebigbox();\r
-\r
-&Header::closepage();\r
-\r
-# Validate Field Entries\r
-sub validateparams \r
-{\r
-       # Darren Critchley - Get rid of dashes in port ranges\r
-       $cgiparams{'DEST_PORT'}=~ tr/-/:/;\r
-       $cgiparams{'SRC_PORT'}=~ tr/-/:/;\r
-       \r
-       # Darren Critchley - code to substitue wildcards\r
-       if ($cgiparams{'SRC_PORT'} eq "*") {\r
-               $cgiparams{'SRC_PORT'} = "1:65535";\r
-       }\r
-       if ($cgiparams{'SRC_PORT'} =~ /^(\D)\:(\d+)$/) {\r
-               $cgiparams{'SRC_PORT'} = "1:$2";\r
-       }\r
-       if ($cgiparams{'SRC_PORT'} =~ /^(\d+)\:(\D)$/) {\r
-               $cgiparams{'SRC_PORT'} = "$1:65535";\r
-       }\r
-       if ($cgiparams{'DEST_PORT'} eq "*") {\r
-               $cgiparams{'DEST_PORT'} = "1:65535";\r
-       }\r
-       if ($cgiparams{'DEST_PORT'} =~ /^(\D)\:(\d+)$/) {\r
-               $cgiparams{'DEST_PORT'} = "1:$2";\r
-       }\r
-       if ($cgiparams{'DEST_PORT'} =~ /^(\d+)\:(\D)$/) {\r
-               $cgiparams{'DEST_PORT'} = "$1:65535";\r
-       }\r
-\r
-       # Darren Critchley - Add code for GRE protocol - we want to ignore ports, but we need a place holder\r
-       if ($cgiparams{'PROTOCOL'} eq 'gre') {\r
-               $cgiparams{'SRC_PORT'} = "GRE";\r
-               $cgiparams{'DEST_PORT'} = "GRE";\r
-       }\r
-\r
-       unless($cgiparams{'PROTOCOL'} =~ /^(tcp|udp|gre)$/) { $errormessage = $Lang::tr{'invalid input'}; }\r
-       # Darren Critchley - Changed how the error routine works a bit - for the validportrange check, we need to \r
-       # pass in src or dest to determine which side we are working with.\r
-       # the routine returns the complete error or ''\r
-       if ($cgiparams{'PROTOCOL'} ne 'gre') {\r
-               $errormessage = &General::validportrange($cgiparams{'SRC_PORT'}, 'src');\r
-       }\r
-       if( ($cgiparams{'ORIG_IP'} ne "0" && $cgiparams{'KEY2'} ne "0") || $cgiparams{'ACTION'} eq $Lang::tr{'add'}) { \r
-       # if it is a port forward record with 0 in orig_ip then ignore checking this field\r
-               unless(&General::validipormask($cgiparams{'ORIG_IP'}))\r
-               {\r
-                       if ($cgiparams{'ORIG_IP'} ne '') {\r
-                               $errormessage = $Lang::tr{'source ip bad'}; }\r
-                       else {\r
-                               $cgiparams{'ORIG_IP'} = '0.0.0.0/0'; }\r
-               }\r
-       }\r
-       # Darren Critchey - New rule that sets destination same as source if dest_port is blank.\r
-       if ($cgiparams{'DEST_PORT'} eq ''){\r
-               $cgiparams{'DEST_PORT'} = $cgiparams{'SRC_PORT'};\r
-       }\r
-       # Darren Critchey - Just in case error message is already set, this routine would wipe it out if\r
-       # we don't do a test here\r
-       if ($cgiparams{'PROTOCOL'} ne 'gre') {\r
-               unless($errormessage) {$errormessage = &General::validportrange($cgiparams{'DEST_PORT'}, 'dest');}\r
-       }\r
-       unless(&General::validip($cgiparams{'DEST_IP'})) { $errormessage = $Lang::tr{'destination ip bad'}; }\r
-       return;\r
-}\r
-\r
-# Darren Critchley - we want to make sure that a port range does not overlap another port range\r
-sub checkportoverlap\r
-{\r
-       my $portrange1 = $_[0]; # New port range\r
-       my $portrange2 = $_[1]; # existing port range\r
-       my @tempr1 = split(/\:/,$portrange1);\r
-       my @tempr2 = split(/\:/,$portrange2);\r
-\r
-       unless (&checkportinc($tempr1[0], $portrange2)){ return 0;}\r
-       unless (&checkportinc($tempr1[1], $portrange2)){ return 0;}\r
-       \r
-       unless (&checkportinc($tempr2[0], $portrange1)){ return 0;}\r
-       unless (&checkportinc($tempr2[1], $portrange1)){ return 0;}\r
-\r
-       return 1; # Everything checks out!\r
-}\r
-\r
-# Darren Critchley - we want to make sure that a port entry is not within an already existing range\r
-sub checkportinc\r
-{\r
-       my $port1 = $_[0]; # Port\r
-       my $portrange2 = $_[1]; # Port range\r
-       my @tempr1 = split(/\:/,$portrange2);\r
-\r
-       if ($port1 < $tempr1[0] || $port1 > $tempr1[1]) {\r
-               return 1; \r
-       } else {\r
-               return 0; \r
-       }\r
-}\r
-\r
-# Darren Critchley - certain ports are reserved for Ipcop \r
-# TCP 67,68,81,222,445\r
-# UDP 67,68\r
-# Params passed in -> port, rangeyn, protocol\r
-sub disallowreserved\r
-{\r
-       # port 67 and 68 same for tcp and udp, don't bother putting in an array\r
-       my $msg = "";\r
-       my @tcp_reserved = (81,222,445);\r
-       my $prt = $_[0]; # the port or range\r
-       my $ryn = $_[1]; # tells us whether or not it is a port range\r
-       my $prot = $_[2]; # protocol\r
-       my $srcdst = $_[3]; # source or destination\r
-       \r
-       if ($ryn) { # disect port range\r
-               if ($srcdst eq "src") {\r
-                       $msg = "$Lang::tr{'rsvd src port overlap'}";\r
-               } else {\r
-                       $msg = "$Lang::tr{'rsvd dst port overlap'}";\r
-               }\r
-               my @tmprng = split(/\:/,$prt);\r
-               unless (67 < $tmprng[0] || 67 > $tmprng[1]) { $errormessage="$msg 67"; return; }\r
-               unless (68 < $tmprng[0] || 68 > $tmprng[1]) { $errormessage="$msg 68"; return; }\r
-               if ($prot eq "tcp") {\r
-                       foreach my $prange (@tcp_reserved) {\r
-                               unless ($prange < $tmprng[0] || $prange > $tmprng[1]) { $errormessage="$msg $prange"; return; }\r
-                       }\r
-               }\r
-       } else {\r
-               if ($srcdst eq "src") {\r
-                       $msg = "$Lang::tr{'reserved src port'}";\r
-               } else {\r
-                       $msg = "$Lang::tr{'reserved dst port'}";\r
-               }\r
-               if ($prt == 67) { $errormessage="$msg 67"; return; }\r
-               if ($prt == 68) { $errormessage="$msg 68"; return; }\r
-               if ($prot eq "tcp") {\r
-                       foreach my $prange (@tcp_reserved) {\r
-                               if ($prange == $prt) { $errormessage="$msg $prange"; return; }\r
-                       }\r
-               }\r
-       }\r
-       return;\r
-}\r
-\r
-# Darren Critchley - Attempt to combine Add/Update validation as they are almost the same\r
-sub valaddupdate\r
-{\r
-       if ($cgiparams{'KEY2'} eq "0"){ # if it is a port forward rule, then validate properly\r
-               &validateparams();\r
-       } else { # it is an xtaccess rule, just check for a valid ip\r
-               unless(&General::validipormask($cgiparams{'ORIG_IP'}))\r
-               {\r
-                       if ($cgiparams{'ORIG_IP'} ne '') {\r
-                               $errormessage = $Lang::tr{'source ip bad'}; }\r
-                       else { # this rule stops someone from adding an ALL xtaccess record\r
-                               $errormessage = $Lang::tr{'xtaccess all error'}; \r
-                               $cgiparams{'ACTION'} = $Lang::tr{'add xtaccess'};\r
-                       }\r
-               }\r
-               # Darren Critchley - check for 0.0.0.0/0 - not allowed for xtaccess\r
-               if ($cgiparams{'ORIG_IP'} eq "0.0.0.0/0" || $cgiparams{'ORIG_IP'} eq "0.0.0.0") {\r
-                       $errormessage = $Lang::tr{'xtaccess all error'}; \r
-                       $cgiparams{'ACTION'} = $Lang::tr{'add xtaccess'};\r
-               }\r
-       }\r
-       # Darren Critchley - Remove commas from remarks\r
-       $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'});\r
-\r
-       # Darren Critchley - Check to see if we are working with port ranges\r
-       our ($prtrange1, $prtrange2);\r
-       $_ = $cgiparams{'SRC_PORT'};\r
-       if ($cgiparams{'KEY2'} eq "0" && m/:/){\r
-               $prtrange1 = 1;\r
-       }\r
-       if ($cgiparams{'SRC_IP'} eq '0.0.0.0') { # Dave Roberts - only check if using DEFAULT IP\r
-               if ($prtrange1 == 1){ # check for source ports reserved for Ipcop\r
-                       &disallowreserved($cgiparams{'SRC_PORT'},1,$cgiparams{'PROTOCOL'},"src");\r
-                       if ($errormessage) { goto EXITSUB; }\r
-               } else { # check for source port reserved for Ipcop\r
-                       &disallowreserved($cgiparams{'SRC_PORT'},0,$cgiparams{'PROTOCOL'},"src");\r
-                       if ($errormessage) { goto EXITSUB; }\r
-               }\r
-       }\r
-       \r
-       $_ = $cgiparams{'DEST_PORT'};\r
-       if ($cgiparams{'KEY2'} eq "0" && m/:/){\r
-               $prtrange2 = 1;\r
-       }\r
-       if ($cgiparams{'SRC_IP'} eq '0.0.0.0') { # Dave Roberts - only check if using DEFAULT IP\r
-               if ($prtrange2 == 1){ # check for destination ports reserved for IPCop\r
-                       &disallowreserved($cgiparams{'DEST_PORT'},1,$cgiparams{'PROTOCOL'},"dst");\r
-                       if ($errormessage) { goto EXITSUB; }\r
-               } else { # check for destination port reserved for IPCop\r
-                       &disallowreserved($cgiparams{'DEST_PORT'},0,$cgiparams{'PROTOCOL'},"dst");\r
-                       if ($errormessage) { goto EXITSUB; }\r
-               }\r
-       }\r
-       \r
-\r
-EXITSUB:\r
-       return;\r
-}\r
-\r
-# Darren Critchley - Duplicate or overlapping Port range check\r
-sub portchecks\r
-{\r
-       $_ = $_[0];\r
-       our ($prtrange1, $prtrange2);\r
-       if (m/:/ && $prtrange1 == 1) { # comparing two port ranges\r
-               unless (&checkportoverlap($cgiparams{'SRC_PORT'},$_[0])) {\r
-                       $errormessage = "$Lang::tr{'source port overlaps'} $_[0]";\r
-               }\r
-       }\r
-       if (m/:/ && $prtrange1 == 0 && $errormessage eq '') { # compare one port to a range\r
-               unless (&checkportinc($cgiparams{'SRC_PORT'}, $_[0])) {\r
-                       $errormessage = "$Lang::tr{'srcprt within existing'} $_[0]";\r
-               }\r
-       }\r
-       if (! m/:/ && $prtrange1 == 1 && $errormessage eq '') { # compare one port to a range\r
-               unless (&checkportinc($_[0], $cgiparams{'SRC_PORT'})) {\r
-                       $errormessage = "$Lang::tr{'srcprt range overlaps'} $_[0]";\r
-               }\r
-       }\r
-\r
-       if ($errormessage eq ''){\r
-               $_ = $_[1];\r
-               if (m/:/ && $prtrange2 == 1) { # if true then there is a port range\r
-                       unless (&checkportoverlap($cgiparams{'DEST_PORT'},$_[1])) {\r
-                               $errormessage = "$Lang::tr{'destination port overlaps'} $_[1]";\r
-                       }\r
-               }\r
-               if (m/:/ && $prtrange2 == 0 && $errormessage eq '') { # compare one port to a range\r
-                       unless (&checkportinc($cgiparams{'DEST_PORT'}, $_[1])) {\r
-                               $errormessage = "$Lang::tr{'dstprt within existing'} $_[1]";\r
-                       }\r
-               }\r
-               if (! m/:/ && $prtrange2 == 1 && $errormessage eq '') { # compare one port to a range\r
-                       unless (&checkportinc($_[1], $cgiparams{'DEST_PORT'})) {\r
-                               $errormessage = "$Lang::tr{'dstprt range overlaps'} $_[1]";\r
-                       }\r
-               }\r
-       }\r
-       return;\r
-}\r
+#!/usr/bin/perl
+#
+# SmoothWall CGIs
+#
+# This code is distributed under the terms of the GPL
+#
+# (c) The SmoothWall Team
+# Copyright (c) 2002/04/13 Steve Bootes - Add source IP support
+#
+# $Id: portfw.cgi,v 1.5.2.18 2005/05/02 16:19:49 eoberlander Exp $
+#
+#
+# Darren Critchley February 2003 - I added the multiple external access rules for each port forward
+# A couple of things to remember when reading the code
+#      There are two kinds of records in the config file, those with a number in the first field, and then 0,
+#              these are port forward rules, these records will have a 0 or 0.0.0.0 in position 9 (ORIG_IP)
+#              If there is a 0, it means that there are external access rules, otherwise the port is open to ALL.
+#      The second type of record is a number followed by a number which indicates that it is an external access
+#      rule. The first number indicates which Portfw rule it belongs to, and the second is just a unique key.
+#
+# Darren Critchley - March 5, 2003 - if you come along after me and work on this page, please comment your
+#              work. Put your name, and date and then your comment - it helps the person that comes along after you
+#              to figure out why and how things have changed, and it is considered good coding practice
+# Thanks . . . 
+#
+
+use strict;
+
+# enable only the following on debugging purpose
+#use warnings;
+#use CGI::Carp 'fatalsToBrowser';
+
+require 'CONFIG_ROOT/general-functions.pl';
+require "${General::swroot}/lang.pl";
+require "${General::swroot}/header.pl";
+
+#workaround to suppress a warning when a variable is used only once
+my @dummy = ( ${Header::colouryellow} );
+undef (@dummy);
+
+my %cgiparams=();
+my %selected=();
+my %checked=();
+my $prtrange1=0;
+my $prtrange2=0;
+my $errormessage = '';
+my $filename = "${General::swroot}/portfw/config";
+my $aliasfile = "${General::swroot}/ethernet/aliases";
+
+&Header::showhttpheaders();
+
+$cgiparams{'ENABLED'} = 'off';
+$cgiparams{'KEY1'} = '0';
+$cgiparams{'KEY2'} = '0';
+$cgiparams{'PROTOCOL'} = '';
+$cgiparams{'SRC_PORT'} = '';
+$cgiparams{'DEST_IP'} = '';
+$cgiparams{'DEST_PORT'} = '';
+$cgiparams{'SRC_IP'} = '';
+$cgiparams{'ORIG_IP'} = '';
+$cgiparams{'REMARK'} = '';
+$cgiparams{'OVERRIDE'} = 'off';
+$cgiparams{'ACTION'} = '';
+
+&Header::getcgihash(\%cgiparams);
+
+my $disable_all = "0";
+my $enable_all = "0";
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'add'})
+{
+       &valaddupdate();
+       
+       # Darren Critchley - if there is an error, don't waste any more time processing
+       if ($errormessage) { goto ERROR; }
+       
+       open(FILE, $filename) or die 'Unable to open config file.';
+       my @current = <FILE>;
+       close(FILE);
+       my $key1 = 0; # used for finding last sequence number used 
+       foreach my $line (@current)
+       {
+               my @temp = split(/\,/,$line);
+
+               chomp ($temp[8]);
+               if ($cgiparams{'KEY2'} eq "0"){ # if key2 is 0 then it is a portfw addition
+                       if ( $cgiparams{'SRC_PORT'} eq $temp[3] &&
+                               $cgiparams{'PROTOCOL'} eq $temp[2] &&
+                               $cgiparams{'SRC_IP'} eq $temp[7])
+                       {
+                                $errormessage =  
+                                       "$Lang::tr{'source port in use'} $cgiparams{'SRC_PORT'}";
+                       }
+                       # Check if key2 = 0, if it is then it is a port forward entry and we want the sequence number
+                       if ( $temp[1] eq "0") {
+                               $key1=$temp[0];
+                       }
+                       # Darren Critchley - Duplicate or overlapping Port range check
+                       if ($temp[1] eq "0" && 
+                               $cgiparams{'PROTOCOL'} eq $temp[2] &&
+                               $cgiparams{'SRC_IP'} eq $temp[7] &&
+                               $errormessage eq '') 
+                       {
+                               &portchecks($temp[3], $temp[5]);
+                       }
+               } else {
+                       if ( $cgiparams{'KEY1'} eq $temp[0] &&
+                               $cgiparams{'ORIG_IP'} eq $temp[8])
+                       {
+                                $errormessage =  
+                                       "$Lang::tr{'source ip in use'} $cgiparams{'ORIG_IP'}";
+                       }
+               }
+       }
+
+ERROR:
+       unless ($errormessage)
+       {
+               # Darren Critchley - we only want to store ranges with Colons
+               $cgiparams{'SRC_PORT'} =~ tr/-/:/; 
+               $cgiparams{'DEST_PORT'} =~ tr/-/:/;
+
+               if ($cgiparams{'KEY1'} eq "0") { # 0 in KEY1 indicates it is a portfw add
+                       $key1++; # Add one to last sequence number
+                       open(FILE,">>$filename") or die 'Unable to open config file.';
+                       flock FILE, 2;
+                               if ($cgiparams{'ORIG_IP'} eq '0.0.0.0/0') {
+                                       # if the default/all is taken, then write it to the rule
+                                               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";
+                       } else { # else create an extra record so it shows up 
+                                       print FILE "$key1,0,$cgiparams{'PROTOCOL'},$cgiparams{'SRC_PORT'},$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},$cgiparams{'SRC_IP'},0,$cgiparams{'REMARK'}\n";
+                                               print FILE "$key1,1,$cgiparams{'PROTOCOL'},0,$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},0,$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";
+                                       }                       
+                       close(FILE);
+                       undef %cgiparams;
+                       &General::log($Lang::tr{'forwarding rule added'});
+                       system('/usr/local/bin/setportfw');
+               } else { # else key1 eq 0
+                       my $insertpoint = ($cgiparams{'KEY2'} - 1);
+                       open(FILE, ">$filename") or die 'Unable to open config file.';
+                       flock FILE, 2;
+                       foreach my $line (@current) {
+                               chomp($line);
+                               my @temp = split(/\,/,$line);
+                               if ($cgiparams{'KEY1'} eq $temp[0] && $insertpoint eq $temp[1]) {
+                                       if ($temp[1] eq "0") { # this is the first xtaccess rule, therefore modify the portfw rule
+                                               $temp[8] = '0';
+                                       }
+                                       print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
+                                       print FILE "$cgiparams{'KEY1'},$cgiparams{'KEY2'},$cgiparams{'PROTOCOL'},0,$cgiparams{'DEST_IP'},$cgiparams{'DEST_PORT'},$cgiparams{'ENABLED'},0,$cgiparams{'ORIG_IP'},$cgiparams{'REMARK'}\n";
+                               } else {
+                                       print FILE "$line\n";
+                               }
+                       }
+                       close(FILE);
+                       undef %cgiparams;
+                       &General::log($Lang::tr{'external access rule added'});
+                       system('/usr/local/bin/setportfw');
+               } # end if if KEY1 eq 0
+       } # end unless($errormessage)
+}
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'update'})
+{
+       &valaddupdate();
+       
+       # Darren Critchley - If there is an error don't waste any more processing time
+       if ($errormessage) { $cgiparams{'ACTION'} = $Lang::tr{'edit'}; goto UPD_ERROR; }
+
+       open(FILE, $filename) or die 'Unable to open config file.';
+       my @current = <FILE>;
+       close(FILE);
+       my $disabledpfw = '0';
+       my $lastpfw = '';
+       my $xtaccessdel = '0';
+       
+       foreach my $line (@current)
+       {
+               my @temp = split(/\,/,$line);
+               if ( $temp[1] eq "0" ) { # keep track of the last portfw and if it is enabled
+                       $disabledpfw = $temp[6];
+                       $lastpfw = $temp[0];
+               }               
+               chomp ($temp[8]);
+               if ( $cgiparams{'SRC_PORT'} eq $temp[3] &&
+                       $cgiparams{'PROTOCOL'} eq $temp[2] &&
+                       $cgiparams{'SRC_IP'} eq $temp[7])
+               {
+                        if ($cgiparams{'KEY1'} ne $temp[0] && $cgiparams{'KEY2'} eq "0")
+                        { 
+                        $errormessage =  
+                               "$Lang::tr{'source port in use'} $cgiparams{'SRC_PORT'}";
+                        }
+               }
+               if ($cgiparams{'ORIG_IP'} eq $temp[8]) 
+               {
+                        if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} ne $temp[1])
+                        # If we have the same source ip within a portfw group, then we have a problem!
+                        {
+                               $errormessage =  "$Lang::tr{'source ip in use'} $cgiparams{'ORIG_IP'}";
+                               $cgiparams{'ACTION'} = $Lang::tr{'edit'};
+                        }
+               }
+               
+               # Darren Critchley - Flag when a user disables an xtaccess
+               if ($cgiparams{'KEY1'} eq $temp[0] &&
+                               $cgiparams{'KEY2'} eq $temp[1] &&
+                               $cgiparams{'KEY2'} ne "0" && # if KEY2 is 0 then it is a portfw
+                               $cgiparams{'ENABLED'} eq "off" &&
+                               $temp[6] eq "on") { # we have determined that someone has turned an xtaccess off
+                       $xtaccessdel = "1";             
+               }
+               
+               # Darren Critchley - Portfw enabled, then enable xtaccess for all associated xtaccess records
+               if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'KEY2'} eq "0" && $cgiparams{'ENABLED'} ne $temp[6]) 
+               {
+                       $enable_all = "1";
+               } else {
+                       $enable_all = "0";
+               }
+               # Darren Critchley - Portfw disabled, then disable xtaccess for all associated xtaccess records
+               if ($cgiparams{'ENABLED'} eq "off" && $cgiparams{'KEY2'} eq "0") 
+               {
+                       $disable_all = "1";
+               } else {
+                       $disable_all = "0";
+               }
+
+               # Darren Critchley - if we are enabling an xtaccess, only allow if the associated Portfw is enabled
+               if ($cgiparams{'KEY1'} eq $lastpfw && $cgiparams{'KEY2'} ne "0") { # identifies an xtaccess record in the group
+                       if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'ENABLED'} ne $temp[6] ){ # a change has been made
+                               if ($disabledpfw eq "off")
+                               { 
+                                       $errormessage =  "$Lang::tr{'cant enable xtaccess'}";
+                                       $cgiparams{'ACTION'} = $Lang::tr{'edit'};
+                               }
+                       }
+               }
+               
+               # Darren Critchley - rule to stop someone from entering ALL into a external access rule, 
+               # the portfw is the only place that ALL can be specified
+               if ($cgiparams{'KEY2'} ne "0" && $cgiparams{'ORIG_IP'} eq "0.0.0.0/0") {
+                       $errormessage =  "$Lang::tr{'xtaccess all error'}";
+                       $cgiparams{'ACTION'} = $Lang::tr{'edit'};
+               }
+               
+               # Darren Critchley - Duplicate or overlapping Port range check
+               if ($temp[1] eq "0" &&
+                       $cgiparams{'KEY1'} ne $temp[0] && 
+                       $cgiparams{'PROTOCOL'} eq $temp[2] &&
+                       $cgiparams{'SRC_IP'} eq $temp[7] &&
+                       $errormessage eq '') 
+               {
+                               &portchecks($temp[3], $temp[5]);
+               } # end port testing
+               
+       }
+       
+       # Darren Critchley - if an xtaccess was disabled, now we need to check to see if it was the only xtaccess
+       if($xtaccessdel eq "1") {
+               my $xctr = 0;
+               foreach my $line (@current)
+               {
+                       my @temp = split(/\,/,$line);
+                       if($temp[0] eq $cgiparams{'KEY1'} &&
+                               $temp[6] eq "on") { # we only want to count the enabled xtaccess's
+                               $xctr++;
+                       }
+               }
+               if ($xctr == 2){
+                       $disable_all = "1";
+               }
+       }
+
+UPD_ERROR:
+       unless ($errormessage)
+       {
+               # Darren Critchley - we only want to store ranges with Colons
+               $cgiparams{'SRC_PORT'} =~ tr/-/:/; 
+               $cgiparams{'DEST_PORT'} =~ tr/-/:/;
+
+               open(FILE, ">$filename") or die 'Unable to open config file.';
+               flock FILE, 2;
+               foreach my $line (@current) {
+                       chomp($line);
+                       my @temp = split(/\,/,$line);
+                       if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1]) {
+               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";
+                       } else {
+                               # Darren Critchley - If it is a port forward record, then chances are good that a change was made to 
+                               # Destination Ip or Port, and we need to update all the associated external access records
+                               if ($cgiparams{'KEY2'} eq "0" && $cgiparams{'KEY1'} eq $temp[0]) {
+                                       $temp[4] = $cgiparams{'DEST_IP'};
+                                       $temp[5] = $cgiparams{'DEST_PORT'};
+                                       $temp[2] = $cgiparams{'PROTOCOL'};
+                               }
+                               
+                               # Darren Critchley - If a Portfw has been disabled, then set all associated xtaccess as disabled
+                               if ( $disable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
+                                       $temp[6] = 'off';
+                               }
+                               if ( $enable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
+                                       $temp[6] = 'on';
+                               }
+                               # Darren Critchley - Deal with the override to allow ALL
+                               if ( $cgiparams{'OVERRIDE'} eq "on" && $temp[1] ne "0" && $cgiparams{'KEY1'} eq $temp[0] ) {
+                                       $temp[6] = 'off';
+                               }
+                       print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
+                       }
+               }
+               close(FILE);
+               undef %cgiparams;
+               &General::log($Lang::tr{'forwarding rule updated'});
+               system('/usr/local/bin/setportfw');
+       } 
+       if ($errormessage) {
+       $cgiparams{'ACTION'} = $Lang::tr{'edit'};
+       }
+}
+
+# Darren Critchley - Allows rules to be enabled and disabled
+if ($cgiparams{'ACTION'} eq $Lang::tr{'toggle enable disable'})
+{
+       open(FILE, $filename) or die 'Unable to open config file.';
+       my @current = <FILE>;
+       close(FILE);
+       my $disabledpfw = '0';
+       my $lastpfw = '';
+       my $xtaccessdel = '0';
+       
+       foreach my $line (@current)
+       {
+               my @temp = split(/\,/,$line);
+               if ( $temp[1] eq "0" ) { # keep track of the last portfw and if it is enabled
+                       $disabledpfw = $temp[6];
+                       $lastpfw = $temp[0];
+               }               
+               # Darren Critchley - Flag when a user disables an xtaccess
+               if ($cgiparams{'KEY1'} eq $temp[0] &&
+                               $cgiparams{'KEY2'} eq $temp[1] &&
+                               $cgiparams{'KEY2'} ne "0" && # if KEY2 is 0 then it is a portfw
+                               $cgiparams{'ENABLED'} eq "off" &&
+                               $temp[6] eq "on") { # we have determined that someone has turned an xtaccess off
+                       $xtaccessdel = "1";             
+               }
+               
+               # Darren Critchley - Portfw enabled, then enable xtaccess for all associated xtaccess records
+               if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'KEY2'} eq "0" && $cgiparams{'ENABLED'} ne $temp[6]) 
+               {
+                       $enable_all = "1";
+               } else {
+                       $enable_all = "0";
+               }
+               # Darren Critchley - Portfw disabled, then disable xtaccess for all associated xtaccess records
+               if ($cgiparams{'ENABLED'} eq "off" && $cgiparams{'KEY2'} eq "0") 
+               {
+                       $disable_all = "1";
+               } else {
+                       $disable_all = "0";
+               }
+
+               # Darren Critchley - if we are enabling an xtaccess, only allow if the associated Portfw is enabled
+               if ($cgiparams{'KEY1'} eq $lastpfw && $cgiparams{'KEY2'} ne "0") { # identifies an xtaccess record in the group
+                       if ($cgiparams{'ENABLED'} eq "on" && $cgiparams{'ENABLED'} ne $temp[6] ){ # a change has been made
+                               if ($disabledpfw eq "off")
+                               { 
+                                       $errormessage =  "$Lang::tr{'cant enable xtaccess'}";
+                                       goto TOGGLEEXIT;
+                               }
+                       }
+               }
+       }
+       
+       # Darren Critchley - if an xtaccess was disabled, now we need to check to see if it was the only xtaccess
+       if($xtaccessdel eq "1") {
+               my $xctr = 0;
+               foreach my $line (@current)
+               {
+                       my @temp = split(/\,/,$line);
+                       if($temp[0] eq $cgiparams{'KEY1'} &&
+                               $temp[6] eq "on") { # we only want to count the enabled xtaccess's
+                               $xctr++;
+                       }
+               }
+               if ($xctr == 2){
+                       $disable_all = "1";
+               }
+       }
+
+       open(FILE, ">$filename") or die 'Unable to open config file.';
+       flock FILE, 2;
+       foreach my $line (@current) {
+               chomp($line);
+               my @temp = split(/\,/,$line);
+               if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1]) {
+               print FILE "$cgiparams{'KEY1'},$cgiparams{'KEY2'},$temp[2],$temp[3],$temp[4],$temp[5],$cgiparams{'ENABLED'},$temp[7],$temp[8],$temp[9]\n";
+               } else {
+                       # Darren Critchley - If a Portfw has been disabled, then set all associated xtaccess as disabled
+                       if ( $disable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
+                               $temp[6] = 'off';
+                       }
+                       if ( $enable_all eq "1" && $cgiparams{'KEY1'} eq $temp[0] ) {
+                               $temp[6] = 'on';
+                       }
+               print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
+               }
+       }
+       close(FILE);
+       &General::log($Lang::tr{'forwarding rule updated'});
+       system('/usr/local/bin/setportfw');
+TOGGLEEXIT:
+       undef %cgiparams;
+} 
+
+
+# Darren Critchley - broke out Edit routine from the delete routine - Edit routine now just puts values in fields
+if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'})
+{
+       open(FILE, "$filename") or die 'Unable to open config file.';
+       my @current = <FILE>;
+       close(FILE);
+
+       unless ($errormessage)
+       {
+               foreach my $line (@current)
+               {
+                       chomp($line);
+                       my @temp = split(/\,/,$line);
+                       if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) {
+                               $cgiparams{'PROTOCOL'} = $temp[2];
+                               $cgiparams{'SRC_PORT'} = $temp[3];
+                               $cgiparams{'DEST_IP'} = $temp[4];
+                               $cgiparams{'DEST_PORT'} = $temp[5];
+                               $cgiparams{'ENABLED'} = $temp[6];
+                               $cgiparams{'SRC_IP'} = $temp[7];
+                               $cgiparams{'ORIG_IP'} = $temp[8];
+                               $cgiparams{'REMARK'} = $temp[9];
+                       }
+                       
+               }
+       }
+}
+
+# Darren Critchley - broke out Remove routine as the logic is getting too complex to be combined with the Edit
+if ($cgiparams{'ACTION'} eq $Lang::tr{'remove'})
+{
+       open(FILE, "$filename") or die 'Unable to open config file.';
+       my @current = <FILE>;
+       close(FILE);
+       
+       # If the record being deleted is an xtaccess record, and it is the only one for a portfw record
+       # then we need to adjust the portfw record to be open to ALL ip addressess or an error will occur
+       # in setportfw.c
+       my $fixportfw = '0';
+       if ($cgiparams{'KEY2'} ne "0") {
+               my $counter = 0;
+               foreach my $line (@current)
+               {
+                       chomp($line);
+                       my @temp = split(/\,/,$line);
+                       if ($temp[0] eq $cgiparams{'KEY1'}) {
+                               $counter++;
+                       }
+               } 
+               if ($counter eq 2) {
+                       $fixportfw = '1';
+               }
+       }
+       
+       unless ($errormessage)
+       {
+               open(FILE, ">$filename") or die 'Unable to open config file.';
+               flock FILE, 2;
+               my $linedeleted = 0;
+               foreach my $line (@current)
+               {
+                       chomp($line);
+                       my @temp = split(/\,/,$line);
+
+                       if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ||
+                               $cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq "0" ) 
+                       {
+                               $linedeleted = 1;
+                       } else {
+                               if ($temp[0] eq $cgiparams{'KEY1'} && $temp[1] eq "0" && $fixportfw eq "1") {
+                                       $temp[8] = '0.0.0.0/0';
+                               }
+                       print FILE "$temp[0],$temp[1],$temp[2],$temp[3],$temp[4],$temp[5],$temp[6],$temp[7],$temp[8],$temp[9]\n";
+#                              print FILE "$line\n";
+                       }
+               }
+               close(FILE);
+               if ($linedeleted == 1) {
+                       &General::log($Lang::tr{'forwarding rule removed'});
+                       undef %cgiparams;
+               }
+               system('/usr/local/bin/setportfw');
+       }
+}
+
+# Darren Critchley - Added routine to allow external access rules to be added
+if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'})
+{
+       open(FILE, $filename) or die 'Unable to open config file.';
+       my @current = <FILE>;
+       close(FILE);
+       my $key = 0; # used for finding last sequence number used 
+       foreach my $line (@current)
+       {
+               my @temp = split(/\,/,$line);
+               if ($temp[0] eq $cgiparams{'KEY1'}) {
+                       $key = $temp[1]
+               }
+               if ($cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) {
+                       $cgiparams{'PROTOCOL'} = $temp[2];
+                       $cgiparams{'SRC_PORT'} = $temp[3];
+                       $cgiparams{'DEST_IP'} = $temp[4];
+                       $cgiparams{'DEST_PORT'} = $temp[5];
+                       $cgiparams{'ENABLED'} = $temp[6];
+                       $cgiparams{'SRC_IP'} = $temp[7];
+                       $cgiparams{'ORIG_IP'} = '';
+                       $cgiparams{'REMARK'} = $temp[9];
+               }
+       }
+       $key++;
+       $cgiparams{'KEY2'} = $key;
+       # Until the ADD button is hit, there needs to be no change to portfw rules
+}
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'reset'})
+{
+       undef %cgiparams;
+}
+
+if ($cgiparams{'ACTION'} eq '')
+{
+       $cgiparams{'PROTOCOL'} = 'tcp';
+       $cgiparams{'ENABLED'} = 'on';
+       $cgiparams{'SRC_IP'} = '0.0.0.0';
+}
+
+$selected{'PROTOCOL'}{'udp'} = '';
+$selected{'PROTOCOL'}{'tcp'} = '';
+$selected{'PROTOCOL'}{'gre'} = '';
+$selected{'PROTOCOL'}{$cgiparams{'PROTOCOL'}} = "selected='selected'";
+
+$selected{'SRC_IP'}{$cgiparams{'SRC_IP'}} = "selected='selected'";
+
+$checked{'ENABLED'}{'off'} = '';
+$checked{'ENABLED'}{'on'} = '';  
+$checked{'ENABLED'}{$cgiparams{'ENABLED'}} = "checked='checked'";
+
+&Header::openpage($Lang::tr{'port forwarding configuration'}, 1, '');
+
+&Header::openbigbox('100%', 'left', '', $errormessage);
+
+if ($errormessage) {
+       &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
+       print "<class name='base'><font color='${Header::colourred}'>$errormessage\n</font>";
+       print "&nbsp;</class>\n";
+       &Header::closebox();
+}
+
+print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>\n";
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){
+       &Header::openbox('100%', 'left', $Lang::tr{'edit a rule'});
+} else {
+       &Header::openbox('100%', 'left', $Lang::tr{'add a new rule'});
+}
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'KEY2'} ne "0" || $cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}){ 
+# if it is not a port forward record, don't validate as the fields are disabled
+       my $PROT = "\U$cgiparams{'PROTOCOL'}\E";
+       # Darren Critchley - Format the source and destination ports
+       my $dstprt = $cgiparams{'DEST_PORT'};
+       $dstprt =~ s/-/ - /;
+       $dstprt =~ s/:/ - /;
+
+print <<END
+<table>
+       <tr>
+               <td class='base'>$Lang::tr{'protocol'}: <b>$PROT</b></td>
+               <td width='20'>&nbsp;</td>
+               <td class='base' align='right'>$Lang::tr{'destination ip'}:&nbsp;</td>
+               <td><b>$cgiparams{'DEST_IP'}</b></td>
+               <td width='20'>&nbsp;</td>
+               <td class='base' align='right'>$Lang::tr{'destination port'}:&nbsp;</td>
+               <td><b>$dstprt</b></td>
+       </tr>
+</table>
+
+<input type='hidden' name='PROTOCOL' value='$cgiparams{'PROTOCOL'}' />
+<input type='hidden' name='SRC_IP' value='$cgiparams{'SRC_IP'}' />
+<input type='hidden' name='SRC_PORT' value='$cgiparams{'SRC_PORT'}' />
+<input type='hidden' name='DEST_IP' value='$cgiparams{'DEST_IP'}' />
+<input type='hidden' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' />
+END
+;
+} else {
+print <<END
+<table width='100%'>
+       <tr>
+               <td width='10%'>$Lang::tr{'protocol'}:&nbsp;</td>
+               <td width='15%'> 
+               <select name='PROTOCOL'>
+                       <option value='tcp' $selected{'PROTOCOL'}{'tcp'}>TCP</option>
+                       <option value='udp' $selected{'PROTOCOL'}{'udp'}>UDP</option>
+                       <option value='gre' $selected{'PROTOCOL'}{'gre'}>GRE</option>
+               </select>
+               </td>
+               <td class='base' width='20%'><font color='${Header::colourred}'>$Lang::tr{'alias ip'}:</font></td>
+               <td>
+                       <select name='SRC_IP'>
+                       <option value='0.0.0.0' $selected{'SRC_IP'}{'0.0.0.0'}>DEFAULT IP</option>
+END
+;
+open(ALIASES, "$aliasfile") or die 'Unable to open aliases file.';
+while (<ALIASES>)
+{
+       chomp($_);
+       my @temp = split(/\,/,$_);
+       if ($temp[1] eq 'on') {
+               print "<option value='$temp[0]' $selected{'SRC_IP'}{$temp[0]}>$temp[0]";
+               if (defined $temp[2] and ($temp[2] ne '')) { print " ($temp[2])"; }
+               print "</option>\n";
+       }
+}
+close(ALIASES);
+print <<END
+                       </select>
+               </td>
+               <td class='base' width='20%'><font color='${Header::colourred}'>$Lang::tr{'source port'}:</font></td>
+               <td width='10%'><input type='text' name='SRC_PORT' value='$cgiparams{'SRC_PORT'}' size='8' /></td>
+       </tr>
+       <tr>
+               <td class='base'>&nbsp;</td>
+               <td>&nbsp;</td>
+               <td class='base'>$Lang::tr{'destination ip'}:</td>
+               <td><input type='text' name='DEST_IP' value='$cgiparams{'DEST_IP'}' size='15' /></td>
+               <td class='base'>$Lang::tr{'destination port'}:</td>
+               <td><input type='text' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' size='8' /></td>
+       </tr>
+</table>
+END
+;
+}
+
+print <<END
+<table>
+       <tr>
+               <td class='base'>$Lang::tr{'remark title'}&nbsp;<img src='/blob.gif' alt='*' />&nbsp;</td>
+               <td><input type='text' name='REMARK' value='$cgiparams{'REMARK'}' size='55' maxlength='50' /></td>
+END
+;
+unless ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'} && $cgiparams{'ENABLED'} eq "off") {
+       print "<td width='20'>&nbsp;</td>";
+       print "<td>$Lang::tr{'enabled'}&nbsp;</td><td><input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} /></td>\n";
+}
+print <<END
+       </tr>
+</table>
+END
+;
+
+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")){ 
+# if it is a port forward rule with a 0 in the orig_port field, this means there are xtaccess records, and we
+# don't want to allow a person to change the orig_ip field as it will mess other logic up
+       print "<input type='hidden' name='ORIG_IP' value='$cgiparams{'ORIG_IP'}' />\n";
+} else {
+print <<END
+<table>
+       <tr>
+               <td class='base'><font class='boldbase' color='${Header::colourred}'>$Lang::tr{'source network'}</font>&nbsp;<img src='/blob.gif' alt='*' />&nbsp;</td>
+               <td><input type='text' name='ORIG_IP' value='$cgiparams{'ORIG_IP'}' size='15' /></td>
+       </tr>
+</table>
+END
+;
+}
+
+print <<END
+<table width='100%'>
+       <hr />
+       <tr>
+               <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>
+END
+;
+
+
+if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){
+       if($cgiparams{'KEY2'} eq "0"){
+               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";
+       } else {
+               print "<td width='40%'>&nbsp;</td>\n";
+       }
+       print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'update'}' />";
+       print "<input type='hidden' name='KEY1' value='$cgiparams{'KEY1'}' />";
+       print "<input type='hidden' name='KEY2' value='$cgiparams{'KEY2'}' /></TD>";
+       print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
+       # on an edit and an xtaccess add, for some reason the "Reset" button stops working, so I make it a submit button
+} else {
+       print "<td width='30%'>&nbsp;</td>\n";
+       print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td>";
+       if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}) {
+               print "<td align='center' width='15%'><input type='hidden' name='KEY1' value='$cgiparams{'KEY1'}' />";
+               print "<input type='hidden' name='KEY2' value='$cgiparams{'KEY2'}' />";
+               print "<input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
+       } elsif ($errormessage ne '') {
+               print "<td align='center' width='15%'><input type='submit' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
+       } else {
+               print "<td align='center' width='15%'><input type='reset' name='ACTION' value='$Lang::tr{'reset'}' /></td>";
+       }
+}
+print <<END
+       <td width='5%' align='right'>
+               <a href='${General::adminmanualurl}/section-firewall.html#section-port-forwarding' target='_blank'>
+               <img src='/images/web-support.png' alt='$Lang::tr{'online help en'}' title='$Lang::tr{'online help en'}' /></a></td>
+       </tr>
+</table>
+END
+;
+&Header::closebox();
+
+print "</form>\n";
+
+&Header::openbox('100%', 'left', $Lang::tr{'current rules'});
+print <<END
+<table width='100%'>
+<tr>
+<td width='7%' class='boldbase' align='center'><b>$Lang::tr{'proto'}</b></td>
+<td width='31%' class='boldbase' align='center'><b>$Lang::tr{'source'}</b></td>
+<td width='2%' class='boldbase' align='center'>&nbsp;</td>
+<td width='31%' class='boldbase' align='center'><b>$Lang::tr{'destination'}</b></td>
+<td width='24%' class='boldbase' align='center'><b>$Lang::tr{'remark'}</b></td>
+<td width='4%' class='boldbase' colspan='4' align='center'><b>$Lang::tr{'action'}</b></td>
+</tr>
+END
+;
+
+my $id = 0;
+my $xtaccesscolor = '#F6F4F4';
+open(RULES, "$filename") or die 'Unable to open config file.';
+while (<RULES>)
+{
+       my $protocol = '';
+       my $gif = '';
+       my $gdesc = '';
+       my $toggle = '';
+       chomp($_);
+       my @temp = split(/\,/,$_);
+       $temp[9] ='' unless defined $temp[9];# Glles ESpinasse : suppress warning on page init
+       if ($temp[2] eq 'udp') {
+               $protocol = 'UDP'; }
+       elsif ($temp[2] eq 'gre') {
+               $protocol = 'GRE' }
+       else {
+               $protocol = 'TCP' }
+       # Change bgcolor when a new portfw rule is added
+       if ($temp[1] eq "0"){
+               $id++;
+       }
+       # Darren Critchley highlight the row we are editing
+       if ( $cgiparams{'ACTION'} eq $Lang::tr{'edit'} && $cgiparams{'KEY1'} eq $temp[0] && $cgiparams{'KEY2'} eq $temp[1] ) { 
+               print "<tr bgcolor='${Header::colouryellow}'>\n";
+       } else {
+               if ($id % 2) {
+                       print "<tr bgcolor='${Header::table1colour}'>\n"; 
+               }
+               else {
+                       print "<tr bgcolor='${Header::table2colour}'>\n";
+               }
+       }
+       
+       if ($temp[6] eq 'on') { $gif = 'on.gif'; $toggle='off'; $gdesc=$Lang::tr{'click to disable'};}
+               else { $gif = 'off.gif'; $toggle='on'; $gdesc=$Lang::tr{'click to enable'}; }
+
+               # Darren Critchley - this code no longer works - should we remove?
+       # catch for 'old-style' rules file - assume default ip if
+       # none exists
+       if (!&General::validip($temp[7]) || $temp[7] eq '0.0.0.0') {
+               $temp[7] = 'DEFAULT IP'; }
+               if ($temp[1] eq '0') { # Port forwarding entry
+
+               # Darren Critchley - Format the source and destintation ports
+               my $srcprt = $temp[3];
+               $srcprt =~ s/-/ - /;
+               $srcprt =~ s/:/ - /;
+               my $dstprt = $temp[5];
+               $dstprt =~ s/-/ - /;
+               $dstprt =~ s/:/ - /;
+
+               # Darren Critchley - Get Port Service Name if we can - code borrowed from firewalllog.dat
+               $_=$temp[3];
+               if (/^\d+$/) {
+                       my $servi = uc(getservbyport($temp[3], lc($temp[2])));
+                       if ($servi ne '' && $temp[3] < 1024) {
+                               $srcprt = "$srcprt($servi)"; }
+               }
+               $_=$temp[5];
+               if (/^\d+$/) {
+                       my $servi = uc(getservbyport($temp[5], lc($temp[2])));
+                       if ($servi ne '' && $temp[5] < 1024) {
+                               $dstprt = "$dstprt($servi)"; }
+               }
+
+               # Darren Critchley - If the line is too long, wrap the port numbers
+               my $srcaddr = "$temp[7] : $srcprt";
+               if (length($srcaddr) > 22) {
+                       $srcaddr = "$temp[7] :<br /> $srcprt";
+               }
+               my $dstaddr = "$temp[4] : $dstprt";
+               if (length($dstaddr) > 26) {
+                       $dstaddr = "$temp[4] :<br /> $dstprt";
+               }
+print <<END
+<td align='center'>$protocol</td>
+<td align='center'>$srcaddr</td>
+<td align='center'><img src='/images/forward.gif' alt='=&gt;' /></td>
+<td align='center'>$dstaddr</td>
+<td align='left'>&nbsp;$temp[9]</td>
+<td align='center'>
+       <form method='post' name='frm$temp[0]c' action='$ENV{'SCRIPT_NAME'}'>
+       <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
+       <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
+       <input type='hidden' name='KEY1' value='$temp[0]' />
+       <input type='hidden' name='KEY2' value='$temp[1]' />
+       <input type='hidden' name='ENABLED' value='$toggle' />
+       </form>
+</td>
+
+<td align='center'>
+       <form method='post' name='frm$temp[0]' action='$ENV{'SCRIPT_NAME'}'>
+       <input type='hidden' name='ACTION' value='$Lang::tr{'add xtaccess'}' />
+       <input type='image' name='$Lang::tr{'add xtaccess'}' src='/images/add.gif' alt='$Lang::tr{'add xtaccess'}' title='$Lang::tr{'add xtaccess'}' />
+       <input type='hidden' name='KEY1' value='$temp[0]' />
+       <input type='hidden' name='KEY2' value='$temp[1]' />
+       </form>
+</td>
+
+<td align='center'>
+       <form method='post' name='frm$temp[0]' action='$ENV{'SCRIPT_NAME'}'>
+       <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
+       <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
+       <input type='hidden' name='KEY1' value='$temp[0]' />
+       <input type='hidden' name='KEY2' value='$temp[1]' />
+       </form>
+</td>
+
+<td align='center'>
+       <form method='post' name='frm$temp[0]b' action='$ENV{'SCRIPT_NAME'}'>
+       <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
+       <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
+       <input type='hidden' name='KEY1' value='$temp[0]' />
+       <input type='hidden' name='KEY2' value='$temp[1]' />
+       </form>
+</td>
+
+</tr>
+END
+       ;
+       } else { # external access entry
+print <<END
+<td align='center'>&nbsp;</td>
+
+<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>
+
+<td align='center'>
+       <form method='post' name='frm$temp[0]$temp[1]t' action='$ENV{'SCRIPT_NAME'}'>
+       <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
+       <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
+       <input type='hidden' name='KEY1' value='$temp[0]' />
+       <input type='hidden' name='KEY2' value='$temp[1]' />
+       <input type='hidden' name='ENABLED' value='$toggle' />
+       </form>
+</td>
+
+<td align='center'>&nbsp;</td>
+
+<td align='center'>
+       <form method='post' name='frm$temp[0]$temp[1]' action='$ENV{'SCRIPT_NAME'}'>
+       <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
+       <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
+       <input type='hidden' name='KEY1' value='$temp[0]' />
+       <input type='hidden' name='KEY2' value='$temp[1]' />
+       </form>
+</td>
+
+<td align='center'>
+       <form method='post' name='frm$temp[0]b$temp[1]b' action='$ENV{'SCRIPT_NAME'}'>
+       <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
+       <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
+       <input type='hidden' name='KEY1' value='$temp[0]' />
+       <input type='hidden' name='KEY2' value='$temp[1]' />
+       </form>
+</td>
+
+</tr>
+END
+       ;
+       }
+}
+
+close(RULES);
+
+print "</table>";
+
+# If the fixed lease file contains entries, print Key to action icons
+if ( ! -z "$filename") {
+print <<END
+<table>
+<tr>
+       <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
+       <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
+       <td class='base'>$Lang::tr{'click to disable'}</td>
+       <td>&nbsp;&nbsp;</td>
+       <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
+       <td class='base'>$Lang::tr{'click to enable'}</td>
+       <td>&nbsp;&nbsp;</td>
+       <td><img src='/images/add.gif' alt='$Lang::tr{'add xtaccess'}' /></td>
+       <td class='base'>$Lang::tr{'add xtaccess'}</td>
+       <td>&nbsp;&nbsp;</td>
+       <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
+       <td class='base'>$Lang::tr{'edit'}</td>
+       <td>&nbsp;&nbsp;</td>
+       <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
+       <td class='base'>$Lang::tr{'remove'}</td>
+</tr>
+</table>
+END
+;
+}
+
+&Header::closebox();
+
+&Header::closebigbox();
+
+&Header::closepage();
+
+# Validate Field Entries
+sub validateparams 
+{
+       # Darren Critchley - Get rid of dashes in port ranges
+       $cgiparams{'DEST_PORT'}=~ tr/-/:/;
+       $cgiparams{'SRC_PORT'}=~ tr/-/:/;
+       
+       # Darren Critchley - code to substitue wildcards
+       if ($cgiparams{'SRC_PORT'} eq "*") {
+               $cgiparams{'SRC_PORT'} = "1:65535";
+       }
+       if ($cgiparams{'SRC_PORT'} =~ /^(\D)\:(\d+)$/) {
+               $cgiparams{'SRC_PORT'} = "1:$2";
+       }
+       if ($cgiparams{'SRC_PORT'} =~ /^(\d+)\:(\D)$/) {
+               $cgiparams{'SRC_PORT'} = "$1:65535";
+       }
+       if ($cgiparams{'DEST_PORT'} eq "*") {
+               $cgiparams{'DEST_PORT'} = "1:65535";
+       }
+       if ($cgiparams{'DEST_PORT'} =~ /^(\D)\:(\d+)$/) {
+               $cgiparams{'DEST_PORT'} = "1:$2";
+       }
+       if ($cgiparams{'DEST_PORT'} =~ /^(\d+)\:(\D)$/) {
+               $cgiparams{'DEST_PORT'} = "$1:65535";
+       }
+
+       # Darren Critchley - Add code for GRE protocol - we want to ignore ports, but we need a place holder
+       if ($cgiparams{'PROTOCOL'} eq 'gre') {
+               $cgiparams{'SRC_PORT'} = "GRE";
+               $cgiparams{'DEST_PORT'} = "GRE";
+       }
+
+       unless($cgiparams{'PROTOCOL'} =~ /^(tcp|udp|gre)$/) { $errormessage = $Lang::tr{'invalid input'}; }
+       # Darren Critchley - Changed how the error routine works a bit - for the validportrange check, we need to 
+       # pass in src or dest to determine which side we are working with.
+       # the routine returns the complete error or ''
+       if ($cgiparams{'PROTOCOL'} ne 'gre') {
+               $errormessage = &General::validportrange($cgiparams{'SRC_PORT'}, 'src');
+       }
+       if( ($cgiparams{'ORIG_IP'} ne "0" && $cgiparams{'KEY2'} ne "0") || $cgiparams{'ACTION'} eq $Lang::tr{'add'}) { 
+       # if it is a port forward record with 0 in orig_ip then ignore checking this field
+               unless(&General::validipormask($cgiparams{'ORIG_IP'}))
+               {
+                       if ($cgiparams{'ORIG_IP'} ne '') {
+                               $errormessage = $Lang::tr{'source ip bad'}; }
+                       else {
+                               $cgiparams{'ORIG_IP'} = '0.0.0.0/0'; }
+               }
+       }
+       # Darren Critchey - New rule that sets destination same as source if dest_port is blank.
+       if ($cgiparams{'DEST_PORT'} eq ''){
+               $cgiparams{'DEST_PORT'} = $cgiparams{'SRC_PORT'};
+       }
+       # Darren Critchey - Just in case error message is already set, this routine would wipe it out if
+       # we don't do a test here
+       if ($cgiparams{'PROTOCOL'} ne 'gre') {
+               unless($errormessage) {$errormessage = &General::validportrange($cgiparams{'DEST_PORT'}, 'dest');}
+       }
+       unless(&General::validip($cgiparams{'DEST_IP'})) { $errormessage = $Lang::tr{'destination ip bad'}; }
+       return;
+}
+
+# Darren Critchley - we want to make sure that a port range does not overlap another port range
+sub checkportoverlap
+{
+       my $portrange1 = $_[0]; # New port range
+       my $portrange2 = $_[1]; # existing port range
+       my @tempr1 = split(/\:/,$portrange1);
+       my @tempr2 = split(/\:/,$portrange2);
+
+       unless (&checkportinc($tempr1[0], $portrange2)){ return 0;}
+       unless (&checkportinc($tempr1[1], $portrange2)){ return 0;}
+       
+       unless (&checkportinc($tempr2[0], $portrange1)){ return 0;}
+       unless (&checkportinc($tempr2[1], $portrange1)){ return 0;}
+
+       return 1; # Everything checks out!
+}
+
+# Darren Critchley - we want to make sure that a port entry is not within an already existing range
+sub checkportinc
+{
+       my $port1 = $_[0]; # Port
+       my $portrange2 = $_[1]; # Port range
+       my @tempr1 = split(/\:/,$portrange2);
+
+       if ($port1 < $tempr1[0] || $port1 > $tempr1[1]) {
+               return 1; 
+       } else {
+               return 0; 
+       }
+}
+
+# Darren Critchley - certain ports are reserved for Ipcop 
+# TCP 67,68,81,222,445
+# UDP 67,68
+# Params passed in -> port, rangeyn, protocol
+sub disallowreserved
+{
+       # port 67 and 68 same for tcp and udp, don't bother putting in an array
+       my $msg = "";
+       my @tcp_reserved = (81,222,444);
+       my $prt = $_[0]; # the port or range
+       my $ryn = $_[1]; # tells us whether or not it is a port range
+       my $prot = $_[2]; # protocol
+       my $srcdst = $_[3]; # source or destination
+       
+       if ($ryn) { # disect port range
+               if ($srcdst eq "src") {
+                       $msg = "$Lang::tr{'rsvd src port overlap'}";
+               } else {
+                       $msg = "$Lang::tr{'rsvd dst port overlap'}";
+               }
+               my @tmprng = split(/\:/,$prt);
+               unless (67 < $tmprng[0] || 67 > $tmprng[1]) { $errormessage="$msg 67"; return; }
+               unless (68 < $tmprng[0] || 68 > $tmprng[1]) { $errormessage="$msg 68"; return; }
+               if ($prot eq "tcp") {
+                       foreach my $prange (@tcp_reserved) {
+                               unless ($prange < $tmprng[0] || $prange > $tmprng[1]) { $errormessage="$msg $prange"; return; }
+                       }
+               }
+       } else {
+               if ($srcdst eq "src") {
+                       $msg = "$Lang::tr{'reserved src port'}";
+               } else {
+                       $msg = "$Lang::tr{'reserved dst port'}";
+               }
+               if ($prt == 67) { $errormessage="$msg 67"; return; }
+               if ($prt == 68) { $errormessage="$msg 68"; return; }
+               if ($prot eq "tcp") {
+                       foreach my $prange (@tcp_reserved) {
+                               if ($prange == $prt) { $errormessage="$msg $prange"; return; }
+                       }
+               }
+       }
+       return;
+}
+
+# Darren Critchley - Attempt to combine Add/Update validation as they are almost the same
+sub valaddupdate
+{
+       if ($cgiparams{'KEY2'} eq "0"){ # if it is a port forward rule, then validate properly
+               &validateparams();
+       } else { # it is an xtaccess rule, just check for a valid ip
+               unless(&General::validipormask($cgiparams{'ORIG_IP'}))
+               {
+                       if ($cgiparams{'ORIG_IP'} ne '') {
+                               $errormessage = $Lang::tr{'source ip bad'}; }
+                       else { # this rule stops someone from adding an ALL xtaccess record
+                               $errormessage = $Lang::tr{'xtaccess all error'}; 
+                               $cgiparams{'ACTION'} = $Lang::tr{'add xtaccess'};
+                       }
+               }
+               # Darren Critchley - check for 0.0.0.0/0 - not allowed for xtaccess
+               if ($cgiparams{'ORIG_IP'} eq "0.0.0.0/0" || $cgiparams{'ORIG_IP'} eq "0.0.0.0") {
+                       $errormessage = $Lang::tr{'xtaccess all error'}; 
+                       $cgiparams{'ACTION'} = $Lang::tr{'add xtaccess'};
+               }
+       }
+       # Darren Critchley - Remove commas from remarks
+       $cgiparams{'REMARK'} = &Header::cleanhtml($cgiparams{'REMARK'});
+
+       # Darren Critchley - Check to see if we are working with port ranges
+       our ($prtrange1, $prtrange2);
+       $_ = $cgiparams{'SRC_PORT'};
+       if ($cgiparams{'KEY2'} eq "0" && m/:/){
+               $prtrange1 = 1;
+       }
+       if ($cgiparams{'SRC_IP'} eq '0.0.0.0') { # Dave Roberts - only check if using DEFAULT IP
+               if ($prtrange1 == 1){ # check for source ports reserved for Ipcop
+                       &disallowreserved($cgiparams{'SRC_PORT'},1,$cgiparams{'PROTOCOL'},"src");
+                       if ($errormessage) { goto EXITSUB; }
+               } else { # check for source port reserved for Ipcop
+                       &disallowreserved($cgiparams{'SRC_PORT'},0,$cgiparams{'PROTOCOL'},"src");
+                       if ($errormessage) { goto EXITSUB; }
+               }
+       }
+       
+       $_ = $cgiparams{'DEST_PORT'};
+       if ($cgiparams{'KEY2'} eq "0" && m/:/){
+               $prtrange2 = 1;
+       }
+       if ($cgiparams{'SRC_IP'} eq '0.0.0.0') { # Dave Roberts - only check if using DEFAULT IP
+               if ($prtrange2 == 1){ # check for destination ports reserved for IPFire
+                       &disallowreserved($cgiparams{'DEST_PORT'},1,$cgiparams{'PROTOCOL'},"dst");
+                       if ($errormessage) { goto EXITSUB; }
+               } else { # check for destination port reserved for IPFire
+                       &disallowreserved($cgiparams{'DEST_PORT'},0,$cgiparams{'PROTOCOL'},"dst");
+                       if ($errormessage) { goto EXITSUB; }
+               }
+       }
+       
+
+EXITSUB:
+       return;
+}
+
+# Darren Critchley - Duplicate or overlapping Port range check
+sub portchecks
+{
+       $_ = $_[0];
+       our ($prtrange1, $prtrange2);
+       if (m/:/ && $prtrange1 == 1) { # comparing two port ranges
+               unless (&checkportoverlap($cgiparams{'SRC_PORT'},$_[0])) {
+                       $errormessage = "$Lang::tr{'source port overlaps'} $_[0]";
+               }
+       }
+       if (m/:/ && $prtrange1 == 0 && $errormessage eq '') { # compare one port to a range
+               unless (&checkportinc($cgiparams{'SRC_PORT'}, $_[0])) {
+                       $errormessage = "$Lang::tr{'srcprt within existing'} $_[0]";
+               }
+       }
+       if (! m/:/ && $prtrange1 == 1 && $errormessage eq '') { # compare one port to a range
+               unless (&checkportinc($_[0], $cgiparams{'SRC_PORT'})) {
+                       $errormessage = "$Lang::tr{'srcprt range overlaps'} $_[0]";
+               }
+       }
+
+       if ($errormessage eq ''){
+               $_ = $_[1];
+               if (m/:/ && $prtrange2 == 1) { # if true then there is a port range
+                       unless (&checkportoverlap($cgiparams{'DEST_PORT'},$_[1])) {
+                               $errormessage = "$Lang::tr{'destination port overlaps'} $_[1]";
+                       }
+               }
+               if (m/:/ && $prtrange2 == 0 && $errormessage eq '') { # compare one port to a range
+                       unless (&checkportinc($cgiparams{'DEST_PORT'}, $_[1])) {
+                               $errormessage = "$Lang::tr{'dstprt within existing'} $_[1]";
+                       }
+               }
+               if (! m/:/ && $prtrange2 == 1 && $errormessage eq '') { # compare one port to a range
+                       unless (&checkportinc($_[1], $cgiparams{'DEST_PORT'})) {
+                               $errormessage = "$Lang::tr{'dstprt range overlaps'} $_[1]";
+                       }
+               }
+       }
+       return;
+}