diff --git a/Shorewall-core/lib.cli b/Shorewall-core/lib.cli index 29f583ffa..bd5de17b8 100644 --- a/Shorewall-core/lib.cli +++ b/Shorewall-core/lib.cli @@ -3238,8 +3238,8 @@ report_capabilities_unsorted() { [ -n "$RECENT_MATCH" ] && report_capability 'Recent Match "--reap" option (REAP_OPTION)' $REAP_OPTION report_capability "Owner Match (OWNER_MATCH)" $OWNER_MATCH report_capability "Owner Name Match (OWNER_NAME_MATCH)" $OWNER_NAME_MATCH + report_capability "Ipset Match (IPSET_MATCH)" $IPSET_MATCH if [ -n "$IPSET_MATCH" ]; then - report_capability "Ipset Match (IPSET_MATCH)" $IPSET_MATCH [ -n "$OLD_IPSET_MATCH" ] && report_capability "OLD_Ipset Match (OLD_IPSET_MATCH)" $OLD_IPSET_MATCH [ -n "$IPSET_MATCH_NOMATCH" ] && report_capability "Ipset Match Nomatch (IPSET_MATCH_NOMATCH)" $IPSET_MATCH_NOMATCH [ -n "$IPSET_MATCH_NOMATCH" ] && report_capability "Ipset Match Counters (IPSET_MATCH_COUNTERS)" $IPSET_MATCH_COUNTERS diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index 52f40a2ce..4a8fd2ada 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -1319,12 +1319,12 @@ sub pop_match( $$ ) { sub clone_irule( $ ); -sub format_rule( $$;$ ) { - my ( $chainref, $rulerefp, $suppresshdr ) = @_; +sub format_rule( $$ ) { + my ( $chainref, $rulerefp ) = @_; return $rulerefp->{cmd} if exists $rulerefp->{cmd}; - my $rule = $suppresshdr ? '' : "-A $chainref->{name}"; + my $rule = "-A $chainref->{name}"; # # The code that follows can be destructive of the rule so we clone it # @@ -3377,15 +3377,43 @@ sub delete_references( $ ) { # # Calculate a digest for the passed chain and store it in the {digest} member. # +# First, a lightweight version of format_rule() +# +sub irule_to_string( $ ) { + my ( $ruleref ) = @_; + + return $ruleref->{cmd} if exists $ruleref->{cmd}; + + my $string = ''; + + for ( grep ! ( get_opttype( $_, 0 ) & ( CONTROL | TARGET ) ), @{$ruleref->{matches}} ) { + my $value = $ruleref->{$_}; + if ( reftype $value ) { + $string .= "$_=" . join( ',', @$value ) . ' '; + } else { + $string .= "$_=$value "; + } + } + + if ( $ruleref->{target} ) { + $string .= join( ' ', " -$ruleref->{jump}", $ruleref->{target} ); + $string .= join( '', ' ', $ruleref->{targetopts} ) if $ruleref->{targetopts}; + } + + $string .= join( '', ' -m comment --comment "', $ruleref->{comment}, '"' ) if $ruleref->{comment}; + + $string; +} + sub calculate_digest( $ ) { my $chainref = shift; my $rules = ''; for ( @{$chainref->{rules}} ) { if ( $rules ) { - $rules .= ' |' . format_rule( $chainref, $_, 1 ); + $rules .= ' |' . irule_to_string( $_ ); } else { - $rules = format_rule( $chainref, $_, 1 ); + $rules = irule_to_string( $_ ); } } @@ -3857,7 +3885,10 @@ sub optimize_level8( $$$ ) { %renamed = (); while ( $progress ) { - my @chains = ( sort { level8_compare($a, $b) } ( grep $_->{referenced} && ! $_->{builtin}, values %{$tableref} ) ); + my @chains = ( sort { level8_compare($a, $b) } ( grep $_->{referenced} && + @{$_->{rules}} && + ! $_->{builtin}, + values %{$tableref} ) ); my @chains1 = @chains; my $chains = @chains; my %rename; @@ -3877,12 +3908,11 @@ sub optimize_level8( $$$ ) { # Shift the current $chainref off of @chains1 # shift @chains1; - # - # Skip empty chains - # - for my $chainref1 ( @chains1 ) { - next unless @{$chainref1->{rules}}; - next if $chainref1->{optflags} & DONT_DELETE; + + for my $chainref1 (grep ! ( $_->{optflags} & DONT_DELETE ), @chains1 ) { + # + # Chains identical? + # if ( $chainref->{digest} eq $chainref1->{digest} ) { progress_message " Chain $chainref1->{name} combined with $chainref->{name}"; $progress = 1; @@ -8199,19 +8229,8 @@ sub add_interface_options( $ ) { # Generate a digest for each chain # for my $chainref ( values %input_chains, values %forward_chains ) { - my $digest = ''; - assert( $chainref ); - - for ( @{$chainref->{rules}} ) { - if ( $digest ) { - $digest .= ' |' . format_rule( $chainref, $_, 1 ); - } else { - $digest = format_rule( $chainref, $_, 1 ); - } - } - - $chainref->{digest} = sha1_hex $digest; + calculate_digest( $chainref ); } # # Insert jumps to the interface chains into the rules chains @@ -8509,7 +8528,7 @@ sub save_dynamic_chains() { ); if ( have_capability 'IPTABLES_S' ) { - emit <<"EOF"; + emithd <<"EOF"; if chain_exists 'UPnP -t nat'; then $tool -t nat -S UPnP | tail -n +2 > \${VARDIR}/.UPnP else @@ -8530,6 +8549,7 @@ fi EOF if ( $config{MINIUPNPD} ) { emit << "EOF"; + if chain_exists 'MINIUPNPD-POSTROUTING -t nat'; then $tool -t nat -S MINIUPNPD-POSTROUTING | tail -n +2 > \${VARDIR}/.MINIUPNPD-POSTROUTING else @@ -8538,7 +8558,7 @@ fi EOF } } else { - emit <<"EOF"; + emithd <<"EOF"; if chain_exists 'UPnP -t nat'; then $utility -t nat | grep '^-A UPnP ' > \${VARDIR}/.UPnP else @@ -8558,7 +8578,8 @@ else fi EOF if ( $config{MINIUPNPD} ) { - emit << "EOF"; + emithd << "EOF"; + if chain_exists 'MINIUPNPD-POSTROUTING -t nat'; then $utility -t nat | grep '^-A MINIUPNPD-POSTROUTING' > \${VARDIR}/.MINIUPNPD-POSTROUTING else @@ -8572,7 +8593,7 @@ EOF emit ( 'else' ); push_indent; -emit <<"EOF"; +emithd <<"EOF"; rm -f \${VARDIR}/.UPnP rm -f \${VARDIR}/.forwardUPnP EOF @@ -8609,7 +8630,7 @@ sub ensure_ipsets( @ ) { pop_indent; - emit( qq( fi\n) ); + emit( q( fi) ); } @@ -8785,7 +8806,6 @@ sub create_load_ipsets() { ' $IPSET flush $set' , ' $IPSET destroy $set' , " done" , - '', ); } else { # @@ -8797,7 +8817,7 @@ sub create_load_ipsets() { ' fi' ); }; - emit( '}' ); + emit( "}\n" ); } # # Now generate load_ipsets() @@ -8866,20 +8886,17 @@ sub create_load_ipsets() { ensure_ipsets( @ipsets ); emit( 'elif [ "$COMMAND" = refresh ]; then' ); ################### Refresh Command ################### - emit ( '' ); ensure_ipsets( @ipsets ); - emit ( '' ); }; - emit ( 'fi' , - '' ); + emit ( 'fi' ); } else { emit 'true'; } pop_indent; - emit '}'; + emit "}\n"; } # @@ -9052,7 +9069,7 @@ sub create_netfilter_load( $ ) { "cat \${VARDIR}/.${utility}-input | \$command # Use this nonsensical form to appease SELinux", 'if [ $? != 0 ]; then', qq( fatal_error "iptables-restore Failed. Input is in \${VARDIR}/.${utility}-input"), - "fi\n" + 'fi' ); pop_indent; diff --git a/Shorewall/Perl/Shorewall/Compiler.pm b/Shorewall/Perl/Shorewall/Compiler.pm index 903d26386..25b15229d 100644 --- a/Shorewall/Perl/Shorewall/Compiler.pm +++ b/Shorewall/Perl/Shorewall/Compiler.pm @@ -103,7 +103,7 @@ sub generate_script_1( $ ) { copy2( $lib, $debug ) if -f $lib; - emit <<'EOF'; + emithd<<'EOF'; ################################################################################ # Functions to execute the various user exits (extension scripts) ################################################################################ @@ -125,7 +125,7 @@ EOF emit '}'; } - emit <<'EOF'; + emithd <<'EOF'; ################################################################################ # End user exit functions ################################################################################ @@ -270,12 +270,11 @@ sub generate_script_2() { ); emit( 'chain_exists DOCKER-INGRESS && g_dockeringress=Yes' ); emit( 'chain_exists DOCKER-ISOLATION && g_dockernetwork=Yes' ); - emit( '' ); } pop_indent; - emit "\n}\n"; # End of initialize() + emit "}\n"; # End of initialize() emit( '' , '#' , @@ -525,7 +524,7 @@ sub generate_script_3($) { my $config_dir = $globals{CONFIGDIR}; - emit<<"EOF"; + emithd <<"EOF"; set_state Started $config_dir run_restored_exit elif [ \$COMMAND = refresh ]; then @@ -572,7 +571,7 @@ EOF ' run_started_exit', "fi\n" ); - emit<<'EOF'; + emithd<<'EOF'; date > ${VARDIR}/restarted case $COMMAND in diff --git a/Shorewall/Perl/Shorewall/Config.pm b/Shorewall/Perl/Shorewall/Config.pm index c5efd49fd..5477ad410 100644 --- a/Shorewall/Perl/Shorewall/Config.pm +++ b/Shorewall/Perl/Shorewall/Config.pm @@ -189,6 +189,7 @@ our %EXPORT_TAGS = ( internal => [ qw( create_temp_script in_hex8 in_hexp emit + emithd emitstd emit_unindented save_progress_message @@ -835,7 +836,7 @@ sub initialize( $;$$$) { TC_SCRIPT => '', EXPORT => 0, KLUDGEFREE => '', - VERSION => "5.1.8-Beta1", + VERSION => "5.1.12-Beta2", CAPVERSION => 50112 , BLACKLIST_LOG_TAG => '', RELATED_LOG_TAG => '', @@ -1689,6 +1690,7 @@ sub emit { $line =~ s/^\n// if $lastlineblank; $line =~ s/^/$indent/gm if $indent; $line =~ s/ /\t/gm; + $line =~ s/[ \t]+\n/\n/gm; print $script "$line\n" if $script; $lastlineblank = ( substr( $line, -1, 1 ) eq "\n" ); @@ -1709,6 +1711,15 @@ sub emit { } } +# +# Used to emit a 'here documents' string without introducing an unwanted blank line at the end +# +sub emithd( $ ) { + my ( $line ) = @_; #make writable + chomp $line; + emit $line; +} + # # Version of emit() that writes to standard out unconditionally # @@ -1719,6 +1730,7 @@ sub emitstd { $line =~ s/^\n// if $lastlineblank; $line =~ s/^/$indent/gm if $indent; $line =~ s/ /\t/gm; + $line =~ s/[ \t]+\n/\n/gm; print "$line\n"; $lastlineblank = ( substr( $line, -1, 1 ) eq "\n" ); } else { diff --git a/Shorewall/Perl/Shorewall/Misc.pm b/Shorewall/Perl/Shorewall/Misc.pm index 25fe3fd09..b94c35a0f 100644 --- a/Shorewall/Perl/Shorewall/Misc.pm +++ b/Shorewall/Perl/Shorewall/Misc.pm @@ -2646,7 +2646,6 @@ EOF rm -f ${VARDIR}/proxyarp fi - EOF } else { emit <<'EOF'; @@ -2660,7 +2659,6 @@ EOF rm -f ${VARDIR}/proxyndp fi - EOF } diff --git a/Shorewall/Perl/Shorewall/Providers.pm b/Shorewall/Perl/Shorewall/Providers.pm index a4ae0f6ee..630992103 100644 --- a/Shorewall/Perl/Shorewall/Providers.pm +++ b/Shorewall/Perl/Shorewall/Providers.pm @@ -876,7 +876,7 @@ sub add_a_provider( $$ ) { } emit( "run_ip route replace default via $gateway src $address dev $physical ${mtu}table $id $realm" ); - emit( qq( echo "\$IP route del default via $gateway src $address dev $physical ${mtu}table $id $realm > /dev/null 2>&1" >> \${VARDIR}/undo_${table}_routing) ); + emit( qq(echo "\$IP route del default via $gateway src $address dev $physical ${mtu}table $id $realm > /dev/null 2>&1" >> \${VARDIR}/undo_${table}_routing) ); } if ( ! $noautosrc ) { @@ -885,7 +885,8 @@ sub add_a_provider( $$ ) { emit( "run_ip rule add from $address pref 20000 table $id" , "echo \"\$IP -$family rule del from $address pref 20000> /dev/null 2>&1\" >> \${VARDIR}/undo_${table}_routing" ); } else { - emit ( "find_interface_addresses $physical | while read address; do", + emit ( '', + "find_interface_addresses $physical | while read address; do", " qt \$IP -$family rule del from \$address", " run_ip rule add from \$address pref 20000 table $id", " echo \"\$IP -$family rule del from \$address pref 20000 > /dev/null 2>&1\" >> \${VARDIR}/undo_${table}_routing", @@ -1250,7 +1251,7 @@ CEOF 'if [ $COMMAND = disable ]; then', " do_persistent_${what}_${table}", "else", - " echo 1 > \${VARDIR}/${physical}_disabled\n", + " echo 1 > \${VARDIR}/${physical}_disabled", "fi\n", ); } @@ -1593,7 +1594,8 @@ sub finish_providers() { } if ( $config{USE_DEFAULT_RT} ) { - emit ( " while qt \$IP -$family route del default table $main; do", + emit ( '', + " while qt \$IP -$family route del default table $main; do", ' true', ' done', '' @@ -1739,7 +1741,7 @@ sub process_providers( $ ) { add_a_provider( $providers{$_}, $tcdevices ) for @providers; - emit << 'EOF';; + emithd << 'EOF';; # # Enable an optional provider @@ -1785,12 +1787,11 @@ EOF pop_indent; pop_indent; - emit << 'EOF';; + emithd << 'EOF';; *) startup_error "$g_interface is not an optional provider or interface" ;; esac - } # @@ -1894,20 +1895,19 @@ sub setup_providers() { start_providers; - setup_null_routing if $config{NULL_ROUTE_RFC1918}; + setup_null_routing, emit '' if $config{NULL_ROUTE_RFC1918}; - emit ''; - - emit "start_$providers{$_}->{what}_$_" for @providers; - - emit ''; + if ( @providers ) { + emit "start_$providers{$_}->{what}_$_" for @providers; + emit ''; + } finish_providers; emit "\nrun_ip route flush cache"; pop_indent; - emit "fi\n"; + emit 'fi'; setup_route_marking if @routemarked_interfaces || @load_interfaces; } else { @@ -1918,9 +1918,10 @@ sub setup_providers() { if ( $pseudoproviders ) { emit ''; emit "start_$providers{$_}->{what}_$_" for @providers; + emit ''; } - emit "\nundo_routing"; + emit "undo_routing"; emit "restore_default_route $config{USE_DEFAULT_RT}"; my $standard_routes = @{$providers{main}{routes}} || @{$providers{default}{routes}}; @@ -1945,7 +1946,7 @@ sub setup_providers() { pop_indent; - emit "fi\n"; + emit 'fi'; } } diff --git a/Shorewall/Perl/Shorewall/Proxyarp.pm b/Shorewall/Perl/Shorewall/Proxyarp.pm index fe6add514..1ed42f6a0 100644 --- a/Shorewall/Perl/Shorewall/Proxyarp.pm +++ b/Shorewall/Perl/Shorewall/Proxyarp.pm @@ -96,6 +96,7 @@ sub setup_one_proxy_arp( $$$$$$$ ) { } emit ( "run_ip neigh add proxy $address nud permanent dev $extphy" , + '' , qq(progress_message " Host $address connected to $interface added to $proto on $extphy"\n) ); push @proxyarp, "$address $interface $external $haveroute"; diff --git a/Shorewall/manpages/shorewall.conf.xml b/Shorewall/manpages/shorewall.conf.xml index 906d6f3bd..f1ca66fec 100644 --- a/Shorewall/manpages/shorewall.conf.xml +++ b/Shorewall/manpages/shorewall.conf.xml @@ -2134,6 +2134,14 @@ LOG:info:,bar net fw Optimization category 8 - Added in Shorewall 4.4.9. When set, causes chains with identical rules to be collapsed into a single chain. + + + While Optimization category 8 can significantly reduce + the size of the generated iptables ruleset, it can also take + significant system resources during compilation. If you find + that compilation takes an unreasonably long time, try + disabling this category by setting OPTIMIZE=23. + @@ -2206,7 +2214,8 @@ LOG:info:,bar net fw In versions prior to 5.1.0, the default value is zero which disables all optimizations. Beginning with Shorewall 5.1.0, the - default value is All which enables all optimizations. + default value is All which enables + all optimizations. diff --git a/docs/Actions.xml b/docs/Actions.xml index cdd989d0f..c591be9df 100644 --- a/docs/Actions.xml +++ b/docs/Actions.xml @@ -81,8 +81,9 @@ Built-in Actions. These actions are known by the Shorewall code - itself. They are listed in the comments at the top of the file - /usr/share/shorewall/actions.std. + itself. They were formerly listed in the comments at the top of the + file /usr/share/shorewall/actions.std. They have + now been replaced by Standard Actions. @@ -115,8 +116,11 @@ ACCEPT - - tcp 135,139,445 file to /etc/shorewall (or somewhere else on your CONFIG_PATH) and modify the copy. - Standard Actions have been largely replaced by macros . + You can see a list of the standard actions with a short + description of each action using the shorewall show + actions command. You can display the contents of + action.name by typing shorewall + show action name. diff --git a/docs/FAQ.xml b/docs/FAQ.xml index 27df3840d..9e356c68a 100644 --- a/docs/FAQ.xml +++ b/docs/FAQ.xml @@ -2225,7 +2225,8 @@ Creating input Chains... Don't start Shorewall at boot time (Debian and Ubuntu users may simply set startup=0 in - /etc/default/shorewall). + /etc/default/shorewall) or disable in systemd + using systemctl disable shorewall.service. @@ -2349,6 +2350,22 @@ gateway:~# reload avoids the stop part. + + + Use a capabilities file: + + + + Run shorewall show -f capabilties > + /etc/shorewall/capabilities + + + + Rerun that command each time you install a new kernel or a + new version of shorewall. + + + diff --git a/docs/Macros.xml b/docs/Macros.xml index 712d166c3..161953ec4 100644 --- a/docs/Macros.xml +++ b/docs/Macros.xml @@ -102,6 +102,14 @@ PARAM - - tcp 135,139,445 somewhere else on your CONFIG_PATH) and modify the copy. + + You can see a list of the Standard Macros in your version of + Shorewall using the shorewall show macros command. + You can see the contents of the file + macro.name by typing shorewall + show macro name. + + User-defined Macros. These macros are created by end-users. They are defined in macro.* files in /etc/shorewall or in another directory @@ -796,19 +804,20 @@ bar:debug - You can not associate an Extension Script with a macro the way that you can with an - Action. So if you need access to iptables features not - directly supported by Shorewall then you must use an action. + Embedded Perl is much more useful in an + action than it is in a macro. So if you need access to + iptables features not directly supported by Shorewall then you should + use an action. - Macros are expanded in-line while each action is its own chain. - So if there are a lot of rules involved in your new action/macro then - it is generally better to use an action than a macro. Only the packets - selected when you invoke the action are directed to the corresponding - chain. On the other hand, if there are only one or two rules involved - in what you want to do then a macro is more efficient. + Macros are expanded in-line while each action (that doesn't + specify the inline option) is its own chain. So if there are a lot of + rules involved in your new action/macro then it is generally better to + use an action than a macro. Only the packets selected when you invoke + the action are directed to the corresponding chain. On the other hand, + if there are only one or two rules involved in what you want to do + then a macro is more efficient.