diff --git a/Shorewall/Perl/Shorewall/Misc.pm b/Shorewall/Perl/Shorewall/Misc.pm index d5230977d..06a832a8b 100644 --- a/Shorewall/Perl/Shorewall/Misc.pm +++ b/Shorewall/Perl/Shorewall/Misc.pm @@ -716,6 +716,36 @@ sub add_ipset_dbl_ijump( $$$@) { 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->{nets}; + 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 # @@ -983,10 +1013,6 @@ sub add_common_rules ( $ ) { if ( ( my $setting = get_interface_option( $interface, 'dbl' ) ) != DBL_NONE ) { - my @matches = @state; - - my ( @src_exclude, @dst_exclude, @classic_exclude ); - my @nodbl = @{$interfaceref->{nodbl}}; if ( @nodbl ) { @@ -995,78 +1021,90 @@ sub add_common_rules ( $ ) { # if ( @nodbl > 1 ) { # - # We need to create an intermediate chain + # Complex case - we need to create an intermediate chain # - if ( $dbl_ipset ) { - $chainref = new_standard_chain( nodbl_src_chain( $interface )); + $chainref = new_standard_chain( nodbl_src_chain( $interface )); - for (@nodbl) { - add_ijump( $chainref, j => 'RETURN', s => $_ ); - } - - add_ijump( $input_option_chainref, j => $chainref->{name} ); - add_ijump( $forward_option_chainref, j => $chainref->{name} ); - - $input_option_chainref = $forward_option_chainref = $chainref; - - if ( $dbl_src_target ne $dbl_dst_target ) { - $chainref = new_standard_chain( nodbl_dst_chain( $interface )); - - for ( @nodbl ){ - add_ijump( $chainref, j => 'RETURN', -d => $_ ); - } - - add_ijump( $output_option_chainref, j => $chainref->{name} ); - - $output_option_chainref = $chainref, - } + for my $hostref (@nodbl) { + add_host_exclusion_ijump( $chainref, 'RETURN', $hostref, 1 ); } - if ( $setting & DBL_CLASSIC ) { - $chainref = new_standard_chain( nodbl_classic_chain( $interface )); + add_ijump( $input_option_chainref, j => $chainref->{name} ); + add_ijump( $forward_option_chainref, j => $chainref->{name} ); - for (@nodbl) { - add_ijump( $chainref, j => 'RETURN', s => $_ ); - add_ijump( $chainref, j => 'RETURN', d => $_ ); + $input_option_chainref = $forward_option_chainref = $chainref; + + if ( $dbl_src_target ne $dbl_dst_target ) { + $chainref = new_standard_chain( nodbl_dst_chain( $interface )); + + for my $hostref (@nodbl) { + add_host_exclusion_ijump( $chainref, 'RETURN', $hostref, 0 ); } - add_ijump( $chainref, j => $dynamicref->{name} ); + add_ijump( $output_option_chainref, j => $chainref->{name} ); - $classic_target_chain = $chainref; + $output_option_chainref = $chainref, } - } else { + + } elsif ( $dbl_ipset ) { # # Easy case # - @matches = ( s => "! $nodbl[0]" , @matches ); - @matches = ( d => "! $nodbl[0]" , @matches ); + my $hostref = $nodbl[0]; + + if ( $setting & DBL_SRC ) { + add_dbl_exclusion_ijump( $input_option_chainref, $dbl_src_target, $hostref, $dbl_ipset, 1, @state ); + add_dbl_exclusion_ijump( $forward_option_chainref, $dbl_src_target, $hostref, $dbl_ipset, 1, @state ); + } + + if ( $setting & DBL_DST ) { + add_dbl_exclusion_ijump( $forward_option_chainref, $dbl_dst_target, $hostref, $dbl_ipset, 0, @state ); + add_dbl_exclusion_ijump( $output_option_chainref, $dbl_dst_target, $hostref, $dbl_ipset, 1, @state ); + } + + $dbl_ipset = ''; + } + + if ( $setting & DBL_CLASSIC ) { + $chainref = new_standard_chain( nodbl_classic_chain( $interface )); + + for my $hostref (@nodbl) { + add_host_exclusion_ijump( $chainref, 'RETURN', $hostref, 1 ); + } + + add_ijump( $chainref, j => $dynamicref->{name} ); + + $classic_target_chain = $chainref; + } + } if ( $dbl_ipset ) { - if ( $setting & DBL_SRC) { - # - # src or src-dst - # - add_ipset_dbl_ijump( $input_option_chainref, $dbl_src_target, "$dbl_ipset src", @matches ); - add_ipset_dbl_ijump( $forward_option_chainref, $dbl_src_target, "$dbl_ipset src", @matches ); - } + if ( $setting & DBL_SRC) { + # + # src or src-dst + # + add_ipset_dbl_ijump( $input_option_chainref, $dbl_src_target, "$dbl_ipset src", @state ); + add_ipset_dbl_ijump( $forward_option_chainref, $dbl_src_target, "$dbl_ipset src", @state ); + } - if ( $setting & DBL_DST ) { - # - # src-dst - # - add_ipset_dbl_ijump( $forward_option_chainref, $dbl_dst_target, "$dbl_ipset dst", @matches ); - add_ipset_dbl_ijump( $output_option_chainref, $dbl_dst_target, "$dbl_ipset dst", @matches ); + if ( $setting & DBL_DST ) { + # + # src-dst + # + add_ipset_dbl_ijump( $forward_option_chainref, $dbl_dst_target, "$dbl_ipset dst", @state ); + add_ipset_dbl_ijump( $output_option_chainref, $dbl_dst_target, "$dbl_ipset dst", @state ); + } } - } if ( $setting & DBL_CLASSIC ) { add_ijump_extended( $input_option_chainref, j => $classic_target_chain, $origin{DYNAMIC_BLACKLIST}, @state ); add_ijump_extended( $forward_option_chainref, j => $classic_target_chain, $origin{DYNAMIC_BLACKLIST}, @state ); add_ijump_extended( $output_option_chainref, j => $classic_target_chain, $origin{DYNAMIC_BLACKLIST}, @state ) if $setting & DBL_DST; } - } + + } # Exclusion # # Finish FASTACCEPT # diff --git a/Shorewall/Perl/Shorewall/Zones.pm b/Shorewall/Perl/Shorewall/Zones.pm index bd7be9729..dab5d5f9e 100644 --- a/Shorewall/Perl/Shorewall/Zones.pm +++ b/Shorewall/Perl/Shorewall/Zones.pm @@ -979,18 +979,22 @@ sub add_group_to_zone($$$$$$) $zoneref->{complex} = 1 if @$interfaceref || @newnetworks > 1 || @exclusions || $options->{routeback}; - push @{$interfaceref}, { options => $options, - hosts => \@newnetworks, - ipsec => $type & IPSEC ? 'ipsec' : 'none' , - exclusions => \@exclusions , - origin => shortlineinfo( '' ) , - }; + my $hostref = { options => $options, + hosts => \@newnetworks, + ipsec => $type & IPSEC ? 'ipsec' : 'none' , + exclusions => \@exclusions , + origin => shortlineinfo( '' ) , + }; + + push @{$interfaceref}, $hostref; if ( $type != IPSEC ) { my $optref = $interfaces{$interface}{options}; $optref->{routeback} ||= $options->{routeback}; $optref->{allip} ||= $allip; } + + return $hostref; } # @@ -2241,7 +2245,6 @@ sub process_host( ) { $zoneref->{options}{complex} = 1; } elsif ( $option eq 'nodbl' ) { fatal_error "The 'nodbl' option is only allowed in 'ip' zones" unless $type & IP; - push @{$interfaceref->{nodbl}}, $hosts; $options{nodbl} = 1; } elsif ( $validhostoptions{$option}) { fatal_error qq(The "$option" option is not allowed with Vserver zones) if $type & VSERVER && ! ( $validhostoptions{$option} & IF_OPTION_VSERVER ); @@ -2286,13 +2289,19 @@ sub process_host( ) { $optionsref->{dynamic} = 1; add_ipset($set); } - + # # # We ignore the user's notion of what interface vserver addresses are on and simply invent one for all of the vservers. # $interface = '%vserver%' if $type & VSERVER; - add_group_to_zone( $zone, $type , $interface, [ split_list( $hosts, 'host' ) ] , $optionsref, 0 ); + my $hostref = add_group_to_zone( $zone, $type , $interface, [ split_list( $hosts, 'host' ) ] , $optionsref, 0 ); + # + # Push 'nodbl' info to the interface + # + if ( $optionsref->{nodbl} ) { + push @{$interfaceref->{nodbl}}, $hostref ; + } progress_message " Host \"$currentline\" validated";