diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index 919bb66b7..f2cd69f07 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -513,7 +513,7 @@ our $mode; # # A reference to this rule is returned when we try to push a rule onto a 'complete' chain # -our $dummyrule = { simple => 1, mode => CAT_MODE }; +our $dummyrule = { simple => 1, matches => [], mode => CAT_MODE }; # # Address Family @@ -619,6 +619,7 @@ our %opttype = ( rule => CONTROL, mode => CONTROL, cmdlevel => CONTROL, simple => CONTROL, + matches => CONTROL, i => UNIQUE, s => UNIQUE, @@ -634,6 +635,8 @@ our %opttype = ( rule => CONTROL, policy => MATCH, state => EXCLUSIVE, + 'conntrack --ctstate' => + EXCLUSIVE, conntrack => COMPLEX, @@ -831,12 +834,13 @@ sub set_rule_option( $$$ ) { } } else { $ruleref->{$option} = $value; + push @{$ruleref->{matches}}, $option; } } sub transform_rule( $;\$ ) { my ( $input, $completeref ) = @_; - my $ruleref = { mode => CAT_MODE, target => '' }; + my $ruleref = { mode => CAT_MODE, matches => [], target => '' }; my $simple = 1; my $target = ''; my $jump = ''; @@ -950,11 +954,17 @@ sub format_option( $$ ) { $rule; } +sub debug() { + return 1; +} + sub format_rule( $$;$ ) { my ( $chainref, $ruleref, $suppresshdr ) = @_; return $ruleref->{cmd} if exists $ruleref->{cmd}; + debug if $chainref->{name} eq 'drct-net'; + my $rule = $suppresshdr ? '' : "-A $chainref->{name}"; for ( @unique_options ) { @@ -971,10 +981,19 @@ sub format_rule( $$;$ ) { } } - $rule .= format_option( 'state', $ruleref->{state} ) if defined $ruleref->{state}; $rule .= format_option( 'policy', $ruleref->{policy} ) if defined $ruleref->{policy}; - $rule .= format_option( $_, $ruleref->{$_} ) for sort ( grep ! $opttype{$_}, keys %{$ruleref} ); + if ( defined ( my $state = $ruleref->{'conntrack --ctstate'} ) ) { + $rule .= format_option( 'conntrack --ctstate' , $state ); + } elsif ( defined $ruleref->{state} ) { + $rule .= format_option( 'state', $ruleref->{state} ); + } + + my %done; + + for ( grep ! $opttype{$_}, @{$ruleref->{matches}} ) { + $rule .= format_option( $_, $ruleref->{$_} ) unless $done{$_}++; + } if ( $ruleref->{target} ) { $rule .= join( ' ', " -$ruleref->{jump}", $ruleref->{target} ); @@ -1041,6 +1060,12 @@ sub merge_rules( $$$ ) { set_rule_option ( $toref, 'state', $fromref->{state} ) if $fromref->{state}; } + unless ( $toref->{'conntrack --ctstate'} ) { + set_rule_option( $toref, + 'conntrack --ctstate', + $fromref->{'conntrack --ctstate'} ) if $fromref->{'conntrack --ctstate'}; + } + set_rule_option( $toref, 'policy', $fromref->{policy} ) if exists $fromref->{policy}; unless ( $toref->{comment} ) { @@ -1302,6 +1327,7 @@ sub push_matches { } else { $ruleref->{$option} = $value; $dont_optimize ||= $option =~ /^[piosd]$/ && $value =~ /^!/; + push @{$ruleref->{matches}}, $option; } } @@ -1313,7 +1339,7 @@ sub push_irule( $$$;@ ) { ( $target, my $targetopts ) = split ' ', $target, 2; - my $ruleref = {}; + my $ruleref = { matches => [] }; $ruleref->{mode} = ( $ruleref->{cmdlevel} = $chainref->{cmdlevel} ) ? CMD_MODE : CAT_MODE; @@ -1476,7 +1502,12 @@ sub clone_rule( $ ) { my $newruleref = {}; while ( my ( $key, $value ) = each %$oldruleref ) { - $newruleref->{$key} = $value; + if ( reftype $value ) { + my @array = @$value; + $newruleref->{$key} = \@array; + } else { + $newruleref->{$key} = $value; + } } $newruleref; @@ -3548,6 +3579,20 @@ sub combine_dports { $baseref->{'multiport'} = '--dports ' . join( ',' , @ports ); } + my @matches = @{$baseref->{matches}}; + + $baseref->{matches} = []; + + my $switched = 0; + + for ( @matches ) { + if ( $_ eq 'dport' || $_ eq 'sport' ) { + push @{$baseref->{matches}}, 'multiport' unless $switched++; + } else { + push @{$baseref->{matches}}, $_; + } + } + $baseref->{comment} = $comment if $comment; trace ( $chainref, 'R', $basenum, $baseref ) if $debug; diff --git a/Shorewall/Perl/Shorewall/Providers.pm b/Shorewall/Perl/Shorewall/Providers.pm index 8b2c9e396..3960d586c 100644 --- a/Shorewall/Perl/Shorewall/Providers.pm +++ b/Shorewall/Perl/Shorewall/Providers.pm @@ -1965,12 +1965,14 @@ sub handle_stickiness( $ ) { $rule2 = clone_rule( $_ ); clear_rule_target( $rule2 ); - set_rule_option( $rule2, 'mark', "--mark 0/$mask -m recent --name $list --remove" ); + set_rule_option( $rule2, 'mark', "--mark 0\/$mask" ); + set_rule_option( $rule2, 'recent', "--name $list --remove" ); } else { $rule1 = clone_rule( $_ ); clear_rule_target( $rule1 ); - set_rule_option( $rule1, 'mark', "--mark $mark\/$mask -m recent --name $list --set" ); + set_rule_option( $rule1, 'mark', "--mark $mark\/$mask" ); + set_rule_option( $rule1, 'recent', "--name $list --set" ); $rule2 = ''; } @@ -1990,32 +1992,22 @@ sub handle_stickiness( $ ) { for my $chainref ( $stickoref, $setstickoref ) { if ( $chainref->{name} eq 'sticko' ) { - $rule1 = {}; - - while ( my ( $key, $value ) = each %$_ ) { - $rule1->{$key} = $value; - } + $rule1 = clone_rule $_; set_rule_target( $rule1, 'MARK', "--set-mark $mark" ); set_rule_option( $rule1, 'recent', " --name $list --rdest --update --seconds 300" ); - $rule2 = {}; - - while ( my ( $key, $value ) = each %$_ ) { - $rule2->{$key} = $value; - } + $rule2 = clone_rule $_; clear_rule_target( $rule2 ); - set_rule_option ( $rule2, 'mark', "--mark 0\/$mask -m recent --name $list --rdest --remove" ); + set_rule_option ( $rule2, 'mark', "--mark 0\/$mask" ); + set_rule_option ( $rule2, 'recent', "--name $list --rdest --remove" ); } else { - $rule1 = {}; - - while ( my ( $key, $value ) = each %$_ ) { - $rule1->{$key} = $value; - } + $rule1 = clone_rule $_; clear_rule_target( $rule1 ); - set_rule_option ( $rule1, 'mark', "--mark $mark -m recent --name $list --rdest --set" ); + set_rule_option ( $rule1, 'mark', "--mark $mark" ); + set_rule_option ( $rule1, 'recent', "--name $list --rdest --set" ); $rule2 = ''; } diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index ef1420738..6b38c1649 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -2080,8 +2080,9 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { my $inchain = ''; # Set to true when a chain reference is passed. my $normalized_target; my $normalized_action; - my $blacklist = ( $section == BLACKLIST_SECTION ); - my $matches = $rule; + my $blacklist = ( $section == BLACKLIST_SECTION ); + my $matches = $rule; + my $raw_matches = ''; if ( $inchain = defined $chainref ) { ( $inaction, undef, undef, undef ) = split /:/, $normalized_action = $chainref->{action}, 4 if $chainref->{action}; @@ -2093,13 +2094,13 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { my $inline_matches = get_inline_matches; if ( $inline_matches =~ /^(.*\s+)-j\s+(.+)$/ ) { - $matches .= $1; + $raw_matches .= $1; $action = $2; my ( $target ) = split ' ', $action; fatal_error "Unknown jump target ($action)" unless $targets{$target}; fatal_error "INLINE may not have a parameter when '-j' is specified in the free-form area" if $param ne ''; } else { - $matches .= "$inline_matches "; + $raw_matches .= "$inline_matches "; if ( $param eq '' ) { $action = $loglevel ? 'LOG' : ''; @@ -2109,8 +2110,6 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { $param = '' unless defined $param; } } - - $rule = $matches; } # # Determine the validity of the action @@ -2133,7 +2132,7 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { my $generated = process_macro( $basictarget, $chainref, - $rule, + $rule . $raw_matches, $target, $current_param, $source, @@ -2477,7 +2476,7 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { my $generated = process_inline( $basictarget, $chainref, - $rule, + $rule . $raw_matches, $loglevel, $target, $current_param, @@ -2519,6 +2518,7 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { do_time( $time ) , do_headers( $headers ) , do_condition( $condition , $chain ) , + $raw_matches , ); } elsif ( $section & ( ESTABLISHED_SECTION | INVALID_SECTION | RELATED_SECTION | UNTRACKED_SECTION ) ) { $rule .= join( '', @@ -2531,6 +2531,7 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { do_headers( $headers ) , do_condition( $condition , $chain ) , do_helper( $helper ) , + $raw_matches , ); } else { $rule .= join( '', @@ -2542,6 +2543,7 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { do_time( $time ) , do_headers( $headers ) , do_condition( $condition , $chain ) , + $raw_matches , ); } @@ -2615,7 +2617,8 @@ sub process_rule ( $$$$$$$$$$$$$$$$$$$ ) { do_ratelimit( $ratelimit, 'ACCEPT' ), do_user $user, do_test( $mark , $globals{TC_MASK} ), - do_condition( $condition , $chain ) + do_condition( $condition , $chain ), + $raw_matches, ); $loglevel = ''; $action = 'ACCEPT';