From 8d5ffcf048fc6350a792605f2f3ef243d5e79ae8 Mon Sep 17 00:00:00 2001 From: teastep Date: Wed, 18 Oct 2006 19:56:22 +0000 Subject: [PATCH] Allow exclusion in /etc/shorewall/hosts git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@4698 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- Shorewall/changelog.txt | 2 + Shorewall/compiler | 75 ++++++++++++++++++++++++++--- Shorewall/lib.config | 99 +++++++++++++++++++++++++++++--------- Shorewall/releasenotes.txt | 15 ++++++ 4 files changed, 162 insertions(+), 29 deletions(-) diff --git a/Shorewall/changelog.txt b/Shorewall/changelog.txt index beed75a9f..23427e641 100644 --- a/Shorewall/changelog.txt +++ b/Shorewall/changelog.txt @@ -16,6 +16,8 @@ Changes in 3.3.3 8) Rename SUBNET column in the masq file. +9) Allow exclusion in /etc/shorewall/hosts. + Changes in 3.3.1 1) Load the proxyarp lib when 'proxyarp' option is specified. diff --git a/Shorewall/compiler b/Shorewall/compiler index 85be208e4..0b3d5dd49 100755 --- a/Shorewall/compiler +++ b/Shorewall/compiler @@ -4109,6 +4109,29 @@ activate_rules() frwd_chain=${zone}_frwd createchain $frwd_chain No + eval exclusions=\"\$${zone}_exclusions\" + + if [ -n "$exclusions" ]; then + local num=1 + in_chain=${zone}_in + out_chain=${zone}_out + createchain $in_chain No + createchain $out_chain No + + if [ "$(rules_chain $zone $zone)" = ACCEPT ]; then + createchain ${zone}2${zone} yes + run_iptables -A ${zone}2${zone} -j ACCEPT + fi + + for host in $exclusions; do + interface=${host%%:*} + address=${host#*:} + run_iptables -A $frwd_chain -i $interface -s $address -j RETURN + run_iptables -A $in_chain -i $interface -s $address -j RETURN + run_iptables -A $out_chain -i $interface -s $address -j RETURN + done + fi + if [ -n "$POLICY_MATCH" ]; then # # Because policy match only matches an 'in' or an 'out' policy (but not both), we have to place the @@ -4143,8 +4166,7 @@ activate_rules() eval complex=\$${zone}_is_complex eval type=\$${zone}_type - - [ -n "$complex" ] && frwd_chain=${zone}_frwd + eval exclusions=\"\$${zone}_exclusions\" echo $zone $type $source_hosts >> $STATEDIR/zones @@ -4155,18 +4177,46 @@ activate_rules() need_broadcast= + + if [ -n "$complex" ]; then + frwd_chain=${zone}_frwd + chain=$(dnat_chain $zone) + if havenatchain $chain; then + local num=0 + for host in $exclusions; do + interface=${host%%:*} + networks=${host#*:} + num=$(($num + 1)) + run_iptables -t nat -I $chain $num -i $interface -s $networks -j RETURN + done + fi + fi + for host in $source_hosts; do interface=${host%%:*} networks=${host#*:} - [ -n "$chain1" ] && run_iptables2 -A OUTPUT -o $interface $(match_dest_hosts $networks) $(match_ipsec_out $zone $host) -j $chain1 - + if [ -n "$chain1" ]; then + if [ -n "$exclusions" ]; then + run_iptables2 -A OUTPUT -o $interface $(match_dest_hosts $networks) $(match_ipsec_out $zone $host) -j ${zone}_out + run_iptables -A ${zone}_out -j $chain1 + else + run_iptables2 -A OUTPUT -o $interface $(match_dest_hosts $networks) $(match_ipsec_out $zone $host) -j $chain1 + fi + fi # # Add jumps from the builtin chain for DNAT rules # addrulejump PREROUTING $(dnat_chain $zone) -i $interface $(match_source_hosts $networks) $(match_ipsec_in $zone $host) - [ -n "$chain2" ] && run_iptables2 -A $(input_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $chain2 + if [ -n "$chain2" ]; then + if [ -n "$exclusions" ]; then + run_iptables2 -A $(input_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j ${zone}_in + run_iptables -A ${zone}_in -j $chain2 + else + run_iptables2 -A $(input_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $chain2 + fi + fi if [ -n "$complex" ] && ! is_ipsec_host $zone $host ; then run_iptables2 -A $(forward_chain $interface) $(match_source_hosts $networks) $(match_ipsec_in $zone $host) -j $frwd_chain @@ -4197,6 +4247,7 @@ activate_rules() [ "$policy" = NONE ] && continue eval dest_hosts=\$${zone1}_hosts + eval exclusions1=\"\$${zone1}_exclusions\" chain="$(rules_chain $zone $zone1)" @@ -4221,7 +4272,7 @@ activate_rules() # If we don't need to route back and if we have only one interface or one port to # the zone then assume that hosts in the zone can communicate directly. # - if [ $num_ifaces -lt 2 -a -z "$routeback" ] ; then + if [ $num_ifaces -lt 2 -a -z "$routeback" -a -z "$exclusions" ] ; then continue fi else @@ -4258,6 +4309,16 @@ activate_rules() done done fi + + if [ -n "$exclusions1" ]; then + local num=0 + for host1 in $exclusions1; do + interface1=${host1%%:*} + networks1=${host1#*:} + num=$(($num + 1)) + run_iptables -I $chain $num -o $interface1 -d $networks1 -j RETURN + done + fi done done @@ -4779,7 +4840,7 @@ run_iptables() \$IPTABLES \$@ fi - if [ $? -ne 0 ]; then + if [ \$? -ne 0 ]; then error_message "ERROR: Command \"\$IPTABLES \$@\" Failed" stop_firewall exit 2 diff --git a/Shorewall/lib.config b/Shorewall/lib.config index 8ff4faf2f..c3c6cd558 100644 --- a/Shorewall/lib.config +++ b/Shorewall/lib.config @@ -581,6 +581,22 @@ validate_hosts_file() { eval zports=\$${z}_ports + if [ -z "$BRIDGING" ]; then + case $hosts in + *!*!*) + startup_error "Invalid hosts file entry: \"$r\"" + ;; + !*) + hosts=0.0.0.0/0 + eval ${z}_is_complex=Yes + ;; + *!*) + hosts=${hosts%%!*} + eval ${z}_is_complex=Yes + ;; + esac + fi + for host in $(separate_list $hosts); do if [ -n "$BRIDGING" ]; then case $host in @@ -601,26 +617,26 @@ validate_hosts_file() { ;; esac else - case $host in - *.*.*) - ;; - *+|*!*) - eval ${z}_is_complex=Yes - ;; - *) - startup_error "BRIDGING=Yes is needed for this zone definition: $r" - ;; - esac - fi - - for option in $(separate_list $options) ; do - case $option in - norfc1918|blacklist|tcpflags|nosmurfs|-) - ;; - maclist) + case $host in + *.*.*) + ;; + *+) + eval ${z}_is_complex=Yes + ;; + *) + startup_error "BRIDGING=Yes is needed for this zone definition: $r" + ;; + esac + fi + + for option in $(separate_list $options) ; do + case $option in + norfc1918|blacklist|tcpflags|nosmurfs|-) + ;; + maclist) lib_load maclist "The 'maclist' option" ;; - ipsec) + ipsec) [ -n "$POLICY_MATCH" ] || \ startup_error "Your kernel and/or iptables does not support policy match: ipsec" eval ${z}_ipsec_hosts=\"\$${z}_ipsec_hosts $interface:$host\" @@ -1121,9 +1137,43 @@ find_hosts() # $1 = host zone expandv hosts interface=${hosts%%:*} addresses=${hosts#*:} - for address in $(separate_list $addresses); do - echo $interface:$address - done + case $addresses in + !*) + echo $interface:0.0.0.0/0 + ;; + *) + for address in $(separate_list ${addresses%%!*}); do + echo $interface:$address + done + ;; + esac + fi + done < $TMP_DIR/hosts +} + +# +# +# Find exclusions in a given zone +# +# Read hosts file and for each record matching the passed ZONE, +# echo any exclusions +# +find_exclusions() # $1 = host zone +{ + local hosts interface address addresses + + while read z hosts options; do + if [ "x$(expand $z)" = "x$1" ]; then + expandv hosts + interface=${hosts%%:*} + addresses=${hosts#*:} + case $addresses in + *!*) + for address in $(separate_list ${addresses#*!}); do + echo $interface:$address + done + ;; + esac fi done < $TMP_DIR/hosts } @@ -1161,6 +1211,8 @@ determine_hosts() { for zone in $ZONES; do hosts=$(find_hosts $zone) hosts=$(echo $hosts) # Remove extra trash + exclusions=$(find_exclusions $zone) + exclusions=$(echo $exclusions) # Remove extra trash eval interfaces=\$${zone}_interfaces @@ -1203,11 +1255,14 @@ determine_hosts() { fi done + eval ${zone}_exclusions="\$exclusions" eval ${zone}_interfaces="\$interfaces" eval ${zone}_hosts="\$hosts" if [ -n "$hosts" ]; then - [ $VERBOSE -ge 1 ] && display_list "$zone Zone:" $hosts + if [ $VERBOSE -ge 1 ]; then + [ -n "$exclusions" ] && display_list "$zone Zone:" $hosts minus "($exclusions)" || display_list "$zone Zone:" $hosts + fi else error_message "WARNING: Zone $zone is empty" fi diff --git a/Shorewall/releasenotes.txt b/Shorewall/releasenotes.txt index 50d0a98e6..9d2ca49bb 100644 --- a/Shorewall/releasenotes.txt +++ b/Shorewall/releasenotes.txt @@ -127,6 +127,21 @@ Other changes in 3.3.3 6) The SUBNET column in /etc/shorewall/masq has been renamed SOURCE to more accurately describe the contents of the column. +7) Previously, it was not possible to use exclusion in + /etc/shorewall/hosts. Beginning with this release, you may now use + exclusion lists in entries in this file. Exclusion lists are + discussed at: + + http://www.shorewall.net/configuration_file_basics.htm#Exclusion. + + Example: + + loc eth0:192.168.1.0/24!192.168.1.4,192.168.1.16/28 + + In that example, the 'loc' zone is defined to be the subnet + 192.168.1.0/24 interfacing via eth0 *except* for host 192.168.1.4 + and hosts in the sub-network 192.168.1.16/28. + Migration Considerations: 1) Shorewall supports the notion of "default actions". A default