Add/Delete multiple hosts in one command; fix Add/Delete IPSEC problems

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@1811 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2004-12-08 20:00:03 +00:00
parent bb4652cdf7
commit ed809afe96
5 changed files with 298 additions and 256 deletions

View File

@ -175,4 +175,7 @@ Changes since 2.0.3
86) Corrected typo in interfaces file. 86) Corrected typo in interfaces file.
97) Add DROPINVALID option. 87) Add DROPINVALID option.
88) Allow list of hosts in add and delete commands. Fix ipsec problem
with "add" and "delete"

View File

@ -6637,11 +6637,11 @@ refresh_firewall()
# #
# Add a host or networks to a zone # Add a host or networks to a zone
# #
add_to_zone() # $1 = <interface>[:<hosts>] $2 = zone add_to_zone() # $1...${n-1} = <interface>[:<hosts>] $n = zone
{ {
local base interface host newhost zone z h z1 z2 chain terminator local interface host zone z h z1 z2 chain
local dhcp_interfaces blacklist_interfaces maclist_interfaces tcpflags_interfaces local dhcp_interfaces blacklist_interfaces maclist_interfaces tcpflags_interfaces
local rulenum source_chain dest_hosts iface hosts is_ipsec policyin= policyout= local rulenum source_chain dest_hosts iface hosts hostlist=
nat_chain_exists() # $1 = chain name nat_chain_exists() # $1 = chain name
{ {
@ -6654,17 +6654,10 @@ add_to_zone() # $1 = <interface>[:<hosts>] $2 = zone
[ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange [ -n "$IPRANGE_MATCH" ] && [ -f $TMP_DIR/iprange ] && rm -f $TMP_DIR/iprange
if ! $IPTABLES $@ ; then if ! $IPTABLES $@ ; then
startup_error "Can't add $1 to zone $2" error_message "Can't add $newhost to zone $zone"
fi fi
} }
#
# Isolate interface and host parts
#
interface=${1%%:*}
host=${1#*:}
[ -z "$host" ] && host="0.0.0.0/0"
# #
# Load $zones # Load $zones
# #
@ -6674,74 +6667,73 @@ add_to_zone() # $1 = <interface>[:<hosts>] $2 = zone
# #
validate_interfaces_file validate_interfaces_file
# #
# Validate Hosts File
#
validate_hosts_file
#
# Validate IPSec File # Validate IPSec File
# #
f=$(find_file ipsec) f=$(find_file ipsec)
if [ -f $f ]; then [ -f $f ] && setup_ipsec $f
progress_message "Processing $f..." #
setup_ipsec $f # Normalize host list
fi #
while [ $# -gt 1 ]; do
interface=${1%%:*}
host=${1#*:}
#
# Be sure that the interface was dynamic at last [re]start
#
if ! chain_exists $(input_chain $interface) ; then
startup_error "Unknown interface $interface"
fi
if ! chain_exists $(dynamic_in $interface) ; then
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
fi
if [ -z "$host" ]; then
hostlist="$hostlist $interface:0.0.0.0/0"
else
for h in $(separate_list $host); do
hostlist="$hostlist $interface:$h"
done
fi
shift
done
# #
# Validate Zone # Validate Zone
# #
zone=$2 zone=$1
validate_zone $zone || startup_error "Unknown zone: $zone" validate_zone $zone || startup_error "Unknown zone: $zone"
[ "$zone" = $FW ] && startup_error "Can't add $1 to firewall zone" [ "$zone" = $FW ] && startup_error "Can't add $1 to firewall zone"
eval is_ipsec=\$${zone}_is_ipsec
eval options=\"\$${zone}_ipsec_options\"
eval in_options=\"\$${zone}_ipsec_in_options\"
eval out_options=\"\$${zone}_ipsec_out_options\"
if [ -n "$is_ipsec" ]; then
[ -n "$POLICY_MATCH" ] || startup_error "Your kernel and/or iptables lacks policy match support"
policyin="-m policy --pol ipsec --dir in $options $in_options"
policyout="-m policy --pol ipsec --dir out $options $out_options"
elif [ -n "$POLICY_MATCH" ]; then
policyin="-m policy --pol none --dir in"
policyout="-m policy --pol none --dir out"
fi
# #
# Be sure that Shorewall has been restarted using a DZ-aware version of the code # Be sure that Shorewall has been restarted using a DZ-aware version of the code
# #
[ -f ${STATEDIR}/chains ] || startup_error "${STATEDIR}/chains -- file not found" [ -f ${STATEDIR}/chains ] || startup_error "${STATEDIR}/chains -- file not found"
[ -f ${STATEDIR}/zones ] || startup_error "${STATEDIR}/zones -- file not found" [ -f ${STATEDIR}/zones ] || startup_error "${STATEDIR}/zones -- file not found"
# #
# Be sure that the interface was dynamic at last [re]start # Check for duplicates and create a new zone state file
#
if ! chain_exists $(input_chain $interface) ; then
startup_error "Unknown interface $interface"
fi
if ! chain_exists $(dynamic_in $interface) ; then
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
fi
#
# Normalize the first argument to this function
#
newhost="$interface:$host"
terminator=fatal_error
#
# Create a new Zone state file
# #
> ${STATEDIR}/zones_$$ > ${STATEDIR}/zones_$$
#
# Add $1 to the Zone state file
#
while read z hosts; do while read z hosts; do
if [ "$z" = "$zone" ]; then if [ "$z" = "$zone" ]; then
for h in $hosts; do for h in $hosts; do
if [ "$h" = "$newhost" ]; then for host in $hostlist; do
rm -f ${STATEDIR}/zones_$$ if [ "$h" = "$host" ]; then
startup_error "$1 already in zone $zone" rm -f ${STATEDIR}/zones_$$
fi startup_error "$host already in zone $zone"
fi
done
done done
[ -z "$hosts" ] && hosts=$newhost || hosts="$hosts $newhost" [ -z "$hosts" ] && hosts=$hostlist || hosts="$hosts $hostlist"
fi fi
eval ${z}_hosts=\"$hosts\" eval ${z}_hosts=\"$hosts\"
@ -6750,60 +6742,73 @@ add_to_zone() # $1 = <interface>[:<hosts>] $2 = zone
done < ${STATEDIR}/zones done < ${STATEDIR}/zones
mv -f ${STATEDIR}/zones_$$ ${STATEDIR}/zones mv -f ${STATEDIR}/zones_$$ ${STATEDIR}/zones
terminator=fatal_error
# #
# If the zone passed in the command has a dnat chain then insert a rule in # Create a new Zone state file
# the nat table PREROUTING chain to jump to that chain when the source
# matches the new host(s)#
# #
chain=${zone}_dnat for newhost in $hostlist; do
#
# Isolate interface and host parts
#
interface=${newhost%%:*}
host=${newhost#*:}
#
# If the zone passed in the command has a dnat chain then insert a rule in
# the nat table PREROUTING chain to jump to that chain when the source
# matches the new host(s)#
#
chain=${zone}_dnat
if nat_chain_exists $chain; then if nat_chain_exists $chain; then
do_iptables -t nat -A $(dynamic_in $interface) $(source_ip_range $host) $policyin -j $chain do_iptables -t nat -A $(dynamic_in $interface) $(source_ip_range $host) $(match_ipsec_in $zone $newhost) -j $chain
fi
#
# Insert new rules into the filter table for the passed interface
#
while read z1 z2 chain; do
if [ "$z1" = "$zone" ]; then
if [ "$z2" = "$FW" ]; then
do_iptables -A $(dynamic_in $interface) $(match_source_hosts $host) $policyin -j $chain
else
source_chain=$(dynamic_fwd $interface)
eval dest_hosts=\"\$${z2}_hosts\"
for h in $dest_hosts; do
iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
do_iptables -A $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $policyout -j $chain
fi
done
fi
elif [ "$z2" = "$zone" ]; then
if [ "$z1" = "$FW" ]; then
#
# Add a rule to the dynamic out chain for the interface
#
do_iptables -A $(dynamic_out $interface) $(match_dest_hosts $host) $policyout -j $chain
else
eval source_hosts=\"\$${z1}_hosts\"
for h in $source_hosts; do
iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
do_iptables -A $(dynamic_fwd $iface) $rulenum $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $policyout -j $chain
fi
done
fi
fi fi
done < ${STATEDIR}/chains #
# Insert new rules into the filter table for the passed interface
#
while read z1 z2 chain; do
if [ "$z1" = "$zone" ]; then
if [ "$z2" = "$FW" ]; then
do_iptables -A $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j $chain
else
source_chain=$(dynamic_fwd $interface)
eval dest_hosts=\"\$${z2}_hosts\"
for h in $dest_hosts; do
iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
do_iptables -A $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
fi
done
fi
elif [ "$z2" = "$zone" ]; then
if [ "$z1" = "$FW" ]; then
#
# Add a rule to the dynamic out chain for the interface
#
do_iptables -A $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
else
eval source_hosts=\"\$${z1}_hosts\"
for h in $source_hosts; do
iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
do_iptables -A $(dynamic_fwd $iface) $rulenum $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $newhost) -j $chain
fi
done
fi
fi
done < ${STATEDIR}/chains
progress_message "$newhost added to zone $zone"
done
rm -rf $TMP_DIR rm -rf $TMP_DIR
progress_message "$1 added to zone $2"
} }
# #
@ -6811,146 +6816,166 @@ add_to_zone() # $1 = <interface>[:<hosts>] $2 = zone
# #
delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone
{ {
# local interface host zone z h z1 z2 chain delhost
# Delete the subject host(s) from the zone state file local dhcp_interfaces blacklist_interfaces maclist_interfaces tcpflags_interfaces
# local rulenum source_chain dest_hosts iface hosts hostlist=
delete_from_zones_file()
{
> ${STATEDIR}/zones_$$
while read z hosts; do
if [ "$z" = "$zone" ]; then
temp=$hosts
hosts=
for h in $temp; do
if [ "$h" = "$delhost" ]; then
echo Yes
else
hosts="$hosts $h"
fi
done
fi
echo "$z $hosts" >> ${STATEDIR}/zones_$$
done < ${STATEDIR}/zones
mv -f ${STATEDIR}/zones_$$ ${STATEDIR}/zones
}
#
# Isolate interface and host parts
#
interface=${1%%:*}
host=${1#*:}
[ -z "$host" ] && host="0.0.0.0/0"
# #
# Load $zones # Load $zones
# #
determine_zones determine_zones
#
# Validate Interfaces File
#
validate_interfaces_file
#
# Validate Hosts File
#
validate_hosts_file
#
# Validate IPSec File
#
f=$(find_file ipsec) f=$(find_file ipsec)
if [ -f $f ]; then
progress_message "Processing $f..."
setup_ipsec $f
fi
zone=$2 [ -f $f ] && setup_ipsec $f
#
# Normalize host list
#
while [ $# -gt 1 ]; do
interface=${1%%:*}
host=${1#*:}
#
# Be sure that the interface was dynamic at last [re]start
#
if ! chain_exists $(input_chain $interface) ; then
startup_error "Unknown interface $interface"
fi
if ! chain_exists $(dynamic_in $interface) ; then
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf"
fi
if [ -z "$host" ]; then
hostlist="$hostlist $interface:0.0.0.0/0"
else
for h in $(separate_list $host); do
hostlist="$hostlist $interface:$h"
done
fi
shift
done
#
# Validate Zone
#
zone=$1
validate_zone $zone || startup_error "Unknown zone: $zone" validate_zone $zone || startup_error "Unknown zone: $zone"
[ "$zone" = $FW ] && startup_error "Can't remove $1 from firewall zone" [ "$zone" = $FW ] && startup_error "Can't delete from the firewall zone"
eval is_ipsec=\$${zone}_is_ipsec
eval options=\"\$${zone}_ipsec_options\"
eval in_options=\"\$${zone}_ipsec_in_options\"
eval out_options=\"\$${zone}_ipsec_out_options\"
if [ -n "$is_ipsec" ]; then
[ -n "$POLICY_MATCH" ] || startup_error "Your kernel and/or iptables lacks policy match support"
policyin="-m policy --pol ipsec --dir in $options $in_options"
policyout="-m policy --pol ipsec --dir out $options $out_options"
elif [ -n "$POLICY_MATCH" ]; then
policyin="-m policy --pol none --dir in"
policyout="-m policy --pol none --dir out"
fi
# #
# Be sure that Shorewall has been restarted using a DZ-aware version of the code # Be sure that Shorewall has been restarted using a DZ-aware version of the code
# #
[ -f ${STATEDIR}/chains ] || startup_error "${STATEDIR}/chains -- file not found" [ -f ${STATEDIR}/chains ] || startup_error "${STATEDIR}/chains -- file not found"
[ -f ${STATEDIR}/zones ] || startup_error "${STATEDIR}/zones -- file not found" [ -f ${STATEDIR}/zones ] || startup_error "${STATEDIR}/zones -- file not found"
# #
# Be sure that the interface was present at last [re]start
#
if ! chain_exists $(input_chain $interface) ; then
startup_error "Unknown interface $interface"
fi
if ! chain_exists $(dynamic_in $interface) ; then
startup_error "Interface $interface is not dynamic"
fi
#
# Normalize the first argument to this function
#
delhost="$interface:$host"
#
# Delete the passed hosts from the zone state file # Delete the passed hosts from the zone state file
# #
[ -z "$(delete_from_zones_file)" ] && \ > ${STATEDIR}/zones_$$
error_message "Warning: $1 does not appear to be in zone $2"
#
# Construct the zone host maps
#
while read z hosts; do while read z hosts; do
if [ "$z" = "$zone" ]; then
temp=$hosts
hosts=
for host in $hostlist; do
found=
for h in $temp; do
if [ "$h" = "$host" ]; then
found=Yes
break
fi
done
[ -n "$found" ] || error_message "Warning: $1 does not appear to be in zone $2"
done
for h in $temp; do
found=
for host in $hostlist; do
if [ "$h" = "$host" ]; then
found=Yes
break
fi
done
[ -n "$found" ] || hosts="$hosts $h"
done
fi
eval ${z}_hosts=\"$hosts\" eval ${z}_hosts=\"$hosts\"
echo "$z $hosts" >> ${STATEDIR}/zones_$$
done < ${STATEDIR}/zones done < ${STATEDIR}/zones
mv -f ${STATEDIR}/zones_$$ ${STATEDIR}/zones
terminator=fatal_error terminator=fatal_error
#
# Delete any nat table entries for the host(s)
#
qt_iptables -t nat -D $(dynamic_in $interface) $(match_source_hosts $host) $policyin -j ${zone}_dnat
#
# Delete rules rules the input chains for the passed interface
#
while read z1 z2 chain; do
if [ "$z1" = "$zone" ]; then
if [ "$z2" = "$FW" ]; then
qt_iptables -D $(dynamic_in $interface) $(match_source_hosts $host) $policyin -j $chain
else
source_chain=$(dynamic_fwd $interface)
eval dest_hosts=\"\$${z2}_hosts\"
for h in $dest_hosts $delhost; do for delhost in $hostlist; do
iface=${h%%:*} interface=${delhost%%:*}
hosts=${h#*:} host=${delhost#*:}
#
# Delete any nat table entries for the host(s)
#
qt_iptables -t nat -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $zone $newhost) -j ${zone}_dnat
#
# Delete rules rules the input chains for the passed interface
#
while read z1 z2 chain; do
if [ "$z1" = "$zone" ]; then
if [ "$z2" = "$FW" ]; then
qt_iptables -D $(dynamic_in $interface) $(match_source_hosts $host) $(match_ipsec_in $z1 $newhost) -j $chain
else
source_chain=$(dynamic_fwd $interface)
eval dest_hosts=\"\$${z2}_hosts\"
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then [ "$z2" = "$zone" ] && dest_hosts="$dest_hosts $hostlist"
qt_iptables -D $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $policyout -j $chain
fi for h in $dest_hosts; do
done iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
qt_iptables -D $source_chain $(match_source_hosts $host) -o $iface $(match_dest_hosts $hosts) $(match_ipsec_out $z2 $h) -j $chain
fi
done
fi
elif [ "$z2" = "$zone" ]; then
if [ "$z1" = "$FW" ]; then
qt_iptables -D $(dynamic_out $interface) $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
else
eval source_hosts=\"\$${z1}_hosts\"
for h in $source_hosts; do
iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then
qt_iptables -D $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $(match_ipsec_out $z2 $delhost) -j $chain
fi
done
fi
fi fi
elif [ "$z2" = "$zone" ]; then done < ${STATEDIR}/chains
if [ "$z1" = "$FW" ]; then
qt_iptables -D $(dynamic_out $interface) $(match_dest_hosts $host) $policyout -j $chain
else
eval source_hosts=\"\$${z1}_hosts\"
for h in $source_hosts; do progress_message "$delhost removed from zone $zone"
iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then done
qt_iptables -D $(dynamic_fwd $iface) $(match_source_hosts $hosts) -o $interface $(match_dest_hosts $host) $policyout -j $chain
fi
done
fi
fi
done < ${STATEDIR}/chains
rm -rf $TMP_DIR rm -rf $TMP_DIR
progress_message "$1 removed from zone $2"
} }
# #
@ -7123,7 +7148,7 @@ do_initialize() {
ensure_config_path ensure_config_path
# #
# Determine the capabilities of the installed iptables/netfilter # Determine the capabilities of the installed iptables/netfilter
# We load the kernel modules here to acurately determine # We load the kernel modules here to acuray determine
# capabilities when module autoloading isn't enabled. # capabilities when module autoloading isn't enabled.
# #
@ -7409,7 +7434,7 @@ case "$COMMAND" in
;; ;;
add) add)
[ $# -ne 3 ] && usage [ $# -lt 3 ] && usage
do_initialize do_initialize
my_mutex_on my_mutex_on
if ! qt $IPTABLES -L shorewall -n ; then if ! qt $IPTABLES -L shorewall -n ; then
@ -7418,12 +7443,13 @@ case "$COMMAND" in
my_mutex_off my_mutex_off
exit 2; exit 2;
fi fi
add_to_zone $2 $3 shift
add_to_zone $@
my_mutex_off my_mutex_off
;; ;;
delete) delete)
[ $# -ne 3 ] && usage [ $# -lt 3 ] && usage
do_initialize do_initialize
my_mutex_on my_mutex_on
if ! qt $IPTABLES -L shorewall -n ; then if ! qt $IPTABLES -L shorewall -n ; then
@ -7432,7 +7458,8 @@ case "$COMMAND" in
my_mutex_off my_mutex_off
exit 2; exit 2;
fi fi
delete_from_zone $2 $3 shift
delete_from_zone $@
my_mutex_off my_mutex_off
;; ;;

View File

@ -29,10 +29,10 @@
case $1 in case $1 in
add) add)
echo "add: add <interface>[:<bridge-port>][:<host>] <zone> echo "add: add <interface>[:<bridge-port>][:<host-list>] ... <zone>
Adds a host or subnet to a dynamic zone usually used with VPN's. Adds a list of hosts or subnets to a dynamic zone usually used with VPN's.
shorewall add interface[:host] zone - Adds the specified interface shorewall add interface[:<port>][:host-list] ... zone - Adds the specified interface
(and bridge port/host if included) to the specified zone. (and bridge port/host if included) to the specified zone.
Example: Example:
@ -95,11 +95,11 @@ debug)
;; ;;
delete) delete)
echo "delete: delete <interface>[:<bridge-port>][:<host>] <zone> echo "delete: delete <interface>[:<bridge-port>][:<host-list>] ... <zone>
Deletes a host or subnet from a dynamic zone usually used with VPN's. Deletes a host or subnet from a dynamic zone usually used with VPN's.
shorewall delete interface[:port][:host] zone - Deletes the specified shorewall delete interface[:port][:host-list] ... zone - Deletes the specified
interface (and bridge port/host if included) from the specified zone. interfaces (and bridge ports/hosts if included) from the specified zone.
Example: Example:

View File

@ -184,6 +184,9 @@ Problems corrected since 2.2.0 Beta 7:
1) A typo in the /etc/shorewall/interfaces file has been corrected. 1) A typo in the /etc/shorewall/interfaces file has been corrected.
2) The "add" and "delete" commands were generating incorrect policy
matches when policy match support was available.
----------------------------------------------------------------------- -----------------------------------------------------------------------
Issues when migrating from Shorewall 2.0 to Shorewall 2.1: Issues when migrating from Shorewall 2.0 to Shorewall 2.1:
@ -806,3 +809,12 @@ New Features:
If not specified or if specified as empty (e.g., DROPINVALID="") If not specified or if specified as empty (e.g., DROPINVALID="")
then DROPINVALID=Yes is assumed. then DROPINVALID=Yes is assumed.
36) The "shorewall add" and "shorewall delete" commands now accept a
list of hosts to add or delete.
Examples:
shorewall add eth1:1.2.3.4 eth1:2.3.4.5 z12
shorewall delete eth1:1.2.3.4 eth1:2.3.4.5 z12

View File

@ -867,8 +867,8 @@ case "$1" in
exec $SHOREWALL_SHELL $FIREWALL $debugging $nolock $1 exec $SHOREWALL_SHELL $FIREWALL $debugging $nolock $1
;; ;;
add|delete) add|delete)
[ $# -ne 3 ] && usage 1 [ $# -lt 3 ] && usage 1
exec $SHOREWALL_SHELL $FIREWALL $debugging $nolock $1 $2 $3 exec $SHOREWALL_SHELL $FIREWALL $debugging $nolock $@
;; ;;
show|list) show|list)
[ -n "$debugging" ] && set -x [ -n "$debugging" ] && set -x