X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=html%2Fcgi-bin%2Fportfw.cgi;h=5583fb88a555eb4136f6383c99abedbdf606749a;hb=f40fd7918a407a4054181c34e4e61264107de957;hp=bfa9e99e7118b1ade4ceb5da3deec2bcd986bec8;hpb=cd1a2927226c734d96478e12bb768256fb64a06a;p=people%2Fpmueller%2Fipfire-2.x.git diff --git a/html/cgi-bin/portfw.cgi b/html/cgi-bin/portfw.cgi index bfa9e99e71..5583fb88a5 100644 --- a/html/cgi-bin/portfw.cgi +++ b/html/cgi-bin/portfw.cgi @@ -1,1179 +1,1177 @@ -#!/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 = ; - 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 = ; - 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 = ; - 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 = ; - 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 = ; - 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 = ; - 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 "$errormessage\n"; - print " \n"; - &Header::closebox(); -} - -print "
\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 < - - $Lang::tr{'protocol'}: $PROT -   - $Lang::tr{'destination ip'}:  - $cgiparams{'DEST_IP'} -   - $Lang::tr{'destination port'}:  - $dstprt - - - - - - - - -END -; -} else { -print < - - $Lang::tr{'protocol'}:  - - - - $Lang::tr{'alias ip'}: - - - - -   -   - $Lang::tr{'destination ip'}: - - $Lang::tr{'destination port'}: - - - -END -; -} - -print < - - $Lang::tr{'remark title'} *  - -END -; -unless ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'} && $cgiparams{'ENABLED'} eq "off") { - print " "; - print "$Lang::tr{'enabled'} \n"; -} -print < - -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 "\n"; -} else { -print < - - $Lang::tr{'source network'} *  - - - -END -; -} - -print < -
- - * $Lang::tr{'this field may be blank'} -END -; - - -if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){ - if($cgiparams{'KEY2'} eq "0"){ - print "$Lang::tr{'open to all'}: \n"; - } else { - print " \n"; - } - print ""; - print ""; - print ""; - print ""; - # on an edit and an xtaccess add, for some reason the "Reset" button stops working, so I make it a submit button -} else { - print " \n"; - print ""; - if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}) { - print ""; - print ""; - print ""; - } elsif ($errormessage ne '') { - print ""; - } else { - print ""; - } -} -print < - - $Lang::tr{ - - -END -; -&Header::closebox(); - -print "\n"; - -&Header::openbox('100%', 'left', $Lang::tr{'current rules'}); -print < - -$Lang::tr{'proto'} -$Lang::tr{'source'} -  -$Lang::tr{'destination'} -$Lang::tr{'remark'} -$Lang::tr{'action'} - -END -; - -my $id = 0; -my $xtaccesscolor = '#F6F4F4'; -open(RULES, "$filename") or die 'Unable to open config file.'; -while () -{ - 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 "\n"; - } else { - if ($id % 2) { - print "\n"; - } - else { - print "\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] :
$srcprt"; - } - my $dstaddr = "$temp[4] : $dstprt"; - if (length($dstaddr) > 26) { - $dstaddr = "$temp[4] :
$dstprt"; - } -print <$protocol -$srcaddr -=> -$dstaddr - $temp[9] - -
- - - - - -
- - - -
- - - - -
- - - -
- - - - -
- - - -
- - - - -
- - - -END - ; - } else { # external access entry -print <  - - $Lang::tr{'access allowed'} $temp[8]     ($temp[9]) - - -
- - - - - -
- - -  - - -
- - - - -
- - - -
- - - - -
- - - -END - ; - } -} - -close(RULES); - -print ""; - -# If the fixed lease file contains entries, print Key to action icons -if ( ! -z "$filename") { -print < - -  $Lang::tr{'legend'}:  - $Lang::tr{ - $Lang::tr{'click to disable'} -    - $Lang::tr{ - $Lang::tr{'click to enable'} -    - $Lang::tr{ - $Lang::tr{'add xtaccess'} -    - $Lang::tr{ - $Lang::tr{'edit'} -    - $Lang::tr{ - $Lang::tr{'remove'} - - -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,445); - 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 IPCop - &disallowreserved($cgiparams{'DEST_PORT'},1,$cgiparams{'PROTOCOL'},"dst"); - if ($errormessage) { goto EXITSUB; } - } else { # check for destination port reserved for IPCop - &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; -} +#!/usr/bin/perl +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2007 Michael Tremer & Christian Schmidt # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +use strict; + +# enable only the following on debugging purpose +#use warnings; +#use CGI::Carp 'fatalsToBrowser'; + +require '/var/ipfire/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 %color = (); +my %mainsettings = (); +&General::readhash("${General::swroot}/main/settings", \%mainsettings); +&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color); + +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 = ; + 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 = ; + 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 = ; + 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 = ; + 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 = ; + 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 = ; + 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 "$errormessage\n"; + print " \n"; + &Header::closebox(); +} + +print "
\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 < + + $Lang::tr{'protocol'}: $PROT +   + $Lang::tr{'destination ip'}:  + $cgiparams{'DEST_IP'} +   + $Lang::tr{'destination port'}:  + $dstprt + + + + + + + + +END +; +} else { +print < + + $Lang::tr{'protocol'}:  + + + + $Lang::tr{'alias ip'}: + + + + +   +   + $Lang::tr{'destination ip'}: + + $Lang::tr{'destination port'}: + + + +END +; +} + +print < + + $Lang::tr{'remark title'} *  + +END +; +unless ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'} && $cgiparams{'ENABLED'} eq "off") { + print " "; + print "$Lang::tr{'enabled'} \n"; +} +print < + +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 "\n"; +} else { +print < + + $Lang::tr{'source network'} *  + + + +END +; +} + +print < +
+ + * $Lang::tr{'this field may be blank'} +END +; + + +if ($cgiparams{'ACTION'} eq $Lang::tr{'edit'}){ + if($cgiparams{'KEY2'} eq "0"){ + print "$Lang::tr{'open to all'}: \n"; + } else { + print " \n"; + } + print ""; + print ""; + print ""; + print ""; + # on an edit and an xtaccess add, for some reason the "Reset" button stops working, so I make it a submit button +} else { + print " \n"; + print ""; + if ($cgiparams{'ACTION'} eq $Lang::tr{'add xtaccess'}) { + print ""; + print ""; + print ""; + } elsif ($errormessage ne '') { + print ""; + } else { + print ""; + } +} +print <  + + +END +; +&Header::closebox(); + +print "\n"; + +&Header::openbox('100%', 'left', $Lang::tr{'current rules'}); +print < + +$Lang::tr{'proto'} +$Lang::tr{'source'} +  +$Lang::tr{'destination'} +$Lang::tr{'remark'} +$Lang::tr{'action'} + +END +; + +my $id = 0; +my $xtaccesscolor = '#F6F4F4'; +open(RULES, "$filename") or die 'Unable to open config file.'; +while () +{ + 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 "\n"; + } else { + if ($id % 2) { + print "\n"; + } + else { + print "\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] :
$srcprt"; + } + my $dstaddr = "$temp[4] : $dstprt"; + if (length($dstaddr) > 26) { + $dstaddr = "$temp[4] :
$dstprt"; + } +print <$protocol +$srcaddr +=> +$dstaddr + $temp[9] + +
+ + + + + +
+ + + +
+ + + + +
+ + + +
+ + + + +
+ + + +
+ + + + +
+ + + +END + ; + } else { # external access entry +print <  + + $Lang::tr{'access allowed'} $temp[8]     ($temp[9]) + + +
+ + + + + +
+ + +  + + +
+ + + + +
+ + + +
+ + + + +
+ + + +END + ; + } +} + +close(RULES); + +print ""; + +# If the fixed lease file contains entries, print Key to action icons +if ( ! -z "$filename") { +print < + +  $Lang::tr{'legend'}:  + $Lang::tr{ + $Lang::tr{'click to disable'} +    + $Lang::tr{ + $Lang::tr{'click to enable'} +    + $Lang::tr{ + $Lang::tr{'add xtaccess'} +    + $Lang::tr{ + $Lang::tr{'edit'} +    + $Lang::tr{ + $Lang::tr{'remove'} + + +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; +}