From 895428c7c173016f2789607aac9ce5dba79e967e Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Sun, 10 Mar 2024 10:30:33 -0700 Subject: [PATCH] Handle the case where a single host exclusion specifies multiple nets Also reorganize the exclusion code to make it self-contained within add_common_rules() Signed-off-by: Tom Eastep --- Shorewall/Perl/Shorewall/Misc.pm | 113 +++++++++++++++++-------------- 1 file changed, 62 insertions(+), 51 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Misc.pm b/Shorewall/Perl/Shorewall/Misc.pm index f0db818ac..9dfdec581 100644 --- a/Shorewall/Perl/Shorewall/Misc.pm +++ b/Shorewall/Perl/Shorewall/Misc.pm @@ -710,42 +710,6 @@ sub create_docker_rules() { sub setup_mss(); -sub add_ipset_dbl_ijump( $$$@) { - my ( $chainref, $target, $ipset_dir ) = ( shift, shift, shift ); - - add_ijump_extended( $chainref, j => $target, $origin{DYNAMIC_BLACKLIST}, @_, "set --match-set" => $ipset_dir ); -} - -sub add_host_exclusion_ijump( $$$@ ) { - my ( $chainref, $dest, $hostref, $src ) = ( shift, shift, shift, shift ); - - my $nets = $hostref->{hosts}; - my $origin = $hostref->{origin}; - - for my $net ( @$nets ) { - if ( $src ) { - add_ijump_extended( $chainref , j => $dest, $origin, imatch_source_net( $net ), @_ ) - } else { - add_ijump_extended( $chainref , j => $dest, $origin, imatch_dest_net( $net ), @_ ); - } - } -} - -sub add_dbl_exclusion_ijump( $$$$@ ) { - my ( $chainref, $dest, $hostref, $ipset, $src ) = ( shift, shift, shift, shift, shift ); - - my $nets = $hostref->{hosts}; - my $origin = $hostref->{origin}; - - for my $net ( @$nets ) { - if ( $src ) { - add_ijump_extended( $chainref , j => $dest, $origin, imatch_source_net( "!$net" ), @_, "set --match-set" => "$ipset src" ); - } else { - add_ijump_extended( $chainref , j => $dest, $origin, imatch_dest_net( "!$net" ), @_, "set --match-set" => "$ipset dst" ); - } - } -} - # # Add rules generated by .conf options and interface options # @@ -897,12 +861,13 @@ sub add_common_rules ( $ ) { add_ijump_extended( $filter_table->{OUTPUT} , j => 'ACCEPT', $origin{FASTACCEPT}, state_imatch $faststate ) } - my $policy = $config{SFILTER_DISPOSITION}; - $level = $config{SFILTER_LOG_LEVEL}; - $tag = $config{SFILTER_LOG_TAG}; - my $audit = $policy =~ s/^A_//; - my @ipsec = have_ipsec ? ( policy => '--pol none --dir in' ) : (); - my $origin = $origin{SFILTER_DISPOSITION}; + my $policy = $config{SFILTER_DISPOSITION}; + $level = $config{SFILTER_LOG_LEVEL}; + $tag = $config{SFILTER_LOG_TAG}; + my $audit = $policy =~ s/^A_//; + my $have_ipsec = have_ipsec; + my @ipsec = $have_ipsec ? ( policy => '--pol none --dir in' ) : (); + my $origin = $origin{SFILTER_DISPOSITION}; if ( $level || $audit ) { # @@ -1015,9 +980,55 @@ sub add_common_rules ( $ ) { # # Dynamic blacklisting # - my @nodbl = @{$interfaceref->{nodbl}}; - my $have_ipsec = have_ipsec; + # + # Generate a rule to match the DBL ipset - called when there is no exclusion + # + sub add_ipset_dbl_ijump( $$$@) { + my ( $chainref, $target, $ipset_dir ) = ( shift, shift, shift ); + + add_ijump_extended( $chainref, j => $target, $origin{DYNAMIC_BLACKLIST}, @_, "set --match-set" => $ipset_dir ); + } + + # + # Add a simple exclusion rule - called when there is more than one excluded subnet. Excluded subnets cause the + # current chain to be exited. + # + sub add_host_exclusion_ijump( $$$@ ) { + my ( $chainref, $hostref, $src ) = ( shift, shift, shift ); + + my $nets = $hostref->{hosts}; + my $origin = $hostref->{origin}; + + for my $net ( @$nets ) { + if ( $src ) { + add_ijump_extended( $chainref , j => 'RETURN', $origin, imatch_source_net( $net ), @_ ) + } else { + add_ijump_extended( $chainref , j => 'RETURN', $origin, imatch_dest_net( $net ), @_ ); + } + } + } + + # + # This one is called when there is a single excluded network. The generated rule tests against the DBL ipset + # unless the source or destination address matches the set + # + sub add_dbl_exclusion_ijump( $$$$@ ) { + my ( $chainref, $dest, $hostref, $ipset, $src ) = ( shift, shift, shift, shift, shift ); + + my $nets = $hostref->{hosts}; + my $origin = $hostref->{origin}; + + for my $net ( @$nets ) { + if ( $src ) { + add_ijump_extended( $chainref , j => $dest, $origin, imatch_source_net( "!$net" ), @_, "set --match-set" => "$ipset src" ); + } else { + add_ijump_extended( $chainref , j => $dest, $origin, imatch_dest_net( "!$net" ), @_, "set --match-set" => "$ipset dst" ); + } + } + } + + my @nodbl = @{$interfaceref->{nodbl}}; my @in_policy = $have_ipsec ? ( policy => "--pol none --dir in" ) : (); my @out_policy = $have_ipsec ? ( policy => "--pol none --dir out" ) : (); @@ -1026,13 +1037,15 @@ sub add_common_rules ( $ ) { # # We have blacklisting exclusions defined in the hosts file # - if ( @nodbl > 1 ) { + my $hostref = $nodbl[0]; + + if ( @nodbl > 1 || @{$hostref->{hosts}} > 1 ) { # # Complex case - we need to create an intermediate chain # $chainref = new_standard_chain( nodbl_src_chain( $interface )); - for my $hostref (@nodbl) { + for $hostref (@nodbl) { add_host_exclusion_ijump( $chainref, 'RETURN', $hostref, 1 ); } @@ -1044,7 +1057,7 @@ sub add_common_rules ( $ ) { if ( $dbl_src_target ne $dbl_dst_target ) { $chainref = new_standard_chain( nodbl_dst_chain( $interface )); - for my $hostref (@nodbl) { + for $hostref (@nodbl) { add_host_exclusion_ijump( $chainref, 'RETURN', $hostref, 0 ); } @@ -1060,8 +1073,6 @@ sub add_common_rules ( $ ) { # # Easy case # - my $hostref = $nodbl[0]; - if ( $setting & DBL_SRC ) { add_dbl_exclusion_ijump( $input_option_chainref, $dbl_src_target, $hostref, $dbl_ipset, 1, @state , @in_policy ); add_dbl_exclusion_ijump( $forward_option_chainref, $dbl_src_target, $hostref, $dbl_ipset, 1, @state , @in_policy ); @@ -1271,7 +1282,7 @@ sub add_common_rules ( $ ) { $interface = $hostref->[0]; my $ipsec = $hostref->[1]; my $net = $hostref->[2]; - my @policy = $ipsec && have_ipsec ? ( policy => "--pol $ipsec --dir in" ) : (); + my @policy = $ipsec && $have_ipsec ? ( policy => "--pol $ipsec --dir in" ) : (); my $target = source_exclusion( $hostref->[3], $chainref ); my $origin = $hostref->[5]; @@ -1379,7 +1390,7 @@ sub add_common_rules ( $ ) { my $interface = $hostref->[0]; my $target = source_exclusion( $hostref->[3], $chainref ); my $ipsec = $hostref->[1]; - my @policy = $ipsec && have_ipsec ? ( policy => "--pol $ipsec --dir in" ) : (); + my @policy = $ipsec && $have_ipsec ? ( policy => "--pol $ipsec --dir in" ) : (); my $origin = $hostref->[5]; for $chain ( option_chains $interface ) {