From cddd1b1ae9da7d48f0be89e208f11db6b668e6f4 Mon Sep 17 00:00:00 2001 From: teastep Date: Mon, 30 Mar 2009 00:49:00 +0000 Subject: [PATCH] Use iptables[6]-restore to instantiate the 'stopped' ruleset Signed-off-by: Tom Eastep git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@9761 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- Shorewall/Perl/Shorewall/Chains.pm | 94 ++++++++++ Shorewall/Perl/Shorewall/Compiler.pm | 19 +- Shorewall/Perl/Shorewall/Rules.pm | 261 +++++---------------------- Shorewall/changelog.txt | 2 + Shorewall/releasenotes.txt | 5 + 5 files changed, 162 insertions(+), 219 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index f4ee61d77..9d7086acb 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -156,6 +156,7 @@ our %EXPORT_TAGS = ( set_global_variables create_netfilter_load create_chainlist_reload + create_stop_load $section %sections %targets @@ -2972,4 +2973,97 @@ sub create_chainlist_reload($) { emit "}\n"; } +# +# Generate the netfilter input to stop the firewall +# +sub create_stop_load( $ ) { + my $test = shift; + + my @table_list; + + if ( $family == F_IPV4 ) { + push @table_list, 'raw' if $capabilities{RAW_TABLE}; + push @table_list, 'nat' if $capabilities{NAT_ENABLED}; + push @table_list, 'mangle' if $capabilities{MANGLE_ENABLED} && $config{MANGLE_ENABLED}; + push @table_list, 'filter'; + } else { + @table_list = qw( raw mangle filter ); + } + + $mode = NULL_MODE; + + my $utility = $family == F_IPV4 ? 'iptables-restore' : 'ip6tables-restore'; + my $UTILITY = $family == F_IPV4 ? 'IPTABLES_RESTORE' : 'IP6TABLES_RESTORE'; + + emit ''; + + emit "exec 3>\${VARDIR}/.${utility}-stop-input"; + + enter_cat_mode; + + my $date = localtime; + + unless ( $test ) { + emit_unindented '#'; + emit_unindented "# Generated by Shorewall-perl $globals{VERSION} - $date"; + emit_unindented '#'; + } + + for my $table ( @table_list ) { + emit_unindented "*$table"; + + my @chains; + # + # iptables-restore seems to be quite picky about the order of the builtin chains + # + for my $chain ( @builtins ) { + my $chainref = $chain_table{$table}{$chain}; + if ( $chainref ) { + assert( $chainref->{cmdlevel} == 0 ); + emit_unindented ":$chain $chainref->{policy} [0:0]"; + push @chains, $chainref; + } + } + # + # First create the chains in the current table + # + for my $chain ( grep $chain_table{$table}{$_}->{referenced} , ( sort keys %{$chain_table{$table}} ) ) { + my $chainref = $chain_table{$table}{$chain}; + unless ( $chainref->{builtin} ) { + assert( $chainref->{cmdlevel} == 0 ); + emit_unindented ":$chainref->{name} - [0:0]"; + push @chains, $chainref; + } + } + # + # Then emit the rules + # + for my $chainref ( @chains ) { + emitr $chainref->{name}, $_ for ( grep defined $_, @{$chainref->{rules}} ); + } + # + # Commit the changes to the table + # + enter_cat_mode unless $mode == CAT_MODE; + emit_unindented 'COMMIT'; + } + + enter_cmd_mode; + # + # Now generate the actual ip[6]tables-restore command + # + emit( 'exec 3>&-', + '', + '[ -n "$DEBUG" ] && command=debug_restore_input || command=$' . $UTILITY, + '', + 'progress_message2 "Running $command..."', + '', + "cat \${VARDIR}/.${utility}-stop-input | \$command # Use this nonsensical form to appease SELinux", + 'if [ $? != 0 ]; then', + qq( fatal_error "$command Failed. Input is in \${VARDIR}/.${utility}-stop-input"), + "fi\n" + ); + +} + 1; diff --git a/Shorewall/Perl/Shorewall/Compiler.pm b/Shorewall/Perl/Shorewall/Compiler.pm index b419f5308..fbf525347 100644 --- a/Shorewall/Perl/Shorewall/Compiler.pm +++ b/Shorewall/Perl/Shorewall/Compiler.pm @@ -516,13 +516,6 @@ EOF emit "}\n"; - unless ( $test ) { - if ( $family == F_IPV4 ) { - copy $globals{SHAREDIRPL} . 'prog.footer'; - } else { - copy $globals{SHAREDIRPL} . 'prog.footer6'; - } - } } # @@ -805,7 +798,17 @@ sub compiler { # S T O P _ F I R E W A L L # (Writes the stop_firewall() function to the compiled script) # - compile_stop_firewall; + compile_stop_firewall( $test ); + # + # Copy the footer to the object + # + unless ( $test ) { + if ( $family == F_IPV4 ) { + copy $globals{SHAREDIRPL} . 'prog.footer'; + } else { + copy $globals{SHAREDIRPL} . 'prog.footer6'; + } + } # # Close, rename and secure the object # diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index a382cf0c3..4c651c1c6 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -39,7 +39,6 @@ our @EXPORT = qw( process_tos setup_ecn add_common_rules setup_mac_lists - process_criticalhosts process_routestopped process_rules generate_matrix @@ -364,52 +363,6 @@ sub setup_blacklist() { } } -sub process_criticalhosts() { - - my @critical = (); - - my $fn = open_file 'routestopped'; - - my $seq = 0; - - first_entry "$doing $fn for critical hosts..."; - - while ( read_a_line ) { - - my $routeback = 0; - - my ($interface, $hosts, $options, $proto, $ports, $sports ) = split_line 1, 6, 'routestopped file'; - - fatal_error "Unknown interface ($interface)" unless known_interface $interface; - - $hosts = ALLIP unless $hosts ne '-'; - - my @hosts; - - $seq++; - - for my $host ( split_list $hosts, 'host' ) { - validate_host $host, 1; - push @hosts, "$interface|$host|$seq"; - } - - unless ( $options eq '-' ) { - for my $option (split_list $options, 'option' ) { - unless ( $option eq 'routeback' || $option eq 'source' || $option eq 'dest' || $option eq 'notrack' ) { - if ( $option eq 'critical' ) { - fatal_error "PROTO may not be specified with 'critical'" if $proto ne '-'; - push @critical, @hosts; - } else { - warning_message "Unknown routestopped option ( $option ) ignored"; - } - } - } - } - } - - \@critical; -} - sub process_routestopped() { my ( @allhosts, %source, %dest , %notrack, @rule ); @@ -472,6 +425,7 @@ sub process_routestopped() { } } else { warning_message "Unknown routestopped option ( $option ) ignored" unless $option eq 'critical'; + warning_message "The 'critical' option is no longer supported (or needed)"; } } } @@ -479,8 +433,6 @@ sub process_routestopped() { push @allhosts, @hosts; } - my $tool = $family == F_IPV4 ? '$IPTABLES' : '$IP6TABLES'; - for my $host ( @allhosts ) { my ( $interface, $h, $seq ) = split /\|/, $host; my $source = match_source_net $h; @@ -489,24 +441,24 @@ sub process_routestopped() { my $desti = match_dest_dev $interface; my $rule = shift @rule; - emit "$tool -A INPUT $sourcei $source $rule -j ACCEPT"; - emit "$tool -A OUTPUT $desti $dest $rule -j ACCEPT" unless $config{ADMINISABSENTMINDED}; + add_rule $filter_table->{INPUT}, "$sourcei $source $rule -j ACCEPT"; + add_rule $filter_table->{OUTPUT}, "$desti $dest $rule -j ACCEPT" unless $config{ADMINISABSENTMINDED}; my $matched = 0; if ( $source{$host} ) { - emit "$tool -A FORWARD $sourcei $source $rule -j ACCEPT"; + add_rule $filter_table->{FORWARD}, "$sourcei $source $rule -j ACCEPT"; $matched = 1; } if ( $dest{$host} ) { - emit "$tool -A FORWARD $desti $dest $rule -j ACCEPT"; + add_rule $filter_table->{FORWARD}, "$desti $dest $rule -j ACCEPT"; $matched = 1; } if ( $notrack{$host} ) { - emit "$tool -t raw -A PREROUTING $sourcei $source $rule -j NOTRACK"; - emit "$tool -t raw -A OUTPUT $desti $dest $rule -j NOTRACK"; + add_rule $raw_table->{PREROUTING}, "$sourcei $source $rule -j NOTRACK"; + add_rule $raw_table->{OUTPUT}, "$desti $dest $rule -j NOTRACK"; } unless ( $matched ) { @@ -515,7 +467,7 @@ sub process_routestopped() { my ( $interface1, $h1 , $seq1 ) = split /\|/, $host1; my $dest1 = match_dest_net $h1; my $desti1 = match_dest_dev $interface1; - emit "$tool -A FORWARD $sourcei $desti1 $source $dest1 $rule -j ACCEPT"; + add_rule $filter_table->{FORWARD}, "$sourcei $desti1 $source $dest1 $rule -j ACCEPT"; clearrule; } } @@ -2117,7 +2069,8 @@ sub setup_mss( ) { # # Compile the stop_firewall() function # -sub compile_stop_firewall() { +sub compile_stop_firewall( $ ) { + my $test = shift; emit <<'EOF'; # @@ -2126,6 +2079,14 @@ sub compile_stop_firewall() { stop_firewall() { EOF + Shorewall::Chains::initialize( $family ); + + initialize_chain_table; + + if ( $config{ADMINISABSENTMINDED} ) { + $filter_table->{OUTPUT}{policy} = 'ACCEPT'; + } + if ( $family == F_IPV4 ) { emit( ' deletechain() {', ' qt $IPTABLES -L $1 -n && qt $IPTABLES -F $1 && qt $IPTABLES -X $1' ); @@ -2137,24 +2098,6 @@ EOF emit <<'EOF'; } - deleteallchains() { - do_iptables -F - do_iptables -X - } - - delete_nat() { - do_iptables -t nat -F - do_iptables -t nat -X - - if [ -f ${VARDIR}/nat ]; then - while read external interface; do - del_ip_addr $external $interface - done < ${VARDIR}/nat - - rm -f ${VARDIR}/nat - fi - } - case $COMMAND in stop|clear|restore) ;; @@ -2211,42 +2154,15 @@ EOF run_stop_exit EOF - if ( $capabilities{MANGLE_ENABLED} && $config{MANGLE_ENABLED} ) { - emit <<'EOF'; - run_iptables -t mangle -F - run_iptables -t mangle -X - for chain in PREROUTING INPUT FORWARD POSTROUTING; do - qt1 $IPTABLES -t mangle -P $chain ACCEPT - done -EOF - } - - if ( $capabilities{RAW_TABLE} ) { - if ( $family == F_IPV4 ) { - emit <<'EOF'; - run_iptables -t raw -F - run_iptables -t raw -X - for chain in PREROUTING OUTPUT; do - qt1 $IPTABLES -t raw -P $chain ACCEPT - done -EOF - } else { - emit <<'EOF'; - run_iptables -t raw -F - run_iptables -t raw -X - for chain in PREROUTING OUTPUT; do - qt1 $IP6TABLES -t raw -P $chain ACCEPT - done -EOF - } - } - if ( $capabilities{NAT_ENABLED} ) { - emit <<'EOF'; - delete_nat - for chain in PREROUTING POSTROUTING OUTPUT; do - qt1 $IPTABLES -t nat -P $chain ACCEPT - done + emit<<'EOF'; + if [ -f ${VARDIR}/nat ]; then + while read external interface; do + del_ip_addr $external $interface + done < ${VARDIR}/nat + + rm -f ${VARDIR}/nat + fi EOF } @@ -2259,9 +2175,10 @@ EOF f=/proc/sys/net/ipv4/conf/$interface/proxy_arp [ -f $f ] && echo 0 > $f done < ${VARDIR}/proxyarp + + rm -f ${VARDIR}/proxyarp fi - rm -f ${VARDIR}/proxyarp EOF } @@ -2273,109 +2190,27 @@ EOF 'restore_default_route' ); - my $criticalhosts = process_criticalhosts; - - if ( @$criticalhosts ) { - if ( $config{ADMINISABSENTMINDED} ) { - emit ( 'for chain in INPUT OUTPUT; do', - ' setpolicy $chain ACCEPT', - 'done', - '', - 'setpolicy FORWARD DROP', - '', - 'deleteallchains', - '' - ); - - for my $hosts ( @$criticalhosts ) { - my ( $interface, $host, $seq ) = ( split /\|/, $hosts ); - my $source = match_source_net $host; - my $dest = match_dest_net $host; - - emit( "do_iptables -A INPUT -i $interface $source -j ACCEPT", - "do_iptables -A OUTPUT -o $interface $dest -j ACCEPT" - ); - } - - emit( '', - 'for chain in INPUT OUTPUT; do', - ' setpolicy $chain DROP', - "done\n" - ); - } else { - emit( '', - 'for chain in INPUT OUTPUT; do', - ' setpolicy $chain ACCEPT', - 'done', - '', - 'setpolicy FORWARD DROP', - '', - "deleteallchains\n" - ); - - for my $hosts ( @$criticalhosts ) { - my ( $interface, $host , $seq ) = ( split /|/, $hosts ); - my $source = match_source_net $host; - my $dest = match_dest_net $host; - - emit( "do_iptables -A INPUT -i $interface $source -j ACCEPT", - "do_iptables -A OUTPUT -o $interface $dest -j ACCEPT" - ); - } - - emit( "\nsetpolicy INPUT DROP", - '', - 'for chain in INPUT FORWARD; do', - ' setcontinue $chain', - "done\n" - ); - } - } elsif ( $config{ADMINISABSENTMINDED} ) { - emit( 'for chain in INPUT FORWARD; do', - ' setpolicy $chain DROP', - 'done', - '', - 'setpolicy OUTPUT ACCEPT', - '', - 'deleteallchains', - '', - 'for chain in INPUT FORWARD; do', - ' setcontinue $chain', - "done\n", - ); - } else { - emit( 'for chain in INPUT OUTPUT FORWARD; do', - ' setpolicy $chain DROP', - 'done', - '', - "deleteallchains\n" - ); - } + my @chains = $config{ADMINISABSENTMINDED} ? qw/INPUT FORWARD/ : qw/INPUT OUTPUT FORWARD/; + + add_rule $filter_table->{$_}, '-m state --state ESTABLISHED,RELATED -j ACCEPT' for @chains; if ( $family == F_IPV6 ) { - emit <<'EOF'; - # - # Enable link local and multi-cast - # - run_iptables -A INPUT -s ff80::/10 -j ACCEPT - run_iptables -A INPUT -d ff80::/10 -j ACCEPT - run_iptables -A INPUT -d ff00::/10 -j ACCEPT -EOF + add_rule $filter_table->{INPUT}, '-s ff80::/10 -j ACCEPT'; + add_rule $filter_table->{INPUT}, '-d ff80::/10 -j ACCEPT'; + add_rule $filter_table->{INPUT}, '-d ff00::/10 -j ACCEPT'; - emit <<'EOF' unless $config{ADMINISABSENTMINDED}; - run_iptables -A OUTPUT -d ff80::/10 -j ACCEPT - run_iptables -A OUTPUT -d ff00::/10 -j ACCEPT - -EOF + unless ( $config{ADMINISABSENTMINDED} ) { + add_rule $filter_table->{OUTPUT}, '-d ff80::/10 -j ACCEPT'; + add_rule $filter_table->{OUTPUT}, '-d ff00::/10 -j ACCEPT'; + } } process_routestopped; - emit( 'do_iptables -A INPUT -i lo -j ACCEPT', - 'do_iptables -A OUTPUT -o lo -j ACCEPT' - ); + add_rule $filter_table->{INPUT}, '-i lo -j ACCEPT'; + add_rule $filter_table->{INPUT}, '-i lo -j ACCEPT'; - emit 'do_iptables -A OUTPUT -o lo -j ACCEPT' unless $config{ADMINISABSENTMINDED}; + add_rule $filter_table->{OUTPUT}, '-o lo -j ACCEPT' unless $config{ADMINISABSENTMINDED}; my $interfaces = find_interfaces_by_option 'dhcp'; @@ -2383,17 +2218,19 @@ EOF my $ports = $family == F_IPV4 ? '67:68' : '546:547'; for my $interface ( @$interfaces ) { - emit "do_iptables -A INPUT -p udp -i $interface --dport $ports -j ACCEPT"; - emit "do_iptables -A OUTPUT -p udp -o $interface --dport $ports -j ACCEPT" unless $config{ADMINISABSENTMINDED}; + add_rule $filter_table->{INPUT}, "-p udp -i $interface --dport $ports -j ACCEPT"; + add_rule $filter_table->{OUTPUT}, "-p udp -o $interface --dport $ports -j ACCEPT" unless $config{ADMINISABSENTMINDED}; # # This might be a bridge # - emit "do_iptables -A FORWARD -p udp -i $interface -o $interface --dport $ports -j ACCEPT"; + add_rule $filter_table->{FORWARD}, "-p udp -i $interface -o $interface --dport $ports -j ACCEPT"; } } emit ''; + create_stop_load $test; + if ( $family == F_IPV4 ) { if ( $config{IP_FORWARDING} eq 'on' ) { emit( 'echo 1 > /proc/sys/net/ipv4/ip_forward', @@ -2426,7 +2263,7 @@ EOF my @ipsets = all_ipsets; if ( @ipsets ) { - emit <<'EOF' + emit <<'EOF'; if [ -n "$(mywhich ipset)" ]; then if ipset -S > ${VARDIR}/ipsets.tmp; then @@ -2435,8 +2272,10 @@ EOF # grep -q '^-N' ${VARDIR}/ipsets.tmp && mv -f ${VARDIR}/ipsets.tmp ${VARDIR}/ipsets.save fi - fi EOF + + emit " ipset -X $_" for @ipsets; + emit "fi\n"; } emit ' diff --git a/Shorewall/changelog.txt b/Shorewall/changelog.txt index f6130667e..3ffffb9b8 100644 --- a/Shorewall/changelog.txt +++ b/Shorewall/changelog.txt @@ -10,6 +10,8 @@ Changes in Shorewall 4.3.8 5) Suppress leading whitespace on certain continuation lines. +6) Use iptables[6]-restore to stop the firewall. + Changes in Shorewall 4.3.7 1) Fix forward treatment of interface options. diff --git a/Shorewall/releasenotes.txt b/Shorewall/releasenotes.txt index 7e910d4d6..35348b301 100644 --- a/Shorewall/releasenotes.txt +++ b/Shorewall/releasenotes.txt @@ -83,6 +83,11 @@ None. address is ignored so the SOURCE column effectively contains "net:206.124.146.177,206.124.147.178,206.124.146.180". +4) The generated script now uses iptables[6]-restore to instantiate + the Netfilter ruleset during processing of the 'stop' command. As a + consequence, the 'critical' option in /etc/shorewall/route_stopped + is no longer needed and will result in a warning. + ---------------------------------------------------------------------------- N E W F E A T U R E S IN 4 . 3 ----------------------------------------------------------------------------