From d9622dabfe0af349c9e9684af06017719e236c96 Mon Sep 17 00:00:00 2001 From: teastep Date: Sat, 28 Mar 2009 19:21:36 +0000 Subject: [PATCH] Centralize iptables knowledge in the Chains module -- first phase Signed-off-by: Tom Eastep git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@9742 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- Shorewall/Perl/Shorewall/Chains.pm | 43 +++ Shorewall/Perl/Shorewall/Compiler.pm | 392 +-------------------------- Shorewall/Perl/Shorewall/Config.pm | 3 + Shorewall/releasenotes.txt | 4 +- 4 files changed, 55 insertions(+), 387 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index 448d5723c..2f9f8df80 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -144,6 +144,8 @@ our %EXPORT_TAGS = ( log_rule expand_rule addnatjump + set_chain_variables + mark_firewall_not_started get_interface_address get_interface_addresses get_interface_bcasts @@ -152,6 +154,7 @@ our %EXPORT_TAGS = ( get_interface_mac have_global_variables set_global_variables + compile_stop_firewall create_netfilter_load create_chainlist_reload $section @@ -2001,6 +2004,46 @@ sub mysplit( $ ) { @result; } +# +# Set up the IPTABLES-related run-time variables +# +sub set_chain_variables() { + if ( $family == F_IPV4 ) { + if ( $config{IPTABLES} ) { + emit( qq(IPTABLES="$config{IPTABLES}"), + '[ -x "$IPTABLES" ] || startup_error "IPTABLES=$IPTABLES does not exist or is not executable"', + ); + } else { + emit( '[ -z "$IPTABLES" ] && IPTABLES=$(mywhich iptables) # /sbin/shorewall exports IPTABLES', + '[ -n "$IPTABLES" -a -x "$IPTABLES" ] || startup_error "Can\'t find iptables executable"' + ); + } + + emit( 'IPTABLES_RESTORE=${IPTABLES}-restore', + '[ -x "$IPTABLES_RESTORE" ] || startup_error "$IPTABLES_RESTORE does not exist or is not executable"' ); + } else { + if ( $config{IP6TABLES} ) { + emit( qq(IP6TABLES="$config{IP6TABLES}"), + '[ -x "$IP6TABLES" ] || startup_error "IP6TABLES=$IP6TABLES does not exist or is not executable"', + ); + } else { + emit( '[ -z "$IP6TABLES" ] && IP6TABLES=$(mywhich ip6tables) # /sbin/shorewall6 exports IP6TABLES', + '[ -n "$IP6TABLES" -a -x "$IP6TABLES" ] || startup_error "Can\'t find ip6tables executable"' + ); + } + + emit( 'IP6TABLES_RESTORE=${IP6TABLES}-restore', + '[ -x "$IP6TABLES_RESTORE" ] || startup_error "$IP6TABLES_RESTORE does not exist or is not executable"' ); + } +} + +# +# Emit code that marks the firewall as not started. +# +sub mark_firewall_not_started() { + emit ( 'qt1 $IPTABLES -L shorewall -n && qt1 $IPTABLES -F shorewall && qt1 $IPTABLES -X shorewall' ); +} + #################################################################################################################### # The following functions come in pairs. The first function returns the name of a run-time shell variable that # will hold a piece of interface-oriented data detected at run-time. The second creates a code fragment to detect diff --git a/Shorewall/Perl/Shorewall/Compiler.pm b/Shorewall/Perl/Shorewall/Compiler.pm index 1e778cb34..89c153bf2 100644 --- a/Shorewall/Perl/Shorewall/Compiler.pm +++ b/Shorewall/Perl/Shorewall/Compiler.pm @@ -208,33 +208,7 @@ sub generate_script_2() { '' ); - if ( $family == F_IPV4 ) { - if ( $config{IPTABLES} ) { - emit( qq(IPTABLES="$config{IPTABLES}"), - '[ -x "$IPTABLES" ] || startup_error "IPTABLES=$IPTABLES does not exist or is not executable"', - ); - } else { - emit( '[ -z "$IPTABLES" ] && IPTABLES=$(mywhich iptables) # /sbin/shorewall exports IPTABLES', - '[ -n "$IPTABLES" -a -x "$IPTABLES" ] || startup_error "Can\'t find iptables executable"' - ); - } - - emit( 'IPTABLES_RESTORE=${IPTABLES}-restore', - '[ -x "$IPTABLES_RESTORE" ] || startup_error "$IPTABLES_RESTORE does not exist or is not executable"' ); - } else { - if ( $config{IP6TABLES} ) { - emit( qq(IP6TABLES="$config{IP6TABLES}"), - '[ -x "$IP6TABLES" ] || startup_error "IP6TABLES=$IP6TABLES does not exist or is not executable"', - ); - } else { - emit( '[ -z "$IP6TABLES" ] && IP6TABLES=$(mywhich ip6tables) # /sbin/shorewall6 exports IP6TABLES', - '[ -n "$IP6TABLES" -a -x "$IP6TABLES" ] || startup_error "Can\'t find ip6tables executable"' - ); - } - - emit( 'IP6TABLES_RESTORE=${IP6TABLES}-restore', - '[ -x "$IP6TABLES_RESTORE" ] || startup_error "$IP6TABLES_RESTORE does not exist or is not executable"' ); - } + set_chain_variables; append_file 'params' if $config{EXPORTPARAMS}; @@ -294,354 +268,11 @@ sub generate_script_2() { } -sub compile_stop_firewall() { - - emit <<'EOF'; -# -# Stop/restore the firewall after an error or because of a 'stop' or 'clear' command -# -stop_firewall() { -EOF - - if ( $family == F_IPV4 ) { - emit( ' deletechain() {', - ' qt $IPTABLES -L $1 -n && qt $IPTABLES -F $1 && qt $IPTABLES -X $1' ); - } else { - emit( ' deletechain() {', - ' qt $IP6TABLES -L $1 -n && qt $IP6TABLES -F $1 && qt $IP6TABLES -X $1' ); - } - - 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) - ;; - *) - set +x - - case $COMMAND in - start) - logger -p kern.err "ERROR:$PRODUCT start failed" - ;; - restart) - logger -p kern.err "ERROR:$PRODUCT restart failed" - ;; - restore) - logger -p kern.err "ERROR:$PRODUCT restore failed" - ;; - esac - - if [ "$RESTOREFILE" = NONE ]; then - COMMAND=clear - clear_firewall - echo "$PRODUCT Cleared" - - kill $$ - exit 2 - else - RESTOREPATH=${VARDIR}/$RESTOREFILE - - if [ -x $RESTOREPATH ]; then - echo Restoring ${PRODUCT:=Shorewall}... - - if $RESTOREPATH restore; then - echo "$PRODUCT restored from $RESTOREPATH" - set_state "Started" - else - set_state "Unknown" - fi - - kill $$ - exit 2 - fi - fi - ;; - esac - - set_state "Stopping" - - STOPPING="Yes" - - TERMINATOR= - - deletechain shorewall - - 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 -EOF - } - - if ( $family == F_IPV4 ) { - emit <<'EOF'; - if [ -f ${VARDIR}/proxyarp ]; then - while read address interface external haveroute; do - qt arp -i $external -d $address pub - [ -z "${haveroute}${NOROUTES}" ] && qt ip route del $address dev $interface - f=/proc/sys/net/ipv4/conf/$interface/proxy_arp - [ -f $f ] && echo 0 > $f - done < ${VARDIR}/proxyarp - fi - - rm -f ${VARDIR}/proxyarp -EOF - } - - push_indent; - - emit 'delete_tc1' if $config{CLEAR_TC}; - - emit( 'undo_routing', - '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" - ); - } - - 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 - - emit <<'EOF' unless $config{ADMINISABSENTMINDED}; - run_iptables -A OUTPUT -d ff80::/10 -j ACCEPT - run_iptables -A OUTPUT -d ff00::/10 -j ACCEPT - -EOF - } - - process_routestopped; - - emit( 'do_iptables -A INPUT -i lo -j ACCEPT', - 'do_iptables -A OUTPUT -o lo -j ACCEPT' - ); - - emit 'do_iptables -A OUTPUT -o lo -j ACCEPT' unless $config{ADMINISABSENTMINDED}; - - my $interfaces = find_interfaces_by_option 'dhcp'; - - if ( @$interfaces ) { - 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}; - # - # This might be a bridge - # - emit "do_iptables -A FORWARD -p udp -i $interface -o $interface --dport $ports -j ACCEPT"; - } - } - - emit ''; - - if ( $family == F_IPV4 ) { - if ( $config{IP_FORWARDING} eq 'on' ) { - emit( 'echo 1 > /proc/sys/net/ipv4/ip_forward', - 'progress_message2 IPv4 Forwarding Enabled' ); - } elsif ( $config{IP_FORWARDING} eq 'off' ) { - emit( 'echo 0 > /proc/sys/net/ipv4/ip_forward', - 'progress_message2 IPv4 Forwarding Disabled!' - ); - } - } else { - for my $interface ( all_bridges ) { - emit "do_iptables -A FORWARD -p 58 -i $interface -o $interface -j ACCEPT"; - } - - if ( $config{IP_FORWARDING} eq 'on' ) { - emit( 'echo 1 > /proc/sys/net/ipv6/conf/all/forwarding', - 'progress_message2 IPv6 Forwarding Enabled' ); - } elsif ( $config{IP_FORWARDING} eq 'off' ) { - emit( 'echo 0 > /proc/sys/net/ipv6/conf/all/forwarding', - 'progress_message2 IPv6 Forwarding Disabled!' - ); - } - } - - pop_indent; - - emit ' - run_stopped_exit'; - - my @ipsets = all_ipsets; - - if ( @ipsets ) { - emit <<'EOF' - - if [ -n "$(mywhich ipset)" ]; then - if ipset -S > ${VARDIR}/ipsets.tmp; then - # - # Don't save an 'empty' file - # - grep -q '^-N' ${VARDIR}/ipsets.tmp && mv -f ${VARDIR}/ipsets.tmp ${VARDIR}/ipsets.save - fi - fi -EOF - } - - emit ' - set_state "Stopped" - - logger -p kern.info "$PRODUCT Stopped" - - case $COMMAND in - stop|clear) - ;; - *) - # - # The firewall is being stopped when we were trying to do something - # else. Kill the shell in case we\'re running in a subshell - # - kill $$ - ;; - esac -} -'; - -} - # # Final stage of script generation. # # Copy prog.functions to the object file. -# Generate code for loading the various files in /var/lib/shorewall[-lite] +# Generate code for loading the various files in /var/lib/shorewall[6][-lite] # Generate code to add IP addresses under ADD_IP_ALIASES and ADD_SNAT_ALIASES # # Generate the 'setup_netfilter()' function that runs iptables-restore. @@ -697,17 +328,6 @@ sub generate_script_3($) { } if ( $family == F_IPV4 ) { - emit ( '#', - '# Recent kernels are difficult to configure -- we see state match omitted a lot so we check for it here', - '#', - 'qt1 $IPTABLES -N foox1234', - 'qt1 $IPTABLES -A foox1234 -m state --state ESTABLISHED,RELATED -j ACCEPT', - 'result=$?', - 'qt1 $IPTABLES -F foox1234', - 'qt1 $IPTABLES -X foox1234', - '[ $result = 0 ] || startup_error "Your kernel/iptables do not include state match support. No version of Shorewall will run on this system"', - '' ); - for my $interface ( @{find_interfaces_by_option 'norfc1918'} ) { emit ( "addr=\$(ip -f inet addr show $interface 2> /dev/null | grep 'inet\ ' | head -n1)", 'if [ -n "$addr" ]; then', @@ -759,9 +379,11 @@ sub generate_script_3($) { emit ( 'else' , ' run_init_exit', 'fi', - '', - 'qt1 $IPTABLES -L shorewall -n && qt1 $IPTABLES -F shorewall && qt1 $IPTABLES -X shorewall', - '', + '' ); + + mark_firewall_not_started; + + emit ('', 'delete_proxyarp', '' ); diff --git a/Shorewall/Perl/Shorewall/Config.pm b/Shorewall/Perl/Shorewall/Config.pm index 9b5b55e0c..d3a942511 100644 --- a/Shorewall/Perl/Shorewall/Config.pm +++ b/Shorewall/Perl/Shorewall/Config.pm @@ -1850,6 +1850,9 @@ sub determine_capabilities( $ ) { qt1( "$iptables -N $sillyname" ); qt1( "$iptables -N $sillyname1" ); + fatal_error 'Your kernel/iptables do not include state match support. No version of Shorewall will run on this system' + unless qt1( "$iptables -A $sillyname -m state --state ESTABLISHED,RELATED -j ACCEPT"); + if ( $family == F_IPV4 ) { $capabilities{CONNTRACK_MATCH} = qt1( "$iptables -A $sillyname -m conntrack --ctorigdst 192.168.1.1 -j ACCEPT" ); } else { diff --git a/Shorewall/releasenotes.txt b/Shorewall/releasenotes.txt index bcd77433e..7e910d4d6 100644 --- a/Shorewall/releasenotes.txt +++ b/Shorewall/releasenotes.txt @@ -188,8 +188,8 @@ None. /var/lib/shorewall[6]/firewall. 5) Dynamic zone support is once again available for IPv4. This support - is built on top of ipsets so you must have installed the - xtable-addons. + is built on top of ipsets so you must have the xtables-addons + installed on the firewall system. Dynamic zones are available when Shorewall-lite is used as well.