Forward Firewall: Added multiport support to DNAT/Portforwarding
authorAlexander Marx <amarx@ipfire.org>
Thu, 11 Apr 2013 08:50:29 +0000 (10:50 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 9 Aug 2013 12:12:39 +0000 (14:12 +0200)
Now it is possible to use multiple ports under DNAT when TARGET has no Port, one Port or one Portrange defined

config/forwardfw/rules.pl
html/cgi-bin/forwardfw.cgi
html/cgi-bin/fwhosts.cgi

index c7acd122b5d98fcc75f8ae8c538288748f550dd4..917e061eb97e8be11891a89d7b905f7b6a0cd829 100755 (executable)
@@ -177,6 +177,7 @@ sub buildrules
        my $snatport;
        my $fireport;
        my $nat;
+       my $fwaccessdport;
        foreach my $key (sort {$a <=> $b} keys %$hash){
                next if ($$hash{$key}[6] eq 'RED' && $conexists eq 'off' );
                if ($$hash{$key}[28] eq 'ON'){
@@ -184,7 +185,12 @@ sub buildrules
                        $natip=&get_nat_ip($$hash{$key}[29]);
                        if($$hash{$key}[31] eq 'dnat'){
                                $nat='DNAT';
-                               $fireport='--dport '.$$hash{$key}[30] if ($$hash{$key}[30]>0);
+                               if ($$hash{$key}[30] =~ /\|/){
+                                       $$hash{$key}[30]=~ tr/|/,/;
+                                       $fireport='-m multiport --dport '.$$hash{$key}[30];
+                               }else{
+                                       $fireport='--dport '.$$hash{$key}[30] if ($$hash{$key}[30]>0);
+                               }
                        }else{
                                $nat='SNAT';
                        }
@@ -291,7 +297,16 @@ sub buildrules
                                                                                my ($ip,$sub) =split("/",$targethash{$b}[0]);
                                                                                print "$command $$hash{$key}[1] $PROT $STAG $sourcehash{$a}[0] $SPORT $natip $fireport $TIME -j $nat --to $ip$DPORT\n";
                                                                                $DPORT =~ s/\-/:/g;
-                                                                               my $fwaccessdport="--dport ".substr($DPORT,1,) if ($DPORT);
+                                                                               if ($DPORT){
+                                                                                       $fwaccessdport="--dport ".substr($DPORT,1,);
+                                                                               }elsif(! $DPORT && $$hash{$key}[30] ne ''){
+                                                                                       if ($$hash{$key}[30]=~m/|/i){
+                                                                                               $$hash{$key}[30] =~ s/\|/,/g;
+                                                                                               $fwaccessdport="-m multiport --dport $$hash{$key}[30]";
+                                                                                       }else{
+                                                                                               $fwaccessdport="--dport $$hash{$key}[30]";
+                                                                                       }
+                                                                               }
                                                                                print "iptables -A PORTFWACCESS $PROT -i $con $STAG $sourcehash{$a}[0] -d $ip $fwaccessdport $TIME -j $$hash{$key}[0]\n";
                                                                        }elsif($$hash{$key}[28] eq 'ON' && $$hash{$key}[32] eq 'snat'){
                                                                                print "$command $$hash{$key}[1] $PROT $STAG $sourcehash{$a}[0] $SPORT -d $targethash{$b}[0] $DPORT $TIME -j $nat --to $natip$fireport\n";
@@ -332,9 +347,17 @@ sub buildrules
                                                                                my ($ip,$sub) =split("/",$targethash{$b}[0]);
                                                                                system "$command $$hash{$key}[1] $PROT $STAG $sourcehash{$a}[0] $SPORT $natip $fireport $TIME -j $nat --to $ip$DPORT\n";
                                                                                $DPORT =~ s/\-/:/g;
-                                                                               my $fwaccessdport="--dport ".substr($DPORT,1,) if ($DPORT);
+                                                                               if ($DPORT){
+                                                                                       $fwaccessdport="--dport ".substr($DPORT,1,);
+                                                                               }elsif(! $DPORT && $$hash{$key}[30] ne ''){
+                                                                                       if ($$hash{$key}[30]=~m/|/i){
+                                                                                               $$hash{$key}[30] =~ s/\|/,/g;
+                                                                                               $fwaccessdport="-m multiport --dport $$hash{$key}[30]";
+                                                                                       }else{
+                                                                                               $fwaccessdport="--dport $$hash{$key}[30]";
+                                                                                       }
+                                                                               }
                                                                                system "iptables -A PORTFWACCESS $PROT -i $con $STAG $sourcehash{$a}[0] -d $ip $fwaccessdport $TIME -j $$hash{$key}[0]\n";
-                                                                               
                                                                        }elsif($$hash{$key}[28] eq 'ON' && $$hash{$key}[31] eq 'snat'){
                                                                                if ($$hash{$key}[17] eq 'ON'){
                                                                                        system "$command $$hash{$key}[1] $PROT $STAG $sourcehash{$a}[0] $SPORT -d $targethash{$b}[0] $DPORT $TIME -j LOG --log-prefix 'SNAT '\n";
@@ -499,6 +522,10 @@ sub get_prot
                        return &fwlib::get_srvgrp_prot($$hash{$key}[15]);
                }
        }
+       #DNAT
+       if ($SRC_TGT eq '' && $$hash{$key}[31] eq 'dnat' && $$hash{$key}[11] eq '' && $$hash{$key}[12] ne ''){
+               return "$$hash{$key}[12]";
+       }
 }
 sub get_port
 {
index 584f7f093adc6702ecd95ad3fcd0c90e83165788..72771e8cf4693683d15bd3bc076e8513c61d71e6 100755 (executable)
@@ -591,7 +591,7 @@ sub addrule
 {
        &error;
        if (-f "${General::swroot}/forward/reread"){
-               print "<table border='0'><form method='post'><td><div style='font-size:11pt; font-weight: bold;vertical-align: middle; '><input type='submit' name='ACTION' value='$Lang::tr{'fwdfw reread'}' style='font-face: Comic Sans MS; color: red; font-weight: bold; font-size: 14pt; text-decoration: blink;'>&nbsp &nbsp $Lang::tr{'fwhost reread'}</div</td></tr></table></form><hr><br>";
+               print "<table border='0'><form method='post'><td><div style='font-size:11pt; font-weight: bold;vertical-align: middle; '><input type='submit' name='ACTION' value='$Lang::tr{'fwdfw reread'}' style='font-face: Comic Sans MS; color: red; font-weight: bold; font-size: 14pt;'>&nbsp &nbsp $Lang::tr{'fwhost reread'}</div</td></tr></table></form><hr><br>";
        }
        &Header::openbox('100%', 'left', "");
        print "<form method='post'>";
@@ -771,7 +771,7 @@ sub checktarget
        #check DNAT settings (has to be single Host and single Port or portrange)
        if ($fwdfwsettings{'USE_NAT'} eq 'ON' && $fwdfwsettings{'nat'} eq 'dnat'){
                if($fwdfwsettings{'grp2'} eq 'tgt_addr' || $fwdfwsettings{'grp2'} eq 'cust_host_tgt' || $fwdfwsettings{'grp2'} eq 'ovpn_host_tgt'){
-                       if ($fwdfwsettings{'USESRV'} eq ''){
+                       if ($fwdfwsettings{'USESRV'} eq '' && $fwdfwsettings{'dnatport'} eq ''){
                                $errormessage=$Lang::tr{'fwdfw target'}.": ".$Lang::tr{'fwdfw dnat porterr'}."<br>";
                        }
                        #check if manual ip is a single Host (if set)
@@ -905,7 +905,6 @@ sub checktarget
        if ($fwdfwsettings{'USESRV'} ne 'ON'){
                $fwdfwsettings{'grp3'}='';
                $fwdfwsettings{$fwdfwsettings{'grp3'}}='';
-               $fwdfwsettings{'TGT_PROT'}='';
                $fwdfwsettings{'ICMP_TGT'}='';
        }
        #check timeframe
@@ -946,10 +945,9 @@ sub checkrule
                #if no port is given in nat area, take target host port
                if($fwdfwsettings{'nat'} eq 'dnat' && $fwdfwsettings{'grp3'} eq 'TGT_PORT' && $fwdfwsettings{'dnatport'} eq ''){$fwdfwsettings{'dnatport'}=$fwdfwsettings{'TGT_PORT'};}
                #check if port given in nat area is a single valid port or portrange
-               if($fwdfwsettings{'nat'} eq 'dnat' && !&check_natport($fwdfwsettings{'dnatport'})){
+               if($fwdfwsettings{'nat'} eq 'dnat' && $fwdfwsettings{'TGT_PORT'} ne '' && !&check_natport($fwdfwsettings{'dnatport'})){
                        $errormessage=$Lang::tr{'fwdfw target'}.": ".$Lang::tr{'fwdfw dnat porterr'}."<br>";
-               }
-               elsif($fwdfwsettings{'USESRV'} eq 'ON' && $fwdfwsettings{'grp3'} eq 'cust_srv'){
+               }elsif($fwdfwsettings{'USESRV'} eq 'ON' && $fwdfwsettings{'grp3'} eq 'cust_srv'){
                        my $custsrvport;
                        #get servcie Protocol and Port
                        foreach my $key (sort keys %customservice){
@@ -962,6 +960,42 @@ sub checkrule
                        }
                        if($fwdfwsettings{'nat'} eq 'dnat' && $fwdfwsettings{'dnatport'} eq ''){$fwdfwsettings{'dnatport'}=$custsrvport;}
                }
+               #check if DNAT port is multiple
+               if($fwdfwsettings{'nat'} eq 'dnat' && $fwdfwsettings{'dnatport'} ne ''){
+                       my @parts=split(",",$fwdfwsettings{'dnatport'});
+                                       my @values=();
+                                       foreach (@parts){
+                                               chomp($_);
+                                               if ($_ =~ /^(\d+)\-(\d+)$/ || $_ =~ /^(\d+)\:(\d+)$/) {
+                                                       my $check;
+                                                       #change dashes with :
+                                                       $_=~ tr/-/:/;
+                                                       if ($_ eq "*") {
+                                                               push(@values,"1:65535");
+                                                               $check='on';
+                                                       }
+                                                       if ($_ =~ /^(\D)\:(\d+)$/ || $_ =~ /^(\D)\-(\d+)$/) {
+                                                               push(@values,"1:$2");
+                                                               $check='on';
+                                                       }
+                                                       if ($_ =~ /^(\d+)\:(\D)$/ || $_ =~ /^(\d+)\-(\D)$/) {
+                                                               push(@values,"$1:65535");
+                                                               $check='on'
+                                                       }
+                                                       $errormessage .= &General::validportrange($_, 'destination');
+                                                       if(!$check){
+                                                               push (@values,$_);
+                                                       }
+                                               }else{
+                                                       if (&General::validport($_)){
+                                                               push (@values,$_);
+                                                       }else{
+                                                               
+                                                       }
+                                               }
+                                       }
+                                       $fwdfwsettings{'dnatport'}=join("|",@values);
+               }
        }
        #check valid remark
        if ($fwdfwsettings{'ruleremark'} ne '' && !&validremark($fwdfwsettings{'ruleremark'})){
@@ -1764,6 +1798,7 @@ END
                        print "<option value='$alias' $selected{'dnat'}{$alias}>$alias</option>";
                }
                print"</td></tr>";
+               $fwdfwsettings{'dnatport'}=~ tr/|/,/;
                print"<tr><td colspan='4'></td><td>Port: </td><td align='right'><input type='text' name='dnatport' style='width:130px;' value=$fwdfwsettings{'dnatport'}> </td></tr>";
                print"<tr><td colspan='8'><br></td></tr>";
                #SNAT
@@ -2371,6 +2406,7 @@ END
                        if ($$hash{$key}[31] eq 'dnat'){
                                print "IPFire ($$hash{$key}[29])";
                                if($$hash{$key}[30] ne ''){
+                                       $$hash{$key}[30]=~ tr/|/,/;
                                        print": $$hash{$key}[30]";
                                }
                                print"<br> DNAT->";
index 91ed3228bae001fa7a33fed46b751aea29f3cb45..0283f5c91da93a1fb351abb4b811826e82342a93 100755 (executable)
@@ -1067,7 +1067,7 @@ if($fwhostsettings{'ACTION'} eq '')
 sub showmenu
 {
        if (-f "${General::swroot}/forward/reread"){
-               print "<table border='0'><form method='post'><td><div style='font-size:11pt; font-weight: bold;vertical-align: middle; '><input type='submit' name='ACTION' value='$Lang::tr{'fwdfw reread'}' style='font-face: Comic Sans MS; color: red; font-weight: bold; font-size: 14pt; text-decoration: blink;'>$Lang::tr{'fwhost reread'}</td></tr></table></form><hr><br>";
+               print "<table border='0'><form method='post'><td><div style='font-size:11pt; font-weight: bold;vertical-align: middle; '><input type='submit' name='ACTION' value='$Lang::tr{'fwdfw reread'}' style='font-face: Comic Sans MS; color: red; font-weight: bold; font-size: 14pt;'>$Lang::tr{'fwhost reread'}</td></tr></table></form><hr><br>";
        }
        &Header::openbox('100%', 'left',$Lang::tr{'fwhost menu'});
        print<<END;