From 0c6b0db56f8ad148dea567a601e99035fb13fcc2 Mon Sep 17 00:00:00 2001 From: teastep Date: Tue, 27 Mar 2007 18:41:55 +0000 Subject: [PATCH] Better iptables-restore input generation (with bug fix); restore 'compiled' message git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@5719 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- New/Shorewall/Chains.pm | 94 +++++++++++++++++++++++++++++++++-------- New/Shorewall/Common.pm | 70 ++++++++++++++++-------------- New/Shorewall/Nat.pm | 10 ++--- New/compiler.pl | 2 +- 4 files changed, 121 insertions(+), 55 deletions(-) diff --git a/New/Shorewall/Chains.pm b/New/Shorewall/Chains.pm index 739240df6..0003f4aee 100644 --- a/New/Shorewall/Chains.pm +++ b/New/Shorewall/Chains.pm @@ -98,6 +98,7 @@ our @EXPORT = qw( STANDARD expand_rule addnatjump insertnatjump + get_interface_addresses create_netfilter_load @policy_chains @@ -1007,9 +1008,11 @@ sub mysplit( $ ) { } # -# Keep track of which interfaces have active 'address' variables +# Keep track of which interfaces have active 'address', 'addresses' and 'networks' variables # +my %interfaceaddr; my %interfaceaddrs; +my %interfacenets; # # Returns the name of the shell variable holding the first address of the passed interface @@ -1019,13 +1022,61 @@ sub interface_address( $ ) { } # -# If this is the first time that the first address of an interface has been requested, emit a run-time command -# that establishes the value of the associated address variable. +# Record that the ruleset requires the first IP address on the passed interface # sub get_interface_address ( $ ) { my ( $interface ) = $_[0]; + + my $variable = interface_address( $interface ); - $interfaceaddrs{$interface} = interface_address( $interface ) . "=\$(find_first_interface_address $interface)"; + $interfaceaddr{$interface} = "$variable=\$(find_first_interface_address $interface)"; + + "\$$variable"; +} + +# +# Returns the name of the shell variable holding the addresses of the passed interface +# +sub interface_addresses( $ ) { + chain_base( $_[0] ) . '_addresses'; +} + +# +# Record that the ruleset requires the IP addresses on the passed interface +# +sub get_interface_addresses ( $ ) { + my ( $interface ) = $_[0]; + + my $variable = interface_addresses( $interface ); + + $interfaceaddr{$interface} = qq($variable=\$(get_interface_addresses $interface) +[ -n "\$$variable" ] || fatal_error "Unable to determine the IP address(es) of $interface" +); + + "\$$variable"; +} + +# +# Returns the name of the shell variable holding the networks routed out of the passed interface +# +sub interface_nets( $ ) { + chain_base( $_[0] ) . '_networks'; +} + +# +# Record that the ruleset requires the first IP address on the passed interface +# +sub get_interface_nets ( $ ) { + my ( $interface ) = $_[0]; + + my $variable = interface_nets( $interface ); + + $interfaceaddr{$interface} = qq($variable=\$(get_routed_networks $interface) +[ -n "\$$variable" ] || fatal_error "Unable to determine the routes through interface \\"$interface\\"" +); + + "\$$variable"; + } # @@ -1077,9 +1128,10 @@ sub expand_rule( $$$$$$$$$$ ) # # An interface in the SOURCE column of a masq file # - add_command( $chainref , "sources=\$(get_routed_networks $iiface)" ); - add_command( $chainref , qq([ -z "\$sources" ] && fatal_error "Unable to determine the routes through interface \"$iiface\"") ); - add_command( $chainref , 'for source in $sources; do' ); + my $networks = get_interface_nets ( $iiface ); + + add_command( $chainref , join( '', 'for source in ', $networks, '; do' ) ); + $rule .= '-s $source '; # # While $loopcount > 0, calls to 'add_rule()' will be converted to calls to 'add_command()' @@ -1105,18 +1157,18 @@ sub expand_rule( $$$$$$$$$$ ) my @interfaces = split /\s+/, $1; if ( @interfaces > 1 ) { - add_command $chainref, 'addresses='; + my $list = ""; for my $interface ( @interfaces ) { - get_interface_address $interface; - add_command $chainref , join( '', 'addresses="$addresses $', interface_address( $interface ). '"' ); + $list = join( ' ', $list , get_interface_address( $interface ) ); } - add_command $chainref , 'for address in $addresses; do'; + + add_command( $chainref , "for address in $list; do" ); + $rule .= '-d $address '; $loopcount++; } else { - get_interface_address $interfaces[0]; - $rule .= join ( '', '-d $', interface_address( $interfaces[0] ), ' ' ); + $rule .= join ( '', '-d ', get_interface_address( $interfaces[0] ), ' ' ); } $dest = ''; @@ -1164,14 +1216,13 @@ sub expand_rule( $$$$$$$$$$ ) my @interfaces = split /\s+/, $1; if ( @interfaces > 1 ) { - add_command $chainref, 'addresses='; + my $list = ""; for my $interface ( @interfaces ) { - get_interface_address $interface; - add_command $chainref , qq(addresses="\$addresses \$(find_first_interface_address $interface)"); + $list = join( ' ', $list , get_interface_address( $interface ) ); } - add_command( $chainref , 'for address in $addresses; do' ); + add_command( $chainref , "for address in $list; do" ); $rule .= '-m conntrack --ctorigdst $address '; $loopcount++; } else { @@ -1410,12 +1461,21 @@ sub create_netfilter_load() { emitj( 'setup_netfilter()', '{' ); + push_indent; + for ( values %interfaceaddr ) { + emit $_; + } + for ( values %interfaceaddrs ) { emit $_; } + for ( values %interfacenets ) { + emit $_; + } + emit ''; if ( $slowstart ) { diff --git a/New/Shorewall/Common.pm b/New/Shorewall/Common.pm index 43398d4a9..c9c090475 100644 --- a/New/Shorewall/Common.pm +++ b/New/Shorewall/Common.pm @@ -125,36 +125,6 @@ sub split_line( $$ ) { @line; } -sub create_temp_object( $ ) { - my $objectfile = $_[0]; - my $suffix; - - eval { - ( $file, $dir, $suffix ) = fileparse( $objectfile ); - $dir = abs_path $dir; - fatal_error "Directory $dir does not exist" unless -d $dir; - fatal_error "$dir is a Symbolic Link" if -l $dir; - fatal_error "$objectfile is a Directory" if -d $objectfile; - fatal_error "$dir is a Symbolic Link" if -l $objectfile; - fatal_error "$objectfile exists and is not a compiled script" if -e _ && ! -x _; - ( $object, $tempfile ) = tempfile ( 'tempfileXXXX' , DIR => $dir ); - }; - - die if $@; - - $file = "$file.$suffix" if $suffix; - $dir .= '/' unless substr( $dir, -1, 1 ) eq '/'; - $file = $dir . $file; - -} - -sub finalize_object() { - close $object; - $object = 0; - rename $tempfile, $file or fatal_error "Cannot Rename $tempfile to $file: $!"; - chmod 0700, $file; -} - # # Write the argument to the object file (if any) with the current indentation. # @@ -206,7 +176,7 @@ sub emitj { # -# Write passed message to the object with no indentation. +# Write passed message to the object with newline but no indentation. # sub emit_unindented( $ ) { @@ -312,6 +282,43 @@ sub copy1( $ ) { } } +sub create_temp_object( $ ) { + my $objectfile = $_[0]; + my $suffix; + + eval { + ( $file, $dir, $suffix ) = fileparse( $objectfile ); + }; + + die $@ if $@; + + fatal_error "Directory $dir does not exist" unless -d $dir; + fatal_error "$dir is a Symbolic Link" if -l $dir; + fatal_error "$objectfile is a Directory" if -d $objectfile; + fatal_error "$dir is a Symbolic Link" if -l $objectfile; + fatal_error "$objectfile exists and is not a compiled script" if -e _ && ! -x _; + + eval { + $dir = abs_path $dir; + ( $object, $tempfile ) = tempfile ( 'tempfileXXXX' , DIR => $dir ); + }; + + die $@ if $@; + + $file = "$file.$suffix" if $suffix; + $dir .= '/' unless substr( $dir, -1, 1 ) eq '/'; + $file = $dir . $file; + +} + +sub finalize_object() { + close $object; + $object = 0; + rename $tempfile, $file or fatal_error "Cannot Rename $tempfile to $file: $!"; + chmod 0700, $file; + progress_message3 "Shorewall configuration compiled to $file" unless $ENV{EXPORT}; +} + sub create_temp_aux_config() { eval { ( $object, $tempfile ) = tempfile ( 'tempfileXXXX' , DIR => $dir ); @@ -325,7 +332,6 @@ sub finalize_aux_config() { close $object; $object = 0; rename $tempfile, "$file.conf" or fatal_error "Cannot Rename $tempfile to $file.conf: $!"; - progress_message3 "Shorewall configuration compiled to $file"; } diff --git a/New/Shorewall/Nat.pm b/New/Shorewall/Nat.pm index a7ed2bbe7..37221e441 100644 --- a/New/Shorewall/Nat.pm +++ b/New/Shorewall/Nat.pm @@ -181,10 +181,8 @@ sub setup_one_masq($$$$$$) $target .= "--to $addr "; } } elsif ( $addresses eq 'detect' ) { - add_command( $chainref , "addresses=\$(find_interface_addresses $interface);" ); - add_command( $chainref , qq([ -z "\$addresses" ] && fatal_error "Unable to determine the IP address(es) of $interface";) ); add_command( $chainref , 'addrlist=' ); - add_command( $chainref , 'for address in $addresses; do' ); + add_command( $chainref , join( '', 'for address in ' , get_interface_addresses( $interface ), '; do' ) ); add_command( $chainref , ' addrlist="$addrlist --to-source $address"' ); add_command( $chainref , 'done' ); @@ -289,7 +287,9 @@ sub validate_nat_column( $$ ) { # sub do_one_nat( $$$$$ ) { - my ( $external, $interface, $internal, $allints, $localnat ) = @_; + my ( $external, $fullinterface, $internal, $allints, $localnat ) = @_; + + my ( $interface, $alias ) = split /:/, $fullinterface; sub add_nat_rule( $$ ) { add_rule ensure_chain( 'nat', $_[0] ) , $_[1]; @@ -334,7 +334,7 @@ sub do_one_nat( $$$$$ ) if ( $add_ip_aliases ) { unless ( $addresses_to_add{$external} ) { $addresses_to_add{$external} = 1; - push @addresses_to_add, ( $external , $interface ); + push @addresses_to_add, ( $external , $fullinterface ); } } diff --git a/New/compiler.pl b/New/compiler.pl index 2a7882022..e84341fd3 100755 --- a/New/compiler.pl +++ b/New/compiler.pl @@ -82,7 +82,7 @@ use Shorewall::Proxyarp; # # Now I could spend my time trying to configure cperl-mode to do what I want; but why? # Like most Open Source Software, it's documentation is pathetic. I would rather spend -# my time making Shorewall better rather than working around braindead editing modes. +# my time making Shorewall better as opposed to working around braindead editing modes. # # Bottom line. I use quoting techinques other than 'here documents'. #