diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index b3cc2ca10..470c53dc0 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -37,6 +37,7 @@ use Shorewall::Config qw(:DEFAULT :internal); use Shorewall::Zones; use Shorewall::IPAddrs; use strict; +use sort 'stable'; our @ISA = qw(Exporter); our @EXPORT = ( qw( @@ -3706,6 +3707,24 @@ sub optimize_level0() { } } +# +# Conditionally sort a list of chain table entry references by name, if -t was specified +# + +sub keysort(\%) { + my $hashref = shift; + + return sort { $a->{name} cmp $b->{name} } keys %$hashref if $test; + return keys %$hashref; +} + +sub valuesort(\%) { + my $hashref = shift; + + return sort { $a->{name} cmp $b->{name} } values %$hashref if $test; + return values %$hashref; +} + sub optimize_level4( $$ ) { my ( $table, $tableref ) = @_; my $progress = 1; @@ -3927,7 +3946,7 @@ sub optimize_level4( $$ ) { my @chains = grep ( $_->{referenced} && ! $_->{optflags} && @{$_->{rules}} < 4 && - keys %{$_->{references}} == 1 , values %$tableref ); + keys %{$_->{references}} == 1 , valuesort %$tableref ); if ( my $chains = @chains ) { $passes++; @@ -3936,7 +3955,7 @@ sub optimize_level4( $$ ) { for my $chainref ( @chains ) { my $name = $chainref->{name}; - for my $sourceref ( map $tableref->{$_}, keys %{$chainref->{references}} ) { + for my $sourceref ( map $tableref->{$_}, sortkeysiftest %{$chainref->{references}} ) { my $name1 = $sourceref->{name}; if ( $chainref->{references}{$name1} == 1 ) { @@ -4066,7 +4085,7 @@ sub optimize_level8( $$$ ) { # # First create aliases for each renamed chain and change the {name} member. # - for my $oldname ( @rename ) { + for my $oldname ( sortiftest @rename ) { my $newname = $renamed{ $oldname } = $rename{ $oldname } . $chainseq++; trace( $tableref->{$oldname}, 'RN', 0, " Renamed $newname" ) if $debug; @@ -4579,7 +4598,7 @@ sub combine_states { sub optimize_level16( $$$ ) { my ( $table, $tableref , $passes ) = @_; - my @chains = ( grep $_->{referenced}, values %{$tableref} ); + my @chains = ( grep $_->{referenced}, valuesort %{$tableref} ); my @chains1 = @chains; my $chains = @chains; @@ -4696,7 +4715,7 @@ sub setup_zone_mss() { my $hosts = find_zone_hosts_by_option( $zone, 'mss' ); - for my $hostref ( @$hosts ) { + for my $hostref ( $test ? sort { $a->[0] cmp $b->[0] } @$hosts : @$hosts ) { my $mss = $hostref->[4]; my @mssmatch = have_capability( 'TCPMSS_MATCH' ) ? ( tcpmss => "--mss $mss:" ) : (); my @sourcedev = imatch_source_dev $hostref->[0]; @@ -7455,13 +7474,13 @@ sub set_global_variables( $$ ) { if ( $conditional ) { my ( $interface, @interfaces ); - @interfaces = keys %interfaceaddr; + @interfaces = sortkeysiftest %interfaceaddr; for $interface ( @interfaces ) { emit( qq([ -z "\$interface" -o "\$interface" = "$interface" ] && $interfaceaddr{$interface}) ); } - @interfaces = keys %interfacegateways; + @interfaces = sortkeysiftest %interfacegateways; for $interface ( @interfaces ) { emit( qq(if [ -z "\$interface" -o "\$interface" = "$interface" ]; then) ); @@ -7471,29 +7490,29 @@ sub set_global_variables( $$ ) { emit( qq(fi\n) ); } - @interfaces = keys %interfacemacs; + @interfaces = sortkeysiftest %interfacemacs; for $interface ( @interfaces ) { emit( qq([ -z "\$interface" -o "\$interface" = "$interface" ] && $interfacemacs{$interface}) ); } } else { - emit $_ for values %interfaceaddr; - emit "$_\n" for values %interfacegateways; - emit $_ for values %interfacemacs; + emit $interfaceaddr{$_} for sortkeysiftest %interfaceaddr; + emit "$interfacegateways{$_}\n" for sortkeysiftest %interfacegateways; + emit $interfacemacs{$_} for sortkeysiftest %interfacemacs; } if ( $setall ) { - emit $_ for values %interfaceaddrs; - emit $_ for values %interfacenets; + emit $interfaceaddr{$_} for sortkeysiftest %interfaceaddr; + emit $interfacenets{$_} for sortkeysiftest %interfacenets; unless ( have_capability( 'ADDRTYPE' ) ) { if ( $family == F_IPV4 ) { emit 'ALL_BCASTS="$(get_all_bcasts) 255.255.255.255"'; - emit $_ for values %interfacebcasts; + emit $interfacebcasts{$_} for sortkeysiftest %interfacebcasts; } else { emit 'ALL_ACASTS="$(get_all_acasts)"'; - emit $_ for values %interfaceacasts; + emit $interfaceacasts{$_} for sortkeysiftest %interfaceacasts; } } } @@ -8457,7 +8476,7 @@ sub add_interface_options( $ ) { # Insert jumps to the interface chains into the rules chains # for my $zone1 ( off_firewall_zones ) { - my @input_interfaces = keys %{zone_interfaces( $zone1 )}; + my @input_interfaces = sortkeysiftest %{zone_interfaces( $zone1 )}; my @forward_interfaces = @input_interfaces; if ( @input_interfaces > 1 ) { @@ -8543,7 +8562,7 @@ sub add_interface_options( $ ) { for my $zone1 ( firewall_zone, vserver_zones ) { for my $zone2 ( off_firewall_zones ) { my $chainref = $filter_table->{rules_chain( $zone1, $zone2 )}; - my @interfaces = keys %{zone_interfaces( $zone2 )}; + my @interfaces = sortkeysiftest %{zone_interfaces( $zone2 )}; my $chain1ref; for my $interface ( @interfaces ) { @@ -8984,7 +9003,7 @@ sub create_save_ipsets() { # $ipsets{$_} = 1 for ( @ipsets, @{$globals{SAVED_IPSETS}} ); - my @sets = keys %ipsets; + my @sets = sortkeysiftest %ipsets; emit( '' , ' rm -f $file' , @@ -9153,7 +9172,7 @@ sub create_load_ipsets() { # sub create_nfobjects() { - my @objects = ( keys %nfobjects ); + my @objects = ( sortkeysiftest %nfobjects ); if ( @objects ) { if ( $config{NFACCT} ) { @@ -9168,7 +9187,7 @@ sub create_nfobjects() { } } - for ( keys %nfobjects ) { + for ( @objects ) { emit( qq(if ! qt \$NFACCT get $_; then), qq( \$NFACCT add $_), qq(fi\n) ); @@ -9541,7 +9560,7 @@ sub create_stop_load( $ ) { } sub initialize_switches() { - if ( keys %switches ) { + if ( sortkeysiftest %switches ) { emit( 'if [ $COMMAND = start ]; then' ); push_indent; for my $switch ( keys %switches ) { diff --git a/Shorewall/Perl/Shorewall/Compiler.pm b/Shorewall/Perl/Shorewall/Compiler.pm index 3f9f11177..5f62b4859 100644 --- a/Shorewall/Perl/Shorewall/Compiler.pm +++ b/Shorewall/Perl/Shorewall/Compiler.pm @@ -49,8 +49,6 @@ our $VERSION = 'MODULEVERSION'; our $export; # True when compiling for export -our $test; # True when running regression tests - our $family; # IP address family (4 or 6) our $have_arptables; # True if we have arptables rules @@ -58,8 +56,8 @@ our $have_arptables; # True if we have arptables rules # # Initilize the package-globals in the other modules # -sub initialize_package_globals( $$$ ) { - Shorewall::Config::initialize($family, $export, $_[1], $_[2]); +sub initialize_package_globals( $$$$ ) { + Shorewall::Config::initialize($family, $export, $_[1], $_[2], $_[3]); Shorewall::Chains::initialize ($family, 1, $export ); Shorewall::Zones::initialize ($family, $_[0]); Shorewall::Nat::initialize($family); @@ -588,7 +586,7 @@ sub compiler { ( '', '', -1, '', 0, '', -1, 0, 0, 0, 0, , '' , '/usr/share/shorewall/shorewallrc', '' ); $export = 0; - $test = 0; + my $test = 0; $have_arptables = 0; sub validate_boolean( $ ) { @@ -641,18 +639,19 @@ sub compiler { # # Now that we know the address family (IPv4/IPv6), we can initialize the other modules' globals # - initialize_package_globals( $update, $shorewallrc, $shorewallrc1 ); - + initialize_package_globals( $update, $test, $shorewallrc, $shorewallrc1 ); + # + # Rather than continuing to extend the argument list of Config::initialize(), + # we use a set of small functions to export settings to the Config module. + # set_config_path( $config_path ) if $config_path; - set_shorewall_dir( $directory ) if $directory ne ''; - $verbosity = 1 if $debug && $verbosity < 1; - set_verbosity( $verbosity ); set_log($log, $log_verbosity) if $log; set_timestamp( $timestamp ); set_debug( $debug , $confess ); + set_command( 'compile', 'Compiling', 'Compiled' ); # # S H O R E W A L L R C , # S H O R E W A L L . C O N F A N D C A P A B I L I T I E S @@ -670,12 +669,7 @@ sub compiler { # # Create a temp file to hold the script # - if ( $scriptfilename ) { - set_command( 'compile', 'Compiling', 'Compiled' ); - create_temp_script( $scriptfilename , $export ); - } else { - set_command( 'check', 'Checking', 'Checked' ); - } + create_temp_script( $scriptfilename , $export ) if $scriptfilename; # # Z O N E D E F I N I T I O N # (Produces no output to the compiled script) diff --git a/Shorewall/Perl/Shorewall/Config.pm b/Shorewall/Perl/Shorewall/Config.pm index 3c988a4a6..b92edb8dd 100644 --- a/Shorewall/Perl/Shorewall/Config.pm +++ b/Shorewall/Perl/Shorewall/Config.pm @@ -166,7 +166,11 @@ our @EXPORT = qw( report_used_capabilities kernel_version - compiletime + compiletime + + sortkeysiftest + sortvaluesiftest + sortiftest F_IPV4 F_IPV6 @@ -264,6 +268,7 @@ our %EXPORT_TAGS = ( internal => [ qw( create_temp_script $debug $file_format $comment + $test %config %origin @@ -793,6 +798,8 @@ our %filecache; our $compiletime; +our $test; + sub process_shorewallrc($$); sub add_variables( \% ); # @@ -804,9 +811,12 @@ sub add_variables( \% ); # # 2. The compiler can run multiple times in the same process so it has to be # able to re-initialize its dependent modules' state. -# -sub initialize($;$$$) { - ( $family, $export, my ( $shorewallrc, $shorewallrc1 ) ) = @_; +#################################################################################################### +# Do not change the required part of this prototype unless you want to take on a lot of additional +# work (This function is called from build). +#################################################################################################### +sub initialize($;$$$$) { + ( $family, $export, $test, my ( $shorewallrc, $shorewallrc1 ) ) = @_; if ( $family == F_IPV4 ) { ( $product, $Product, $toolname, $toolNAME ) = qw( shorewall Shorewall iptables IPTABLES ); @@ -851,7 +861,7 @@ sub initialize($;$$$) { TC_SCRIPT => '', EXPORT => 0, KLUDGEFREE => '', - VERSION => '5.2.0-Beta1', + VERSION => '5.2.4.1', CAPVERSION => 50200 , BLACKLIST_LOG_TAG => '', RELATED_LOG_TAG => '', @@ -1828,6 +1838,30 @@ sub set_command( $$$ ) { ($command, $doing, $done) = @_; } +# +# Return the keys or values of the passed hash. If $test, the keys/values will be sorted by their own values +# +sub sortkeysiftest(\%) { + my ( $hashref ) = @_; + + return sort keys %$hashref if $test; + return keys %$hashref; +} + +sub sortvaluesiftest(\%) { + my ( $hashref ) = @_; + + return sort values %$hashref if $test; + return keys %$hashref; +} + +# +# Sort a list by the list elements if $test +# +sub sortiftest(@) { + return $test ? sort @_ : @_; +} + # # Print the current TOD to STDOUT. # diff --git a/Shorewall/Perl/Shorewall/Misc.pm b/Shorewall/Perl/Shorewall/Misc.pm index a94dc74e9..3802167b4 100644 --- a/Shorewall/Perl/Shorewall/Misc.pm +++ b/Shorewall/Perl/Shorewall/Misc.pm @@ -34,6 +34,7 @@ use Shorewall::Zones; use Shorewall::Chains qw(:DEFAULT :internal); use Shorewall::Rules; use Shorewall::Proc; +use sort 'stable'; use strict; @@ -130,7 +131,7 @@ sub setup_ecn() } if ( @hosts ) { - my @interfaces = ( keys %interfaces ); + my @interfaces = ( sortkeysiftest %interfaces ); progress_message "$doing ECN control on @interfaces..."; @@ -1322,7 +1323,7 @@ sub setup_mac_lists( $ ) { $maclist_interfaces{ $hostref->[0] } = 1; } - my @maclist_interfaces = ( keys %maclist_interfaces ); + my @maclist_interfaces = ( sortkeysiftest %maclist_interfaces ); if ( $phase == 1 ) { @@ -1408,7 +1409,7 @@ sub setup_mac_lists( $ ) { # # Generate jumps from the input and forward chains # - for my $hostref ( @$maclist_hosts ) { + for my $hostref ( $test ? sort { $a->[0] cmp $b->[0] } @$maclist_hosts : @$maclist_hosts ) { my $interface = $hostref->[0]; my $ipsec = $hostref->[1]; my @policy = $ipsec && have_ipsec ? ( policy => "--pol $ipsec --dir in" ) : (); @@ -1801,7 +1802,7 @@ sub handle_complex_zone( $$ ) { my $type = $zoneref->{type}; my $source_ref = ( $zoneref->{hosts}{ipsec} ) || {}; - for my $interface ( keys %$source_ref ) { + for my $interface ( sortkeysiftest %$source_ref ) { my $sourcechainref = $filter_table->{forward_chain $interface}; my @interfacematch; my $interfaceref = find_interface $interface; @@ -1941,7 +1942,7 @@ sub add_output_jumps( $$$$$$$$ ) { my $use_output = 0; my @dest = imatch_dest_net $net; my @ipsec_out_match = match_ipsec_out $zone , $hostref; - my @zone_interfaces = keys %{zone_interfaces( $zone )}; + my @zone_interfaces = sortkeysiftest %{zone_interfaces( $zone )}; if ( @vservers || use_interface_chain( $interface, 'use_output_chain' ) || ( @{$interfacechainref->{rules}} && ! $chain1ref ) || @zone_interfaces > 1 ) { # @@ -2313,9 +2314,9 @@ sub generate_matrix() { # # Take care of PREROUTING, INPUT and OUTPUT jumps # - for my $type ( keys %$source_hosts_ref ) { + for my $type ( sortkeysiftest %$source_hosts_ref ) { my $typeref = $source_hosts_ref->{$type}; - for my $interface ( keys %$typeref ) { + for my $interface ( sortkeysiftest %$typeref ) { if ( get_physical( $interface ) eq '+' ) { # # Insert the interface-specific jumps before this one which is not interface-specific @@ -2400,9 +2401,9 @@ sub generate_matrix() { my $chainref = $filter_table->{$chain}; #Will be null if $chain is a Netfilter Built-in target like ACCEPT - for my $type ( keys %{$zone1ref->{hosts}} ) { + for my $type ( sortkeysiftest %{$zone1ref->{hosts}} ) { my $typeref = $zone1ref->{hosts}{$type}; - for my $interface ( keys %$typeref ) { + for my $interface ( sortkeysiftest %$typeref ) { for my $hostref ( @{$typeref->{$interface}} ) { next if $hostref->{options}{sourceonly}; if ( $zone ne $zone1 || $num_ifaces > 1 || $hostref->{options}{routeback} ) { diff --git a/Shorewall/Perl/Shorewall/Providers.pm b/Shorewall/Perl/Shorewall/Providers.pm index 18598da14..4f4ad59bb 100644 --- a/Shorewall/Perl/Shorewall/Providers.pm +++ b/Shorewall/Perl/Shorewall/Providers.pm @@ -1892,8 +1892,8 @@ sub map_provider_to_interface() { my $haveoptional; - for my $providerref ( values %providers ) { - if ( $providerref->{optional} ) { + for my $provider ( @providers ) { + if ( ( my $providerref=$providers{$provider} )->{optional} ) { unless ( $haveoptional++ ) { emit( 'if [ -n "$interface" ]; then', ' case $interface in' ); @@ -2054,8 +2054,7 @@ sub compile_updown() { ); } - my @nonshared = ( grep $providers{$_}->{optional}, - values %provider_interfaces ); + my @nonshared = ( grep $providers{$_}->{optional}, sortvaluesiftest %provider_interfaces ); if ( @nonshared ) { my $interfaces = join( '|', map $providers{$_}->{physical}, @nonshared ); @@ -2246,9 +2245,11 @@ sub handle_optional_interfaces() { # names but they might derive from wildcard interface entries. Optional interfaces which do not have # wildcard physical names are also included in the providers table. # - for my $providerref ( grep $_->{optional} , values %providers ) { - push @interfaces, $providerref->{interface}; - $wildcards ||= $providerref->{wildcard}; + for my $provider ( @providers ) { + if ( ( my $providerref = $providers{$provider} )->{optional} ) { + push @interfaces, $providerref->{interface}; + $wildcards ||= $providerref->{wildcard}; + } } # @@ -2296,17 +2297,7 @@ sub handle_optional_interfaces() { emit( "$physical)" ), push_indent if $wildcards; - if ( $provider eq $physical ) { - # - # Just an optional interface, or provider and interface are the same - # - emit qq(if [ -z "\$interface" -o "\$interface" = "$physical" ]; then); - } else { - # - # Provider - # - emit qq(if [ -z "\$interface" -o "\$interface" = "$physical" ]; then); - } + emit qq(if [ -z "\$interface" -o "\$interface" = "$physical" ]; then); push_indent; diff --git a/Shorewall/Perl/Shorewall/Proxyarp.pm b/Shorewall/Perl/Shorewall/Proxyarp.pm index c014bd5bd..7051aef9f 100644 --- a/Shorewall/Perl/Shorewall/Proxyarp.pm +++ b/Shorewall/Perl/Shorewall/Proxyarp.pm @@ -155,7 +155,7 @@ sub setup_proxy_arp() { emit ''; - for my $interface ( keys %reset ) { + for my $interface ( sortkeysiftest %reset ) { unless ( $set{interface} ) { my $physical = get_physical $interface; emit ( "if [ -f /proc/sys/net/ipv$family/conf/$physical/$proc_file ]; then" , @@ -164,7 +164,7 @@ sub setup_proxy_arp() { } } - for my $interface ( keys %set ) { + for my $interface ( sortkeysiftest %set ) { my $physical = get_physical $interface; emit ( "if [ -f /proc/sys/net/ipv$family/conf/$physical/$proc_file ]; then" , " echo 1 > /proc/sys/net/ipv$family/conf/$physical/$proc_file" ); diff --git a/Shorewall/Perl/Shorewall/Zones.pm b/Shorewall/Perl/Shorewall/Zones.pm index 0f7ec8ddc..1fc4f515f 100644 --- a/Shorewall/Perl/Shorewall/Zones.pm +++ b/Shorewall/Perl/Shorewall/Zones.pm @@ -29,6 +29,7 @@ package Shorewall::Zones; require Exporter; use Shorewall::Config qw(:DEFAULT :internal); use Shorewall::IPAddrs; +use sort 'stable'; use strict; @@ -847,10 +848,10 @@ sub dump_zone_contents() { $entry .= ( " mark=" . in_hex( $zoneref->{mark} ) ) if exists $zoneref->{mark}; if ( $hostref ) { - for my $type ( keys %$hostref ) { + for my $type ( sortkeysiftest %$hostref ) { my $interfaceref = $hostref->{$type}; - for my $interface ( keys %$interfaceref ) { + for my $interface ( sortkeysiftest %$interfaceref ) { my $iref = $interfaces{$interface}; my $arrayref = $interfaceref->{$interface};