From d755c39fe3712b2db36bf0917eb2168c6cab081a Mon Sep 17 00:00:00 2001 From: teastep Date: Thu, 15 Mar 2007 03:25:08 +0000 Subject: [PATCH] Move matrix generation to Rules module git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@5543 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- New/Shorewall/Rules.pm | 404 ++++++++++++++++++++++++++++++++++++++++- New/compiler.pl | 400 ---------------------------------------- 2 files changed, 403 insertions(+), 401 deletions(-) diff --git a/New/Shorewall/Rules.pm b/New/Shorewall/Rules.pm index a27b5c9b1..872f59bcf 100644 --- a/New/Shorewall/Rules.pm +++ b/New/Shorewall/Rules.pm @@ -6,11 +6,13 @@ use Shorewall::Zones; use Shorewall::Chains; use Shorewall::Actions; use Shorewall::Macros; +use Shorewall::Interfaces; +use Shorewall::Policy; use strict; 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 @VERSION = 1.00; @@ -462,4 +464,404 @@ sub process_rules() { $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; diff --git a/New/compiler.pl b/New/compiler.pl index 679a9feb3..e238e855b 100755 --- a/New/compiler.pl +++ b/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 { copy find_file 'prog.header';