Move matrix generation to Rules module

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@5543 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2007-03-15 03:25:08 +00:00
parent b54ea15e2e
commit d755c39fe3
2 changed files with 403 additions and 401 deletions

View File

@ -6,11 +6,13 @@ use Shorewall::Zones;
use Shorewall::Chains; use Shorewall::Chains;
use Shorewall::Actions; use Shorewall::Actions;
use Shorewall::Macros; use Shorewall::Macros;
use Shorewall::Interfaces;
use Shorewall::Policy;
use strict; use strict;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw( process_rules ); our @EXPORT = qw( process_rules generate_matrix );
our @EXPORT_OK = qw( process_rule process_rule1 ); our @EXPORT_OK = qw( process_rule process_rule1 );
our @VERSION = 1.00; our @VERSION = 1.00;
@ -462,4 +464,404 @@ sub process_rules() {
$section = 'DONE'; $section = 'DONE';
} }
#
# To quote an old comment, generate_matrix makes a sows ear out of a silk purse.
#
# The biggest disadvantage of the zone-policy-rule model used by Shorewall is that it doesn't scale well as the number of zones increases (Order N**2 where N = number of zones).
# A major goal of the rewrite of the compiler in Perl was to restrict those scaling effects to this functions and the rules that it generates.
#
# The function traverses the full "source-zone X destination-zone" matrix and generates the rules necessary to direct traffic through the right set of rules.
#
sub generate_matrix() {
#
# Helper functions for generate_matrix()
#-----------------------------------------
#
# Return the target for rules from the $zone to $zone1.
#
sub rules_target( $$ ) {
my ( $zone, $zone1 ) = @_;
my $chain = "${zone}2${zone1}";
my $chainref = $filter_table->{$chain};
return $chain if $chainref && $chainref->{referenced};
return 'ACCEPT' if $zone eq $zone1;
if ( $chainref->{policy} ne 'CONTINUE' ) {
my $policyref = $chainref->{policychain};
return $policyref->{name} if $policyref;
fatal_error "No policy defined for zone $zone to zone $zone1";
}
'';
}
#
# Add a jump to the passed chain ($chainref) to the dynamic zone chain for the passed zone.
#
sub create_zone_dyn_chain( $$ ) {
my ( $zone , $chainref ) = @_;
my $name = "${zone}_dyn";
new_standard_chain $name;
add_rule $chainref, "-j $name";
}
#
# Insert the passed exclusions at the front of the passed chain.
#
sub insert_exclusions( $$ ) {
my ( $chainref, $exclusionsref ) = @_;
my $num = 1;
for my $host ( @{$exclusionsref} ) {
my ( $interface, $net ) = split /:/, $host;
insert_rule $chainref , $num++, "-i $interface " . match_source_net( $host ) . '-j RETURN';
}
}
#
# Add the passed exclusions at the end of the passed chain.
#
sub add_exclusions ( $$ ) {
my ( $chainref, $exclusionsref ) = @_;
for my $host ( @{$exclusionsref} ) {
my ( $interface, $net ) = split /:/, $host;
add_rule $chainref , "-i $interface " . match_source_net( $host ) . '-j RETURN';
}
}
#
# Generate_Matrix() Starts Here
#
my $prerouting_rule = 1;
my $postrouting_rule = 1;
my $exclusion_seq = 1;
my %chain_exclusions;
my %policy_exclusions;
for my $interface ( @interfaces ) {
addnatjump 'POSTROUTING' , snat_chain( $interface ), "-o $interface ";
}
if ( $config{DYNAMIC_ZONES} ) {
for my $interface ( @interfaces ) {
addnatjump 'PREROUTING' , dynamic_in( $interface ), "-i $interface ";
}
}
addnatjump 'PREROUTING' , 'nat_in' , '';
addnatjump 'POSTROUTING' , 'nat_out' , '';
for my $interface ( @interfaces ) {
addnatjump 'PREROUTING' , input_chain( $interface ) , "-i $interface ";
addnatjump 'POSTROUTING' , output_chain( $interface ) , "-o $interface ";
}
for my $zone ( grep $zones{$_}{options}{complex} , @zones ) {
my $frwd_ref = new_standard_chain "${zone}_frwd";
my $zoneref = $zones{$zone};
my $exclusions = $zoneref->{exclusions};
if ( @$exclusions ) {
my $num = 1;
my $in_ref = new_standard_chain "${zone}_input";
my $out_ref = new_standard_chain "${zone}_output";
add_rule ensure_filter_chain( "${zone}2${zone}", 1 ) , '-j ACCEPT' if rules_target $zone, $zone eq 'ACCEPT';
for my $host ( @$exclusions ) {
my ( $interface, $net ) = split /:/, $host;
add_rule $frwd_ref , "-i $interface -s $net -j RETURN";
add_rule $in_ref , "-i $interface -s $net -j RETURN";
add_rule $out_ref , "-i $interface -s $net -j RETURN";
}
if ( $capabilities{POLICY_MATCH} ) {
my $type = $zoneref->{type};
my $source_ref = $zoneref->{hosts}{ipsec} || [];
create_zone_dyn_chain $zone, $frwd_ref && $config{DYNAMIC_ZONES} && (@$source_ref || $type ne 'ipsec4' );
while ( my ( $interface, $arrayref ) = each %$source_ref ) {
for my $hostref ( @{$arrayref} ) {
my $ipsec_match = match_ipsec_in $zone , $hostref;
for my $net ( @{$hostref->{hosts}} ) {
add_rule
find_chainref( 'filter' , forward_chain $interface ) ,
match_source_net $net . $ipsec_match . "-j $frwd_ref->n{name}";
}
}
}
}
}
}
#
# Main source-zone matrix-generation loop
#
for my $zone ( grep ( $zones{$_}{type} ne 'firewall' , @zones ) ) {
my $zoneref = $zones{$zone};
my $source_hosts_ref = $zoneref->{hosts};
my $chain1 = rules_target $firewall_zone , $zone;
my $chain2 = rules_target $zone, $firewall_zone;
my $complex = $zoneref->{options}{complex} || 0;
my $type = $zoneref->{type};
my $exclusions = $zoneref->{exclusions};
my $need_broadcast = {}; ### Fixme ###
my $frwd_ref = 0;
my $chain = 0;
if ( $complex ) {
$frwd_ref = $filter_table->{"${zone}_frwd"};
my $dnat_ref = ensure_chain 'nat' , dnat_chain( $zone );
if ( @$exclusions ) {
insert_exclusions $dnat_ref, $exclusions if $dnat_ref->{referenced};
}
}
#
# Take care of PREROUTING, INPUT and OUTPUT jumps
#
for my $typeref ( values %$source_hosts_ref ) {
while ( my ( $interface, $arrayref ) = each %$typeref ) {
for my $hostref ( @$arrayref ) {
my $ipsec_in_match = match_ipsec_in $zone , $hostref;
my $ipsec_out_match = match_ipsec_out $zone , $hostref;
for my $net ( @{$hostref->{hosts}} ) {
my $source = match_source_net $net;
my $dest = match_dest_net $net;
if ( $chain1 ) {
if ( @$exclusions ) {
add_rule $filter_table->{output_chain $interface} , $dest . $ipsec_out_match . "-j ${zone}_output";
add_rule $filter_table->{"${zone}_output"} , "-j $chain1";
} else {
add_rule $filter_table->{output_chain $interface} , $dest . $ipsec_out_match . "-j $chain1";
}
}
insertnatjump 'PREROUTING' , dnat_chain $zone, \$prerouting_rule, ( "-i $interface " . $source . $ipsec_in_match );
if ( $chain2 ) {
if ( @$exclusions ) {
add_rule $filter_table->{input_chain $interface}, $source . $ipsec_in_match . "-j ${zone}_input";
add_rule $filter_table->{"${zone}_input"} , "-j $chain2";
} else {
add_rule $filter_table->{input_chain $interface}, $source . $ipsec_in_match . "-j $chain2";
}
}
add_rule $filter_table->{forward_chain $interface} , $source . $ipsec_in_match . "-j $frwd_ref->{name}"
if $complex && $hostref->{ipsec} ne 'ipsec';
}
}
}
}
#
# F O R W A R D I N G
#
my @dest_zones;
my $last_chain = '';
if ( $config{OPTIMIZE} > 0 ) {
my @temp_zones;
ZONE1:
for my $zone1 ( grep $zones{$_}{type} ne 'firewall' , @zones ) {
my $zone1ref = $zones{$zone1};
my $policy = $filter_table->{"${zone}2${zone1}"}->{policy};
next if $policy eq 'NONE';
my $chain = rules_target $zone, $zone1;
next unless $chain;
if ( $zone eq $zone1 ) {
#
# One thing that the Llama fails to mention is that evaluating a hash in a numeric context produces a warning.
#
no warnings;
next if ( %{ $zoneref->{interfaces}} < 2 ) && ! ( $zoneref->{options}{routeback} || @$exclusions );
}
if ( $chain =~ /2all$/ ) {
if ( $chain ne $last_chain ) {
$last_chain = $chain;
push @dest_zones, @temp_zones;
@temp_zones = ( $zone1 );
} elsif ( $policy eq 'ACCEPT' ) {
push @temp_zones , $zone1;
} else {
$last_chain = $chain;
@temp_zones = ( $zone1 );
}
} else {
push @dest_zones, @temp_zones, $zone1;
@temp_zones = ();
$last_chain = '';
}
}
if ( $last_chain && @temp_zones == 1 ) {
push @dest_zones, @temp_zones;
$last_chain = '';
}
} else {
@dest_zones = grep $zones{$_}{type} ne 'firewall' , @zones ;
}
#
# Here it is -- THE BIG UGLY!!!!!!!!!!!!
#
# We now loop through the destination zones creating jumps to the rules chain for each source/dest combination.
# @dest_zones is the list of destination zones that we need to handle from this source zone
#
ZONE1:
for my $zone1 ( @dest_zones ) {
my $zone1ref = $zones{$zone1};
my $policy = $filter_table->{"${zone}2${zone1}"}->{policy};
next if $policy eq 'NONE';
my $chain = rules_target $zone, $zone1;
next unless $chain;
my $num_ifaces = 0;
if ( $zone eq $zone1 ) {
#
# One thing that the Llama fails to mention is that evaluating a hash in a numeric context produces a warning.
#
no warnings;
next ZONE1 if ( $num_ifaces = %{$zoneref->{interfaces}} ) < 2 && ! ( $zoneref->{options}{routeback} || @$exclusions );
}
my $chainref = $filter_table->{$chain};
my $exclusions1 = $zone1ref->{exclusions};
my $dest_hosts_ref = $zone1ref->{hosts};
if ( @$exclusions1 ) {
if ( $chain eq "all2$zone1" ) {
unless ( $chain_exclusions{$chain} ) {
$chain_exclusions{$chain} = 1;
insert_exclusions $chainref , $exclusions1;
}
} elsif ( $chain =~ /2all$/ ) {
my $chain1 = $policy_exclusions{"${chain}_${zone1}"};
unless ( $chain ) {
$chain1 = newexclusionchain;
$policy_exclusions{"${chain}_${zone1}"} = $chain1;
my $chain1ref = ensure_filter_chain $chain1, 0;
add_exclusions $chain1ref, $exclusions1;
add_rule $chain1ref, "-j $chain";
}
$chain = $chain1;
} else {
insert_exclusions $chainref , $exclusions1;
}
}
if ( $complex ) {
for my $typeref ( values %$dest_hosts_ref ) {
while ( my ( $interface , $arrayref ) = each %$typeref ) {
for my $hostref ( @$arrayref ) {
if ( $zone ne $zone1 || $num_ifaces > 1 || $hostref->{options}{routeback} ) {
my $ipsec_out_match = match_ipsec_out $zone1 , $hostref;
for my $net ( @{$hostref->{hosts}} ) {
add_rule $frwd_ref, "-o $interface " . match_dest_net($net) . $ipsec_out_match . "-j $chain";
}
}
}
}
}
} else {
for my $typeref ( values %$source_hosts_ref ) {
while ( my ( $interface , $arrayref ) = each %$typeref ) {
my $chain3ref = $filter_table->{forward_chain $interface};
for my $hostref ( @$arrayref ) {
for my $net ( @{$hostref->{hosts}} ) {
my $source_match = match_source_net $net;
for my $type1ref ( values %$dest_hosts_ref ) {
while ( my ( $interface1, $array1ref ) = each %$type1ref ) {
for my $host1ref ( @$array1ref ) {
my $ipsec_out_match = match_ipsec_out $zone1 , $host1ref;
for my $net1 ( @{$host1ref->{hosts}} ) {
unless ( $interface eq $interface1 && $net eq $net1 && ! $host1ref->{options}{routeback} ) {
add_rule $chain3ref, "-o $interface1 " . $source_match . match_dest_net($net1) . $ipsec_out_match . "-j $chain";
}
}
}
}
}
}
}
}
}
}
#
# E N D F O R W A R D I N G
#
# Now add (an) unconditional jump(s) to the last unique policy-only chain determined above, if any
#
if ( $last_chain ) {
if ( $complex ) {
add_rule $frwd_ref , "-j $last_chain";
} else {
for my $typeref ( values %$source_hosts_ref ) {
while ( my ( $interface , $arrayref ) = each %$typeref ) {
my $chain2ref = $filter_table->{forward_chain $interface};
for my $hostref ( @$arrayref ) {
for my $net ( @{$hostref->{hosts}} ) {
add_rule $chain2ref, match_source_net($net) . "-j $last_chain";
}
}
}
}
}
}
}
}
#
# Now add the jumps to the interface chains from FORWARD, INPUT, OUTPUT and POSTROUTING
#
for my $interface ( @interfaces ) {
add_rule $filter_table->{FORWARD} , "-i $interface -j " . forward_chain $interface;
add_rule $filter_table->{INPUT} , "-i $interface -j " . input_chain $interface;
add_rule $filter_table->{OUTPUT} , "-o $interface -j " . output_chain $interface;
addnatjump 'POSTROUTING' , masq_chain( $interface ) , "-o $interface ";
}
my $chainref = $filter_table->{"${firewall_zone}2${firewall_zone}"};
add_rule $filter_table->{OUTPUT} , "-o lo -j " . ($chainref->{referenced} ? "$chainref->{name}" : 'ACCEPT' );
add_rule $filter_table->{INPUT} , '-i lo -j ACCEPT';
complete_standard_chain $filter_table->{INPUT} , 'all' , $firewall_zone;
complete_standard_chain $filter_table->{OUTPUT} , $firewall_zone , 'all';
complete_standard_chain $filter_table->{FORWARD} , 'all' , 'all';
my %builtins = ( mangle => [ qw/PREROUTING INPUT FORWARD POSTROUTING/ ] ,
nat=> [ qw/PREROUTING OUTPUT POSTROUTING/ ] ,
filter=> [ qw/INPUT FORWARD OUTPUT/ ] );
if ( $config{LOGALLNEW} ) {
for my $table qw/mangle nat filter/ {
for my $chain ( @{$builtins{$table}} ) {
log_rule_limit
$config{LOGALLNEW} ,
$chain_table{$table}{$chain} ,
$table ,
$chain ,
'' ,
'' ,
'insert' ,
'-m state --state NEW';
}
}
}
}
1; 1;

