diff --git a/New/Shorewall/Tc.pm b/New/Shorewall/Tc.pm new file mode 100644 index 000000000..9b66e31af --- /dev/null +++ b/New/Shorewall/Tc.pm @@ -0,0 +1,225 @@ +package Shorewall::Tc; +require Exporter; +use Shorewall::Common; +use Shorewall::Config; +use Shorewall::Zones; +use Shorewall::Chains; + +use strict; + +our @ISA = qw(Exporter); +our @EXPORT = qw( process_tcrules ); +our @EXPORT_OK = qw( process_tc_rule ); +our @VERSION = 1.00; + +my %tcs = ( t => { chain => 'tcpost', + connmark => 0, + fw => 1 + } , + ct => { chain => 'tcpost' , + target => 'CONNMARK --set-mark' , + connmark => 1 , + fw => 1 + } , + c => { target => 'CONNMARK --set-mark' , + connmark => 1 , + fw => 1 + } , + p => { chain => 'tcpre' , + connmark => 0 , + fw => 0 + } , + cp => { chain => 'tcpre' , + target => 'CONNMARK --set-mark' , + connmark => 1 , + fw => 0 + } , + f => { chain => 'tcfor' , + connmark => 0 , + fw => 0 + } , + cf => { chain => 'tcfor' , + fw => 0 , + connmark => 1 , + } , + t => { chain => 'tcpost' , + connmark => 0 , + fw => 0 + } , + ct => { chain => 'tcpost' , + target => 'CONNMARK --set-mark' , + connmark => 1 , + fw => 0 + } , + c => { target => 'CONNMARK --set-mark' , + connmark => 1 , + fw => 0 + } + ); + +use constant { NOMARK => 0 , + SMALLMARK => 1 , + HIGHMARK => 2 + }; + +my @tccmd = ( { pattern => 'SAVE' , + target => 'CONNMARK --save-mark --mask' , + mark => SMALLMARK , + mask => '0xFF' + } , + { pattern => 'RESTORE' , + target => 'CONNMARK --restore-mark --mask' , + mark => SMALLMARK , + mask => '0xFF' + } , + { pattern => 'CONTINUE', + target => 'RETURN' , + mark => NOMARK , + mask => '' + } , + { pattern => '\|.*' , + target => 'MARK --or-mark' , + mark => HIGHMARK , + mask => '' } , + { pattern => '&.*' , + target => 'MARK --and-mark ' , + mark => HIGHMARK , + mask => '' + } + ); + +sub process_tc_rule( $$$$$$$$$$ ) { + my ( $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $extra ) = @_; + + my $original_mark = $mark; + + ( $mark, my $designator ) = split /:/, $mark; + + my $chain = $env{MARKING_CHAIN}; + my $target = 'MARK --set-mark'; + my $tcsref; + my $connmark = 0; + my $classid = 0; + + if ( $source ) { + if ( $source eq $firewall_zone ) { + $chain = 'tcout'; + $source = ''; + } else { + $chain = 'tcout' if $source =~ s/^($firewall_zone)://; + } + } + + if ( $designator ) { + $tcsref = $tcs{$designator}; + + if ( $tcsref ) { + if ( $chain eq 'tcout' ) { + fatal_error "Invalid chain designator for source $firewall_zone; rule \"$line\"" unless $tcsref->{fw}; + } + + $chain = $tcsref->{chain} if $tcsref->{chain}; + $target = $tcsref->{target} if $tcsref->{target}; + $mark = "$mark/0xFF" if $connmark = $tcsref->{connmark}; + + } else { + fatal_error "Invalid MARK ($original_mark) in rule \"$line\"" unless $mark =~ /^([0-9]+|0x[0-9a-f]+)$/ and $designator =~ /^([0-9]+|0x[0-9a-f]+)$/; + $chain = 'tcpost'; + $classid = 1; + $mark = $original_mark; + $target = 'CLASSIFY --set-class'; + } + } + + my $mask = 0xffff; + + my ($cmd, $rest) = split '/', $mark; + + unless ( $classid ) + { + MARK: + { + PATTERN: + for my $tccmd ( @tccmd ) { + if ( $cmd =~ /^($tccmd->{pattern})$/ ) { + fatal_error "$mark not valid with :C[FP]" if $connmark; + + $target = "$tccmd->{target} "; + my $marktype = $tccmd->{mark}; + + $mark =~ s/^[!&]//; + + if ( $rest ) { + fatal_error "Invalid MARK ($original_mark)" if $marktype == NOMARK; + + $mark = $rest if $tccmd->{mask}; + + if ( $marktype == SMALLMARK ) { + verify_small_mark $mark; + } else { + validate_mark $mark; + } + } elsif ( $tccmd->{mask} ) { + $mark = $tccmd->{mask}; + } + + last MARK; + } + } + } + + validate_mark $mark; + + fatal_error 'Marks < 256 may not be set in the PREROUTING chain when HIGH_ROUTE_MARKS=Yes' + if $cmd || $chain eq 'tcpre' || numeric_value( $cmd ) <= 0xFF || $config{HIGH_ROUTE_MARKS}; + } + + expand_rule + ensure_chain( 'mangle' , $chain ) , + do_proto( $proto, $ports, $sports) . do_test( $testval, $mask ) , + $source , + $dest , + '' , + "-j $target $mark" , + '' , + '' , + ''; + + progress_message " TC Rule \"$line\" $done"; + +} + +# +# Process the tcrules file +# +sub process_tcrules() { + + open TC, "$ENV{TMP_DIR}/tcrules" or fatal_error "Unable to open stripped tcrules file: $!"; + + while ( $line = ) { + + chomp $line; + $line =~ s/\s+/ /g; + + my ( $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $extra ) = split /\s+/, $line; + + if ( $mark eq 'COMMENT' ) { + if ( $capabilities{COMMENTS} ) { + ( $comment = $line ) =~ s/^\s*COMMENT\s*//; + $comment =~ s/\s*$//; + } else { + warning_message "COMMENT ignored -- requires comment support in iptables/Netfilter"; + } + } else { + fatal_error "Invalid tcrule: \"$line\"" if $extra; + process_tc_rule $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos + } + + } + + close TC; + + $comment = ''; +} + +1; diff --git a/New/compiler.pl b/New/compiler.pl index c31e689e7..3f1a834e0 100755 --- a/New/compiler.pl +++ b/New/compiler.pl @@ -9,6 +9,7 @@ use Shorewall::Zones; use Shorewall::Interfaces; use Shorewall::Hosts; use Shorewall::Nat; +use Shorewall::Tc; # # Set to one if we find a SECTION @@ -900,216 +901,6 @@ sub complete_standard_chain ( $$$ ) { policy_rules $stdchainref , $policy , $loglevel, $default; } -my %tcs = ( t => { chain => 'tcpost', - connmark => 0, - fw => 1 - } , - ct => { chain => 'tcpost' , - target => 'CONNMARK --set-mark' , - connmark => 1 , - fw => 1 - } , - c => { target => 'CONNMARK --set-mark' , - connmark => 1 , - fw => 1 - } , - p => { chain => 'tcpre' , - connmark => 0 , - fw => 0 - } , - cp => { chain => 'tcpre' , - target => 'CONNMARK --set-mark' , - connmark => 1 , - fw => 0 - } , - f => { chain => 'tcfor' , - connmark => 0 , - fw => 0 - } , - cf => { chain => 'tcfor' , - fw => 0 , - connmark => 1 , - } , - t => { chain => 'tcpost' , - connmark => 0 , - fw => 0 - } , - ct => { chain => 'tcpost' , - target => 'CONNMARK --set-mark' , - connmark => 1 , - fw => 0 - } , - c => { target => 'CONNMARK --set-mark' , - connmark => 1 , - fw => 0 - } - ); - -use constant { NOMARK => 0 , - SMALLMARK => 1 , - HIGHMARK => 2 - }; - -my @tccmd = ( { pattern => 'SAVE' , - target => 'CONNMARK --save-mark --mask' , - mark => SMALLMARK , - mask => '0xFF' - } , - { pattern => 'RESTORE' , - target => 'CONNMARK --restore-mark --mask' , - mark => SMALLMARK , - mask => '0xFF' - } , - { pattern => 'CONTINUE', - target => 'RETURN' , - mark => NOMARK , - mask => '' - } , - { pattern => '\|.*' , - target => 'MARK --or-mark' , - mark => HIGHMARK , - mask => '' } , - { pattern => '&.*' , - target => 'MARK --and-mark ' , - mark => HIGHMARK , - mask => '' - } - ); - -sub process_tc_rule( $$$$$$$$$$ ) { - my ( $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $extra ) = @_; - - my $original_mark = $mark; - - ( $mark, my $designator ) = split /:/, $mark; - - my $chain = $env{MARKING_CHAIN}; - my $target = 'MARK --set-mark'; - my $tcsref; - my $connmark = 0; - my $classid = 0; - - if ( $source ) { - if ( $source eq $firewall_zone ) { - $chain = 'tcout'; - $source = ''; - } else { - $chain = 'tcout' if $source =~ s/^($firewall_zone)://; - } - } - - if ( $designator ) { - $tcsref = $tcs{$designator}; - - if ( $tcsref ) { - if ( $chain eq 'tcout' ) { - fatal_error "Invalid chain designator for source $firewall_zone; rule \"$line\"" unless $tcsref->{fw}; - } - - $chain = $tcsref->{chain} if $tcsref->{chain}; - $target = $tcsref->{target} if $tcsref->{target}; - $mark = "$mark/0xFF" if $connmark = $tcsref->{connmark}; - - } else { - fatal_error "Invalid MARK ($original_mark) in rule \"$line\"" unless $mark =~ /^([0-9]+|0x[0-9a-f]+)$/ and $designator =~ /^([0-9]+|0x[0-9a-f]+)$/; - $chain = 'tcpost'; - $classid = 1; - $mark = $original_mark; - $target = 'CLASSIFY --set-class'; - } - } - - my $mask = 0xffff; - - my ($cmd, $rest) = split '/', $mark; - - unless ( $classid ) - { - MARK: - { - PATTERN: - for my $tccmd ( @tccmd ) { - if ( $cmd =~ /^($tccmd->{pattern})$/ ) { - fatal_error "$mark not valid with :C[FP]" if $connmark; - - $target = "$tccmd->{target} "; - my $marktype = $tccmd->{mark}; - - $mark =~ s/^[!&]//; - - if ( $rest ) { - fatal_error "Invalid MARK ($original_mark)" if $marktype == NOMARK; - - $mark = $rest if $tccmd->{mask}; - - if ( $marktype == SMALLMARK ) { - verify_small_mark $mark; - } else { - validate_mark $mark; - } - } elsif ( $tccmd->{mask} ) { - $mark = $tccmd->{mask}; - } - - last MARK; - } - } - } - - validate_mark $mark; - - fatal_error 'Marks < 256 may not be set in the PREROUTING chain when HIGH_ROUTE_MARKS=Yes' - if $cmd || $chain eq 'tcpre' || numeric_value( $cmd ) <= 0xFF || $config{HIGH_ROUTE_MARKS}; - } - - expand_rule - ensure_chain( 'mangle' , $chain ) , - do_proto( $proto, $ports, $sports) . do_test( $testval, $mask ) , - $source , - $dest , - '' , - "-j $target $mark" , - '' , - '' , - ''; - - progress_message " TC Rule \"$line\" $done"; - -} - -# -# Process the tcrules file -# -sub process_tcrules() { - - open TC, "$ENV{TMP_DIR}/tcrules" or fatal_error "Unable to open stripped tcrules file: $!"; - - while ( $line = ) { - - chomp $line; - $line =~ s/\s+/ /g; - - my ( $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos , $extra ) = split /\s+/, $line; - - if ( $mark eq 'COMMENT' ) { - if ( $capabilities{COMMENTS} ) { - ( $comment = $line ) =~ s/^\s*COMMENT\s*//; - $comment =~ s/\s*$//; - } else { - warning_message "COMMENT ignored -- requires comment support in iptables/Netfilter"; - } - } else { - fatal_error "Invalid tcrule: \"$line\"" if $extra; - process_tc_rule $mark, $source, $dest, $proto, $ports, $sports, $user, $testval, $length, $tos - } - - } - - close TC; - - $comment = ''; -} - my %maclist_targets = ( ACCEPT => { target => 'RETURN' , mangle => 1 } , REJECT => { target => 'reject' , mangle => 0 } , DROP => { target => 'DROP' , mangle => 1 } );