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,252 @@ 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 > ${STATEDIR}/zones_$$
startup_error "Unknown interface $interface"
fi
if ! chain_exists $(dynamic_in $interface) ; then while read z hosts; do
startup_error "At last Shorewall [re]start, DYNAMIC_ZONES=No in shorewall.conf" if [ "$z" = "$zone" ]; then
fi for h in $hosts; do
# for host in $hostlist; do
# Normalize the first argument to this function if [ "$h" = "$host" ]; then
# rm -f ${STATEDIR}/zones_$$
newhost="$interface:$host" startup_error "$host already in zone $zone"
fi
done
done
[ -z "$hosts" ] && hosts=$hostlist || hosts="$hosts $hostlist"
fi
eval ${z}_hosts=\"$hosts\"
echo "$z $hosts" >> ${STATEDIR}/zones_$$
done < ${STATEDIR}/zones
mv -f ${STATEDIR}/zones_$$ ${STATEDIR}/zones
terminator=fatal_error terminator=fatal_error
# #
# Create a new Zone state file # Create a new Zone state file
# #
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
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) $(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
}
#
# Delete a host or networks from a zone
#
delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone
{
local interface host zone z h z1 z2 chain delhost
local dhcp_interfaces blacklist_interfaces maclist_interfaces tcpflags_interfaces
local rulenum source_chain dest_hosts iface hosts hostlist=
#
# Load $zones
#
determine_zones
#
# Validate Interfaces File
#
validate_interfaces_file
#
# Validate Hosts File
#
validate_hosts_file
#
# Validate IPSec File
#
f=$(find_file ipsec)
[ -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"
[ "$zone" = $FW ] && startup_error "Can't delete from the firewall zone"
#
# 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}/zones ] || startup_error "${STATEDIR}/zones -- file not found"
#
# Delete the passed hosts from the 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 temp=$hosts
if [ "$h" = "$newhost" ]; then hosts=
rm -f ${STATEDIR}/zones_$$
startup_error "$1 already in zone $zone" for host in $hostlist; do
fi 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 done
[ -z "$hosts" ] && hosts=$newhost || hosts="$hosts $newhost" 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 fi
eval ${z}_hosts=\"$hosts\" eval ${z}_hosts=\"$hosts\"
@ -6750,207 +6921,61 @@ 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
#
# 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
do_iptables -t nat -A $(dynamic_in $interface) $(source_ip_range $host) $policyin -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
done < ${STATEDIR}/chains
rm -rf $TMP_DIR
progress_message "$1 added to zone $2"
}
#
# Delete a host or networks from a zone
#
delete_from_zone() # $1 = <interface>[:<hosts>] $2 = zone
{
#
# Delete the subject host(s) from the zone state file
#
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
#
determine_zones
f=$(find_file ipsec)
if [ -f $f ]; then
progress_message "Processing $f..."
setup_ipsec $f
fi
zone=$2
validate_zone $zone || startup_error "Unknown zone: $zone"
[ "$zone" = $FW ] && startup_error "Can't remove $1 from 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
#
[ -f ${STATEDIR}/chains ] || startup_error "${STATEDIR}/chains -- 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
#
[ -z "$(delete_from_zones_file)" ] && \
error_message "Warning: $1 does not appear to be in zone $2"
#
# Construct the zone host maps
#
while read z hosts; do
eval ${z}_hosts=\"$hosts\"
done < ${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
iface=${h%%:*}
hosts=${h#*:}
if [ "$iface" != "$interface" -o "$hosts" != "$host" ]; then progress_message "$delhost removed from zone $zone"
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
done
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