From 7e1a310929fa42a47c9610187125be25f83e5f71 Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Fri, 3 Jan 2014 09:35:34 -0800 Subject: [PATCH] Implement ipset matches in tcfilters Signed-off-by: Tom Eastep --- Shorewall/Perl/Shorewall/Config.pm | 8 ++++ Shorewall/Perl/Shorewall/Tc.pm | 70 +++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Config.pm b/Shorewall/Perl/Shorewall/Config.pm index 4e818efb6..0b4025ad8 100644 --- a/Shorewall/Perl/Shorewall/Config.pm +++ b/Shorewall/Perl/Shorewall/Config.pm @@ -374,6 +374,7 @@ our %capdesc = ( NAT_ENABLED => 'NAT', CONDITION_MATCH => 'Condition Match', IPTABLES_S => 'iptables -S', BASIC_FILTER => 'Basic Filter', + BASIC_EMATCH => 'Basic Filter ematch', CT_TARGET => 'CT Target', STATISTIC_MATCH => 'Statistics Match', @@ -953,6 +954,7 @@ sub initialize( $;$$) { CONDITION_MATCH => undef, IPTABLES_S => undef, BASIC_FILTER => undef, + BASIC_EMATCH => undef, CT_TARGET => undef, STATISTIC_MATCH => undef, IMQ_TARGET => undef, @@ -4270,6 +4272,10 @@ sub Basic_Filter() { $tc && system( "$tc filter add basic help 2>&1 | grep -q ^Usage" ) == 0; } +sub Basic_Ematch() { + $tc && have_capability 'BASIC_FILTER' && system( "$tc filter add basic help 2>&1 | egrep -q match" ) == 0; +} + sub Fwmark_Rt_Mask() { $ip && system( "$ip rule add help 2>&1 | grep -q /MASK" ) == 0; } @@ -4372,6 +4378,7 @@ our %detect_capability = AUDIT_TARGET => \&Audit_Target, ADDRTYPE => \&Addrtype, BASIC_FILTER => \&Basic_Filter, + BASIC_EMATCH => \&Basic_Ematch, CHECKSUM_TARGET => \&Checksum_Target, CLASSIFY_TARGET => \&Classify_Target, CONDITION_MATCH => \&Condition_Match, @@ -4585,6 +4592,7 @@ sub determine_capabilities() { $capabilities{CONDITION_MATCH} = detect_capability( 'CONDITION_MATCH' ); $capabilities{IPTABLES_S} = detect_capability( 'IPTABLES_S' ); $capabilities{BASIC_FILTER} = detect_capability( 'BASIC_FILTER' ); + $capabilities{BASIC_EMATCH} = detect_capability( 'BASIC_EMATCH' ); $capabilities{CT_TARGET} = detect_capability( 'CT_TARGET' ); $capabilities{STATISTIC_MATCH} = detect_capability( 'STATISTIC_MATCH' ); $capabilities{IMQ_TARGET} = detect_capability( 'IMQ_TARGET' ); diff --git a/Shorewall/Perl/Shorewall/Tc.pm b/Shorewall/Perl/Shorewall/Tc.pm index c13e0f996..06cc3f6d0 100644 --- a/Shorewall/Perl/Shorewall/Tc.pm +++ b/Shorewall/Perl/Shorewall/Tc.pm @@ -1908,6 +1908,36 @@ sub validate_tc_class( ) { my %validlengths = ( 32 => '0xffe0', 64 => '0xffc0', 128 => '0xff80', 256 => '0xff00', 512 => '0xfe00', 1024 => '0xfc00', 2048 => '0xf800', 4096 => '0xf000', 8192 => '0xe000' ); +# +# Handle an ipset name in the SOURCE or DEST columns of a filter +# +sub handle_ematch( $$ ) { + my ( $setname, $option ) = @_; + + my $options = $option; + + require_capability 'BASIC_EMATCH', 'IPSets', ''; + + if ( $setname =~ /^(.*)\[([1-6])\]$/ ) { + $setname = $1; + my $count = $2; + + $options .= ",$option" while --$count > 0; + } elsif ( $setname =~ /^(.*)\[((?:src|dst)(?:,(?:src|dst))){0,5}\]$/ ) { + $setname = $1; + $options = $2 if supplied $2; + + my @options = split /,/, $options; + + if ( $config{IPSET_WARNINGS} ) { + my %typemap = ( src => 'Source', dst => 'Destination' ); + warning_message( "The '$options[0]' ipset flag is used in a $typemap{$option} column" ), unless $options[0] eq $option; + } + } + + return " ipset( $setname, $options )"; +} + # # Process a record from the tcfilters file # @@ -1925,6 +1955,8 @@ sub process_tc_filter1( $$$$$$$$$ ) { my $devref; + my $ematch = ''; + if ( $device =~ /^[\da-fA-F]+$/ && ! $tcdevices{$device} ) { ( $device, $devref ) = dev_by_number( hex_value( $device ) ); } else { @@ -1970,15 +2002,27 @@ sub process_tc_filter1( $$$$$$$$$ ) { my $rule = "filter add dev $devref->{physical} protocol $ip parent $devnum:0 prio $prio u32"; if ( $source ne '-' ) { - my ( $net , $mask ) = decompose_net( $source ); - $rule .= "\\\n match $ip32 src $net/$mask"; - $have_rule = 1; + if ( $source =~ /^\+/ ) { + $ematch = join( ' ', 'match', handle_ematch( $source, 'src' ) ); + } else { + my ( $net , $mask ) = decompose_net( $source ); + $rule .= "\\\n match $ip32 src $net/$mask"; + $have_rule = 1; + } } if ( $dest ne '-' ) { - my ( $net , $mask ) = decompose_net( $dest ); - $rule .= "\\\n match $ip32 dst $net/$mask"; - $have_rule = 1; + if ( $dest =~ /^\+/ ) { + if ( $ematch ) { + $ematch = join( ' ', $ematch, handle_ematch( $dest, 'dst' ) ); + } else { + $ematch = join( ' ', 'match', handle_ematch( $dest, 'dst' ) ); + } + } else { + my ( $net , $mask ) = decompose_net( $dest ); + $rule .= "\\\n match $ip32 dst $net/$mask"; + $have_rule = 1; + } } if ( $tos ne '-' ) { @@ -2019,13 +2063,25 @@ sub process_tc_filter1( $$$$$$$$$ ) { } } + if ( $ematch ) { + if ( $have_rule ) { + my $tnum = in_hex3 $devref->{tablenumber}++; + push @$filtersref, ( "\nrun_tc $rule\\" , + " link $tnum:0" ); + $rule = "filter add dev $devref->{physical} protocol $ip parent $devnum:0 prio $prio basic ht $tnum:0 match ${ematch}"; + } else { + $rule = "filter add dev $devref->{physical} protocol $ip parent $devnum:0 prio $prio basic match$ ${ematch}"; + $have_rule = 1; + } + } + if ( $portlist eq '-' && $sportlist eq '-' ) { if ( $have_rule ) { push @$filtersref , ( "\nrun_tc $rule\\" , " flowid $devnum:$class" , '' ); } else { - warning_message "Degenerate tcfilter ignored"; + warning_message "Degenerate tcfilter ignored" unless $ematch; } } else { fatal_error "Ports may not be specified without a PROTO" unless $protonumber;