mirror of
https://gitlab.com/shorewall/code.git
synced 2025-01-16 18:48:35 +01:00
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:
parent
b54ea15e2e
commit
d755c39fe3
@ -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;
|
||||||
|
400
New/compiler.pl
400
New/compiler.pl
@ -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';
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user