View File

@ -482,406 +482,6 @@ sub setup_mac_lists( $ ) {
} }
} }
#
# To quote an old comment, generate_matrix makes a sows ear out of a silk purse.
#
# The biggest disadvantage of the zone-policy-rule model used by Shorewall is that it doesn't scale well as the number of zones increases (Order N**2 where N = number of zones).
# A major goal of the rewrite of the compiler in Perl was to restrict those scaling effects to this functions and the rules that it generates.
#
# The function traverses the full "source-zone X destination-zone" matrix and generates the rules necessary to direct traffic through the right set of rules.
#
sub generate_matrix() {
#
# Helper functions for generate_matrix()
#-----------------------------------------
#
# Return the target for rules from the $zone to $zone1.
#
sub rules_target( $$ ) {
my ( $zone, $zone1 ) = @_;
my $chain = "${zone}2${zone1}";
my $chainref = $filter_table->{$chain};
return $chain if $chainref && $chainref->{referenced};
return 'ACCEPT' if $zone eq $zone1;
if ( $chainref->{policy} ne 'CONTINUE' ) {
my $policyref = $chainref->{policychain};
return $policyref->{name} if $policyref;
fatal_error "No policy defined for zone $zone to zone $zone1";
}
'';
}
#
# Add a jump to the passed chain ($chainref) to the dynamic zone chain for the passed zone.
#
sub create_zone_dyn_chain( $$ ) {
my ( $zone , $chainref ) = @_;
my $name = "${zone}_dyn";
new_standard_chain $name;
add_rule $chainref, "-j $name";
}
#
# Insert the passed exclusions at the front of the passed chain.
#
sub insert_exclusions( $$ ) {
my ( $chainref, $exclusionsref ) = @_;
my $num = 1;
for my $host ( @{$exclusionsref} ) {
my ( $interface, $net ) = split /:/, $host;
insert_rule $chainref , $num++, "-i $interface " . match_source_net( $host ) . '-j RETURN';
}
}
#
# Add the passed exclusions at the end of the passed chain.
#
sub add_exclusions ( $$ ) {
my ( $chainref, $exclusionsref ) = @_;
for my $host ( @{$exclusionsref} ) {
my ( $interface, $net ) = split /:/, $host;
add_rule $chainref , "-i $interface " . match_source_net( $host ) . '-j RETURN';
}
}
#
# Generate_Matrix() Starts Here
#
my $prerouting_rule = 1;
my $postrouting_rule = 1;
my $exclusion_seq = 1;
my %chain_exclusions;
my %policy_exclusions;
for my $interface ( @interfaces ) {
addnatjump 'POSTROUTING' , snat_chain( $interface ), "-o $interface ";
}
if ( $config{DYNAMIC_ZONES} ) {
for my $interface ( @interfaces ) {
addnatjump 'PREROUTING' , dynamic_in( $interface ), "-i $interface ";
}
}
addnatjump 'PREROUTING' , 'nat_in' , '';
addnatjump 'POSTROUTING' , 'nat_out' , '';
for my $interface ( @interfaces ) {
addnatjump 'PREROUTING' , input_chain( $interface ) , "-i $interface ";
addnatjump 'POSTROUTING' , output_chain( $interface ) , "-o $interface ";
}
for my $zone ( grep $zones{$_}{options}{complex} , @zones ) {
my $frwd_ref = new_standard_chain "${zone}_frwd";
my $zoneref = $zones{$zone};
my $exclusions = $zoneref->{exclusions};
if ( @$exclusions ) {
my $num = 1;
my $in_ref = new_standard_chain "${zone}_input";
my $out_ref = new_standard_chain "${zone}_output";
add_rule ensure_filter_chain( "${zone}2${zone}", 1 ) , '-j ACCEPT' if rules_target $zone, $zone eq 'ACCEPT';
for my $host ( @$exclusions ) {
my ( $interface, $net ) = split /:/, $host;
add_rule $frwd_ref , "-i $interface -s $net -j RETURN";
add_rule $in_ref , "-i $interface -s $net -j RETURN";
add_rule $out_ref , "-i $interface -s $net -j RETURN";
}
if ( $capabilities{POLICY_MATCH} ) {
my $type = $zoneref->{type};
my $source_ref = $zoneref->{hosts}{ipsec} || [];
create_zone_dyn_chain $zone, $frwd_ref && $config{DYNAMIC_ZONES} && (@$source_ref || $type ne 'ipsec4' );
while ( my ( $interface, $arrayref ) = each %$source_ref ) {
for my $hostref ( @{$arrayref} ) {
my $ipsec_match = match_ipsec_in $zone , $hostref;
for my $net ( @{$hostref->{hosts}} ) {
add_rule
find_chainref( 'filter' , forward_chain $interface ) ,
match_source_net $net . $ipsec_match . "-j $frwd_ref->n{name}";
}
}
}
}
}
}
#
# Main source-zone matrix-generation loop
#
for my $zone ( grep ( $zones{$_}{type} ne 'firewall' , @zones ) ) {
my $zoneref = $zones{$zone};
my $source_hosts_ref = $zoneref->{hosts};
my $chain1 = rules_target $firewall_zone , $zone;
my $chain2 = rules_target $zone, $firewall_zone;
my $complex = $zoneref->{options}{complex} || 0;
my $type = $zoneref->{type};
my $exclusions = $zoneref->{exclusions};
my $need_broadcast = {}; ### Fixme ###
my $frwd_ref = 0;
my $chain = 0;
if ( $complex ) {
$frwd_ref = $filter_table->{"${zone}_frwd"};
my $dnat_ref = ensure_chain 'nat' , dnat_chain( $zone );
if ( @$exclusions ) {
insert_exclusions $dnat_ref, $exclusions if $dnat_ref->{referenced};
}
}
#
# Take care of PREROUTING, INPUT and OUTPUT jumps
#
for my $typeref ( values %$source_hosts_ref ) {
while ( my ( $interface, $arrayref ) = each %$typeref ) {
for my $hostref ( @$arrayref ) {
my $ipsec_in_match = match_ipsec_in $zone , $hostref;
my $ipsec_out_match = match_ipsec_out $zone , $hostref;
for my $net ( @{$hostref->{hosts}} ) {
my $source = match_source_net $net;
my $dest = match_dest_net $net;
if ( $chain1 ) {
if ( @$exclusions ) {
add_rule $filter_table->{output_chain $interface} , $dest . $ipsec_out_match . "-j ${zone}_output";
add_rule $filter_table->{"${zone}_output"} , "-j $chain1";
} else {
add_rule $filter_table->{output_chain $interface} , $dest . $ipsec_out_match . "-j $chain1";
}
}
insertnatjump 'PREROUTING' , dnat_chain $zone, \$prerouting_rule, ( "-i $interface " . $source . $ipsec_in_match );
if ( $chain2 ) {
if ( @$exclusions ) {
add_rule $filter_table->{input_chain $interface}, $source . $ipsec_in_match . "-j ${zone}_input";
add_rule $filter_table->{"${zone}_input"} , "-j $chain2";
} else {
add_rule $filter_table->{input_chain $interface}, $source . $ipsec_in_match . "-j $chain2";
}
}
add_rule $filter_table->{forward_chain $interface} , $source . $ipsec_in_match . "-j $frwd_ref->{name}"
if $complex && $hostref->{ipsec} ne 'ipsec';
}
}
}
}
#
# F O R W A R D I N G
#
my @dest_zones;
my $last_chain = '';
if ( $config{OPTIMIZE} > 0 ) {
my @temp_zones;
ZONE1:
for my $zone1 ( grep $zones{$_}{type} ne 'firewall' , @zones ) {
my $zone1ref = $zones{$zone1};
my $policy = $filter_table->{"${zone}2${zone1}"}->{policy};
next if $policy eq 'NONE';
my $chain = rules_target $zone, $zone1;
next unless $chain;
if ( $zone eq $zone1 ) {
#
# One thing that the Llama fails to mention is that evaluating a hash in a numeric context produces a warning.
#
no warnings;
next if ( %{ $zoneref->{interfaces}} < 2 ) && ! ( $zoneref->{options}{routeback} || @$exclusions );
}
if ( $chain =~ /2all$/ ) {
if ( $chain ne $last_chain ) {
$last_chain = $chain;
push @dest_zones, @temp_zones;
@temp_zones = ( $zone1 );
} elsif ( $policy eq 'ACCEPT' ) {
push @temp_zones , $zone1;
} else {
$last_chain = $chain;
@temp_zones = ( $zone1 );
}
} else {
push @dest_zones, @temp_zones, $zone1;
@temp_zones = ();
$last_chain = '';
}
}
if ( $last_chain && @temp_zones == 1 ) {
push @dest_zones, @temp_zones;
$last_chain = '';
}
} else {
@dest_zones = grep $zones{$_}{type} ne 'firewall' , @zones ;
}
#
# Here it is -- THE BIG UGLY!!!!!!!!!!!!
#
# We now loop through the destination zones creating jumps to the rules chain for each source/dest combination.
# @dest_zones is the list of destination zones that we need to handle from this source zone
#
ZONE1:
for my $zone1 ( @dest_zones ) {
my $zone1ref = $zones{$zone1};
my $policy = $filter_table->{"${zone}2${zone1}"}->{policy};
next if $policy eq 'NONE';
my $chain = rules_target $zone, $zone1;
next unless $chain;
my $num_ifaces = 0;
if ( $zone eq $zone1 ) {
#
# One thing that the Llama fails to mention is that evaluating a hash in a numeric context produces a warning.
#
no warnings;
next ZONE1 if ( $num_ifaces = %{$zoneref->{interfaces}} ) < 2 && ! ( $zoneref->{options}{routeback} || @$exclusions );
}
my $chainref = $filter_table->{$chain};
my $exclusions1 = $zone1ref->{exclusions};
my $dest_hosts_ref = $zone1ref->{hosts};
if ( @$exclusions1 ) {
if ( $chain eq "all2$zone1" ) {
unless ( $chain_exclusions{$chain} ) {
$chain_exclusions{$chain} = 1;
insert_exclusions $chainref , $exclusions1;
}
} elsif ( $chain =~ /2all$/ ) {
my $chain1 = $policy_exclusions{"${chain}_${zone1}"};
unless ( $chain ) {
$chain1 = newexclusionchain;
$policy_exclusions{"${chain}_${zone1}"} = $chain1;
my $chain1ref = ensure_filter_chain $chain1, 0;
add_exclusions $chain1ref, $exclusions1;
add_rule $chain1ref, "-j $chain";
}
$chain = $chain1;
} else {
insert_exclusions $chainref , $exclusions1;
}
}
if ( $complex ) {
for my $typeref ( values %$dest_hosts_ref ) {
while ( my ( $interface , $arrayref ) = each %$typeref ) {
for my $hostref ( @$arrayref ) {
if ( $zone ne $zone1 || $num_ifaces > 1 || $hostref->{options}{routeback} ) {
my $ipsec_out_match = match_ipsec_out $zone1 , $hostref;
for my $net ( @{$hostref->{hosts}} ) {
add_rule $frwd_ref, "-o $interface " . match_dest_net($net) . $ipsec_out_match . "-j $chain";
}
}
}
}
}
} else {
for my $typeref ( values %$source_hosts_ref ) {
while ( my ( $interface , $arrayref ) = each %$typeref ) {
my $chain3ref = $filter_table->{forward_chain $interface};
for my $hostref ( @$arrayref ) {
for my $net ( @{$hostref->{hosts}} ) {
my $source_match = match_source_net $net;
for my $type1ref ( values %$dest_hosts_ref ) {
while ( my ( $interface1, $array1ref ) = each %$type1ref ) {
for my $host1ref ( @$array1ref ) {
my $ipsec_out_match = match_ipsec_out $zone1 , $host1ref;
for my $net1 ( @{$host1ref->{hosts}} ) {
unless ( $interface eq $interface1 && $net eq $net1 && ! $host1ref->{options}{routeback} ) {
add_rule $chain3ref, "-o $interface1 " . $source_match . match_dest_net($net1) . $ipsec_out_match . "-j $chain";
}
}
}
}
}
}
}
}
}
}
#
# E N D F O R W A R D I N G
#
# Now add (an) unconditional jump(s) to the last unique policy-only chain determined above, if any
#
if ( $last_chain ) {
if ( $complex ) {
add_rule $frwd_ref , "-j $last_chain";
} else {
for my $typeref ( values %$source_hosts_ref ) {
while ( my ( $interface , $arrayref ) = each %$typeref ) {
my $chain2ref = $filter_table->{forward_chain $interface};
for my $hostref ( @$arrayref ) {
for my $net ( @{$hostref->{hosts}} ) {
add_rule $chain2ref, match_source_net($net) . "-j $last_chain";
}
}
}
}
}
}
}
}
#
# Now add the jumps to the interface chains from FORWARD, INPUT, OUTPUT and POSTROUTING
#
for my $interface ( @interfaces ) {
add_rule $filter_table->{FORWARD} , "-i $interface -j " . forward_chain $interface;
add_rule $filter_table->{INPUT} , "-i $interface -j " . input_chain $interface;
add_rule $filter_table->{OUTPUT} , "-o $interface -j " . output_chain $interface;
addnatjump 'POSTROUTING' , masq_chain( $interface ) , "-o $interface ";
}
my $chainref = $filter_table->{"${firewall_zone}2${firewall_zone}"};
add_rule $filter_table->{OUTPUT} , "-o lo -j " . ($chainref->{referenced} ? "$chainref->{name}" : 'ACCEPT' );
add_rule $filter_table->{INPUT} , '-i lo -j ACCEPT';
complete_standard_chain $filter_table->{INPUT} , 'all' , $firewall_zone;
complete_standard_chain $filter_table->{OUTPUT} , $firewall_zone , 'all';
complete_standard_chain $filter_table->{FORWARD} , 'all' , 'all';
my %builtins = ( mangle => [ qw/PREROUTING INPUT FORWARD POSTROUTING/ ] ,
nat=> [ qw/PREROUTING OUTPUT POSTROUTING/ ] ,
filter=> [ qw/INPUT FORWARD OUTPUT/ ] );
if ( $config{LOGALLNEW} ) {
for my $table qw/mangle nat filter/ {
for my $chain ( @{$builtins{$table}} ) {
log_rule_limit
$config{LOGALLNEW} ,
$chain_table{$table}{$chain} ,
$table ,
$chain ,
'' ,
'' ,
'insert' ,
'-m state --state NEW';
}
}
}
}
sub generate_script_1 { sub generate_script_1 {
copy find_file 'prog.header'; copy find_file 'prog.header';