Handle 'nodbl' in complex host definitions

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2024-03-06 17:18:50 -08:00
parent a8718b9867
commit cbe2935fce
2 changed files with 108 additions and 61 deletions

View File

@ -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
#

View File

@ -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";