diff --git a/Shorewall-common/releasenotes.txt b/Shorewall-common/releasenotes.txt index bb51147f5..6ff97ca09 100644 --- a/Shorewall-common/releasenotes.txt +++ b/Shorewall-common/releasenotes.txt @@ -252,19 +252,21 @@ New Features in 4.1.6. Protocol Name/Number. Specify "-" if any PROTO should match. - DEST PORT - Destination port. May only be given if the PROTO is - tcp, udp or sctp. Neither port ranges nor port lists - may be given. Specify "-" if any PORT should match. + DEST PORT(S) + A comma-separated list of destination ports. May only + be given if the PROTO is tcp, udp, icmp or + sctp. Port ranges may not be used. Specify "-" + if any PORT should match. - SOURCE PORT - Source port. May only be given if the PROTO is - tcp, udp or sctp. Neither port ranges nor port lists - may be given. Specify "-" if any PORT should match. + SOURCE PORT(S) + A comma-separated list of source port. May only be + given if the PROTO is tcp, udp or sctp. Port ranges + may not be used. Specify "-" if any PORT should match. Entries in /etc/shorewall/tcfilters generate U32 tc filters which - may be displayed using the "shorewall show tc" ("shorewall-lite - show tc") command. + may be displayed using the "shorewall show filters" ("shorewall-lite + show filters") command. Note: The 'show filters' command is an + alias for the existing 'show classifiers' command. Note that /etc/shorewall/tcfilters provides a usable alternative to HIGH_ROUTE_MARKS=Yes. You can use marks to select between providers diff --git a/Shorewall-perl/Shorewall/Tc.pm b/Shorewall-perl/Shorewall/Tc.pm index a47657967..71726a5a3 100644 --- a/Shorewall-perl/Shorewall/Tc.pm +++ b/Shorewall-perl/Shorewall/Tc.pm @@ -125,7 +125,7 @@ our @deferred_rules; # tablenumber => # default => # redirected => [ , , ... ] -# u32tables => [ table1 , ... ] } +# } # our @tcdevices; our %tcdevices; @@ -524,7 +524,7 @@ sub validate_tc_class( $$$$$$ ) { # Process a record from the tcfilters file # sub process_tc_filter( $$$$$$ ) { - my ($devclass , $source, $dest , $proto, $port , $sport ) = @_; + my ($devclass , $source, $dest , $proto, $portlist , $sportlist ) = @_; my ($device, $class, $rest ) = split /:/, $devclass, 3; @@ -564,60 +564,78 @@ sub process_tc_filter( $$$$$$ ) { } } - unless ( $port eq '-' && $sport eq '-' ) { + if ( $portlist eq '-' && $sportlist eq '-' ) { + emit( "\nrun_tc $rule\\" , + " flowid $devref->{number}:$class" , + '' ); + } else { # # In order to be able to access the protocol header, we must create another hash table and link to it. # - # Create the Table if we don't already have a table for this device and protocol. + # Create the Table. # - my $tnum = $devref->{u32tables}[$protonumber]; + my $tnum = in_hex3 $devref->{tablenumber}++; - unless ( defined $tnum ) { - $tnum = $devref->{u32tables}[$protonumber] = in_hex3 $devref->{tablenumber}++; - - emit( "run_tc filter add dev $device parent $devnum:0 protocol ip pref 10 handle $tnum: u32 divisor 1" ); - } + emit( "\nrun_tc filter add dev $device parent $devnum:0 protocol ip pref 10 handle $tnum: u32 divisor 1" ); # # And link to it using the current contents of $rule # - emit( "run_tc $rule\\" , + emit( "\nrun_tc $rule\\" , " link $tnum:0 offset at 0 mask 0x0F00 shift 6 plus 0 eat" ); # # The rule to match the port(s) will be inserted into the new table # $rule = "filter add dev $device protocol ip parent $devnum:0 pref 10 u32 ht $tnum:0"; - unless ( $port eq '-' ) { - fatal_error "Only TCP, UDP, SCTP and ICMP may specify DEST PORT" - unless $protonumber == TCP || $protonumber == UDP || $protonumber == SCTP || $protonumber == ICMP; - - if ( $protonumber == ICMP ) { - my ( $icmptype , $icmpcode ) = split '//', validate_icmp( $port ); - - $icmptype = in_hex2 numeric_value $icmptype; - $icmpcode = in_hex2 numeric_value $icmpcode if defined $icmpcode; - - $rule .= "\\\n match u8 $icmptype 0xff at nexthdr+0"; - $rule .= "\\\n match u8 $icmpcode 0xff at nexthdr+1" if defined $icmpcode; - } else { - my $portnumber = in_hex8 validate_port( $protonumber , $port ); - $rule .= "\\\n match u32 $portnumber 0x0000ffff at nexthdr+0"; - } - } - - unless ( $sport eq '-' ) { + if ( $portlist eq '-' ) { fatal_error "Only TCP, UDP and SCTP may specify SOURCE PORT" unless $protonumber == TCP || $protonumber == UDP || $protonumber == SCTP; - - my $portnumber = in_hex4 validate_port( $protonumber , $sport ); - - $rule .= "\\\n match u32 ${portnumber}0000 0xffff0000 at nexthdr+0"; + + for my $sport ( split_list $sportlist , 'port list' ) { + my $portnumber = in_hex4 validate_port( $protonumber , $sport ); + emit( "\nrun_tc $rule\\" , + " match u32 ${portnumber}0000 0xffff0000 at nexthdr+0\\" , + " flowid $devref->{number}:$class" ); + } + } else { + fatal_error "Only TCP, UDP, SCTP and ICMP may specify DEST PORT" + unless $protonumber == TCP || $protonumber == UDP || $protonumber == SCTP || $protonumber == ICMP; + + for my $port( split_list $portlist, 'port list' ) { + if ( $protonumber == ICMP ) { + fatal_error "Only TCP, UDP and SCTP may specify SOURCE PORT" if $sportlist ne '-'; + my ( $icmptype , $icmpcode ) = split '//', validate_icmp( $port ); + + $icmptype = in_hex2 numeric_value $icmptype; + $icmpcode = in_hex2 numeric_value $icmpcode if defined $icmpcode; + + my $rule1 = " match u8 $icmptype 0xff at nexthdr+0"; + $rule1 .= "\\\n match u8 $icmpcode 0xff at nexthdr+1" if defined $icmpcode; + emit( "\nrun_tc ${rule}\\" , + "$rule1\\" , + " flowid $devref->{number}:$class" ); + } else { + my $portnumber = in_hex8 validate_port( $protonumber , $port ); + my $rule1 = "match u32 $portnumber 0x0000ffff at nexthdr+0"; + if ( $sportlist eq '-' ) { + emit( "\nrun_tc ${rule}\\" , + " $rule1\\" , + " flowid $devref->{number}:$class" ); + } else { + for my $sport ( split_list $sportlist , 'port list' ) { + my $portnumber = in_hex4 validate_port( $protonumber , $sport ); + emit( "\nrun_tc ${rule}\\", + " $rule1\\" , + " match u32 ${portnumber}0000 0xffff0000 at nexthdr+0\\" , + " flowid $devref->{number}:$class" ); + } + } + } + } } } - emit( "run_tc $rule\\" , - " flowid $devref->{number}:$class" , - '' ); + emit ''; progress_message " TC Filter \"$currentline\" $done";