Finally implement exclude lists in rules

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@2493 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2005-08-15 17:35:45 +00:00
parent 5df7bc0538
commit 42ee8d0c19
3 changed files with 330 additions and 288 deletions

View File

@ -17,6 +17,8 @@ Changes in 2.5.1
8) Generate error for 'norfc1918' on an interface with an RFC 1918 IP 8) Generate error for 'norfc1918' on an interface with an RFC 1918 IP
address. address.
9) Finally implement exclude lists in rules.
Changes in 2.5.1ex/2.5.0 Changes in 2.5.1ex/2.5.0
1) Clean up handling of zones 1) Clean up handling of zones

View File

@ -4645,6 +4645,7 @@ process_actions3() {
# ratelimit = Optional rate limiting clause # ratelimit = Optional rate limiting clause
# userandgroup = -m owner match to limit the rule to a particular user and/or group # userandgroup = -m owner match to limit the rule to a particular user and/or group
# logtag = Log tag # logtag = Log tag
# excludesource = Source Exclusion List
# #
add_nat_rule() { add_nat_rule() {
local chain local chain
@ -4711,8 +4712,8 @@ add_nat_rule() {
if [ $COMMAND != check ]; then if [ $COMMAND != check ]; then
if [ "$source" = "$FW" ]; then if [ "$source" = "$FW" ]; then
if [ -n "$excludedests" ]; then if [ -n "${excludesource}${excludedests}" ]; then
build_exclusion_chain chain nat "" $excludedests build_exclusion_chain chain nat "$excludesource" $excludedests
for adr in $(separate_list $addr); do for adr in $(separate_list $addr); do
run_iptables2 -t nat -A OUTPUT $cli $proto $userandgroup $multiport $sports $dports $(dest_ip_range $adr) -j $chain run_iptables2 -t nat -A OUTPUT $cli $proto $userandgroup $multiport $sports $dports $(dest_ip_range $adr) -j $chain
@ -4734,8 +4735,8 @@ add_nat_rule() {
done done
fi fi
else else
if [ -n "${excludedests}" ]; then if [ -n "${excludesource}${excludedests}" ]; then
build_exclusion_chain chain nat "" $excludedests build_exclusion_chain chain nat "$excludesource" $excludedests
for adr in $(separate_list $addr); do for adr in $(separate_list $addr); do
addnatrule $(dnat_chain $source) $cli $proto $multiport $sports $dports $(dest_ip_range $adr) -j $chain addnatrule $(dnat_chain $source) $cli $proto $multiport $sports $dports $(dest_ip_range $adr) -j $chain
@ -4776,278 +4777,6 @@ add_nat_rule() {
ratelimit= ratelimit=
} }
#
# Add one Filter Rule -- Helper function for the rules file processor
#
# The caller has established the following variables:
# COMMAND = current command. If 'check', we're executing a 'check'
# which only goes through the motions.
# client = SOURCE IP or MAC
# server = DESTINATION IP or interface
# protocol = Protocol
# address = Original Destination Address
# port = Destination Port
# cport = Source Port
# multioption = String to invoke multiport match if appropriate
# servport = Port the server listens on
# chain = The canonical chain for this rule
# logchain = The chain that should be mentioned in log messages
# ratelimit = Optional rate limiting clause
# userandgroup= -m owner clause
# userspec = User name
# logtag = Log tag
# policy = Applicable Policy
#
add_a_rule()
{
local natrule=
do_ports() {
if [ -n "$port" ]; then
dports="--dport"
if [ -n "$multioption" -a "$port" != "${port%,*}" ]; then
multiport="$multioption"
dports="--dports"
fi
dports="$dports $port"
fi
if [ -n "$cport" ]; then
sports="--sport"
if [ -n "$multioption" -a "$cport" != "${cport%,*}" ]; then
multiport="$multioption"
sports="--sports"
fi
sports="$sports $cport"
fi
}
interface_error()
{
fatal_error "Unknown interface $1 in rule: \"$rule\""
}
rule_interface_verify()
{
verify_interface $1 || interface_error $1
}
# Set source variables. The 'cli' variable will hold the client match predicate(s).
cli=
case "$client" in
-)
;;
*:*)
rule_interface_verify ${client%:*}
cli="$(match_source_dev ${client%:*}) $(source_ip_range ${client#*:})"
;;
*.*.*|+*)
cli="$(source_ip_range $client)"
;;
~*)
cli=$(mac_match $client)
;;
*)
if [ -n "$client" ]; then
rule_interface_verify $client
cli="$(match_source_dev $client)"
fi
;;
esac
# Set destination variables - 'serv' and 'dest_interface' hold the server match predicate(s).
dest_interface=
serv=
case "$server" in
-)
;;
*.*.*|+*)
serv=$server
;;
~*)
fatal_error "Rule \"$rule\" - Destination may not be specified by MAC Address"
;;
*)
if [ -n "$server" ]; then
[ -n "$nonat" ] && fatal_error "Destination interface not allowed with $logtarget"
rule_interface_verify $server
dest_interface="$(match_dest_dev $server)"
fi
;;
esac
# Setup protocol and port variables
sports=
dports=
proto=$protocol
addr=$address
servport=$serverport
multiport=
[ x$port = x- ] && port=
[ x$cport = x- ] && cport=
case $proto in
tcp|TCP|6)
do_ports
[ "$target" = QUEUE ] && proto="$proto --syn"
;;
udp|UDP|17)
do_ports
;;
icmp|ICMP|1)
[ -n "$port" ] && dports="--icmp-type $port"
;;
all|ALL)
[ -n "$port" ] && \
fatal_error "Port number not allowed with protocol \"all\"; rule: \"$rule\""
proto=
;;
*)
[ -n "$port" ] && \
fatal_error "Port number not allowed with protocol \"$proto\"; rule: \"$rule\""
;;
esac
proto="${proto:+-p $proto}"
# Some misc. setup
case "$logtarget" in
ACCEPT|DROP|REJECT|CONTINUE)
if [ -z "$proto" -a -z "$cli" -a -z "$serv" -a -z "$servport" -a -z "$userandgroup" ] ; then
error_message "Warning -- Rule \"$rule\" is a POLICY"
error_message " -- and should be moved to the policy file"
fi
;;
REDIRECT)
[ -n "$serv" ] && \
fatal_error "REDIRECT rules cannot specify a server IP; rule: \"$rule\""
servport=${servport:=$port}
natrule=Yes
;;
DNAT|SAME)
[ -n "$serv" ] || \
fatal_error "$logtarget rules require a server address; rule: \"$rule\""
natrule=Yes
;;
LOG)
[ -z "$loglevel" ] && \
fatal_error "LOG requires log level"
;;
esac
if [ -n "${serv}${servport}" ]; then
if [ $COMMAND != check ]; then
# A specific server or server port given
if [ -n "$natrule" ]; then
add_nat_rule
[ $policy = ACCEPT ] && return
elif [ -n "$servport" -a "$servport" != "$port" ]; then
fatal_error "Only DNAT, SAME and REDIRECT rules may specify destination port mapping; rule \"$rule\""
fi
if [ -z "$dnat_only" ]; then
if [ -n "$serv" ]; then
for serv1 in $(separate_list $serv); do
for srv in $(firewall_ip_range $serv1); do
if [ -n "$addr" -a -n "$CONNTRACK_MATCH" ]; then
for adr in $(separate_list $addr); do
if [ -n "$loglevel" -a -z "$natrule" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A -m conntrack --ctorigdst $adr \
$userandgroup $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports)
fi
run_iptables2 -A $chain $proto $ratelimit $multiport $cli $sports \
$(dest_ip_range $srv) $dports -m conntrack --ctorigdst $adr $userandgroup -j $target
done
else
if [ -n "$loglevel" -a -z "$natrule" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports)
fi
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $(dest_ip_range $srv) $dports $ratelimit $userandgroup -j RETURN
fi
if [ "$logtarget" != NONAT ]; then
run_iptables2 -A $chain $proto $multiport $cli $sports \
$(dest_ip_range $srv) $dports $ratelimit $userandgroup -j $target
fi
fi
done
done
else
if [ -n "$loglevel" -a -z "$natrule" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $sports $multiport $cli $dports)
fi
[ -n "$nonat" ] && \
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $dports $ratelimit $userandgroup -j RETURN
[ "$logtarget" != NONAT ] && \
run_iptables2 -A $chain $proto $multiport $cli $sports \
$dports $ratelimit $userandgroup -j $target
fi
fi
fi
else
# Destination is a simple zone
if [ $COMMAND != check ]; then
if [ -n "$addr" ]; then
for adr in $(separate_list $addr); do
if [ -n "$loglevel" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $multiport $cli $dest_interface $sports $dports -m conntrack --ctorigdst $adr)
fi
if [ "$logtarget" != LOG ]; then
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $dports $ratelimit $userandgroup -m conntrack --ctorigdst $adr -j RETURN
fi
if [ "$logtarget" != NONAT ]; then
run_iptables2 -A $chain $proto $multiport $cli $dest_interface \
$sports $dports $ratelimit $userandgroup -m conntrack --ctorigdst $adr -j $target
fi
fi
done
else
if [ -n "$loglevel" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $multiport $cli $dest_interface $sports $dports)
fi
if [ "$logtarget" != LOG ]; then
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $dports $ratelimit $userandgroup -j RETURN
fi
if [ "$logtarget" != NONAT ]; then
run_iptables2 -A $chain $proto $multiport $cli $dest_interface \
$sports $dports $ratelimit $userandgroup -j $target
fi
fi
fi
fi
fi
}
# #
# Process a record from the rules file for the 'start', 'restart' or 'check' commands # Process a record from the rules file for the 'start', 'restart' or 'check' commands
# #
@ -5073,8 +4802,283 @@ process_rule() # $1 = target
local userandgroup= local userandgroup=
local logtag= local logtag=
local nonat= local nonat=
#
# Add one Filter Rule
#
# The caller has established the following variables:
# COMMAND = current command. If 'check', we're executing a 'check'
# which only goes through the motions.
# client = SOURCE IP or MAC
# server = DESTINATION IP or interface
# protocol = Protocol
# address = Original Destination Address
# port = Destination Port
# cport = Source Port
# multioption = String to invoke multiport match if appropriate
# servport = Port the server listens on
# chain = The canonical chain for this rule or an exclusion chain
# logchain = The chain that should be mentioned in log messages
# ratelimit = Optional rate limiting clause
# userandgroup = -m owner clause
# userspec = User name
# logtag = Log tag
# policy = Applicable Policy
#
add_a_rule()
{
local natrule=
# Function Body - isolate rate limit do_ports() {
if [ -n "$port" ]; then
dports="--dport"
if [ -n "$multioption" -a "$port" != "${port%,*}" ]; then
multiport="$multioption"
dports="--dports"
fi
dports="$dports $port"
fi
if [ -n "$cport" ]; then
sports="--sport"
if [ -n "$multioption" -a "$cport" != "${cport%,*}" ]; then
multiport="$multioption"
sports="--sports"
fi
sports="$sports $cport"
fi
}
interface_error()
{
fatal_error "Unknown interface $1 in rule: \"$rule\""
}
rule_interface_verify()
{
verify_interface $1 || interface_error $1
}
# Set source variables. The 'cli' variable will hold the client match predicate(s).
cli=
case "$client" in
-)
;;
*:*)
rule_interface_verify ${client%:*}
cli="$(match_source_dev ${client%:*}) $(source_ip_range ${client#*:})"
;;
*.*.*|+*)
cli="$(source_ip_range $client)"
;;
~*)
cli=$(mac_match $client)
;;
*)
if [ -n "$client" ]; then
rule_interface_verify $client
cli="$(match_source_dev $client)"
fi
;;
esac
# Set destination variables - 'serv' and 'dest_interface' hold the server match predicate(s).
dest_interface=
serv=
case "$server" in
-)
;;
*.*.*|+*)
serv=$server
;;
~*)
fatal_error "Rule \"$rule\" - Destination may not be specified by MAC Address"
;;
*)
if [ -n "$server" ]; then
[ -n "$nonat" ] && fatal_error "Destination interface not allowed with $logtarget"
rule_interface_verify $server
dest_interface="$(match_dest_dev $server)"
fi
;;
esac
# Setup protocol and port variables
sports=
dports=
proto=$protocol
addr=$address
servport=$serverport
multiport=
[ x$port = x- ] && port=
[ x$cport = x- ] && cport=
case $proto in
tcp|TCP|6)
do_ports
[ "$target" = QUEUE ] && proto="$proto --syn"
;;
udp|UDP|17)
do_ports
;;
icmp|ICMP|1)
[ -n "$port" ] && dports="--icmp-type $port"
;;
all|ALL)
[ -n "$port" ] && \
fatal_error "Port number not allowed with protocol \"all\"; rule: \"$rule\""
proto=
;;
*)
[ -n "$port" ] && \
fatal_error "Port number not allowed with protocol \"$proto\"; rule: \"$rule\""
;;
esac
proto="${proto:+-p $proto}"
# Some misc. setup
case "$logtarget" in
ACCEPT|DROP|REJECT|CONTINUE)
if [ -z "$proto" -a -z "$cli" -a -z "$serv" -a -z "$servport" -a -z "$userandgroup" -a -z "$excludesource" -a -z "$excludedest" ] ; then
error_message "Warning -- Rule \"$rule\" is a POLICY"
error_message " -- and should be moved to the policy file"
fi
;;
REDIRECT)
[ -n "$excludedest" ] && fatal_error "Invalid DEST for this ACTION; rule \"$rule\""
[ -n "$serv" ] && \
fatal_error "REDIRECT rules cannot specify a server IP; rule: \"$rule\""
servport=${servport:=$port}
natrule=Yes
;;
DNAT|SAME)
[ -n "$excludedest" ] && fatal_error "Invalid DEST for this ACTION; rule \"$rule\""
[ -n "$serv" ] || \
fatal_error "$logtarget rules require a server address; rule: \"$rule\""
natrule=Yes
;;
LOG)
[ -z "$loglevel" ] && \
fatal_error "LOG requires log level"
;;
esac
if [ -n "${serv}${servport}" ]; then
if [ $COMMAND != check ]; then
# A specific server or server port given
if [ -n "$natrule" ]; then
add_nat_rule
[ $policy = ACCEPT ] && return
elif [ -n "$servport" -a "$servport" != "$port" ]; then
fatal_error "Only DNAT, SAME and REDIRECT rules may specify destination port mapping; rule \"$rule\""
fi
if [ -z "$dnat_only" ]; then
if [ -n "$serv" ]; then
for serv1 in $(separate_list $serv); do
for srv in $(firewall_ip_range $serv1); do
if [ -n "$addr" -a -n "$CONNTRACK_MATCH" ]; then
for adr in $(separate_list $addr); do
if [ -n "$loglevel" -a -z "$natrule" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A -m conntrack --ctorigdst $adr \
$userandgroup $(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports)
fi
run_iptables2 -A $chain $proto $ratelimit $multiport $cli $sports \
$(dest_ip_range $srv) $dports -m conntrack --ctorigdst $adr $userandgroup -j $target
done
else
if [ -n "$loglevel" -a -z "$natrule" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $sports $multiport $cli $(dest_ip_range $srv) $dports)
fi
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $(dest_ip_range $srv) $dports $ratelimit $userandgroup -j RETURN
fi
if [ "$logtarget" != NONAT ]; then
run_iptables2 -A $chain $proto $multiport $cli $sports \
$(dest_ip_range $srv) $dports $ratelimit $userandgroup -j $target
fi
fi
done
done
else
if [ -n "$loglevel" -a -z "$natrule" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $sports $multiport $cli $dports)
fi
[ -n "$nonat" ] && \
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $dports $ratelimit $userandgroup -j RETURN
[ "$logtarget" != NONAT ] && \
run_iptables2 -A $chain $proto $multiport $cli $sports \
$dports $ratelimit $userandgroup -j $target
fi
fi
fi
else
# Destination is a simple zone
if [ $COMMAND != check ]; then
if [ -n "$addr" ]; then
for adr in $(separate_list $addr); do
if [ -n "$loglevel" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $multiport $cli $dest_interface $sports $dports -m conntrack --ctorigdst $adr)
fi
if [ "$logtarget" != LOG ]; then
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $dports $ratelimit $userandgroup -m conntrack --ctorigdst $adr -j RETURN
fi
if [ "$logtarget" != NONAT ]; then
run_iptables2 -A $chain $proto $multiport $cli $dest_interface \
$sports $dports $ratelimit $userandgroup -m conntrack --ctorigdst $adr -j $target
fi
fi
done
else
if [ -n "$loglevel" ]; then
log_rule_limit $loglevel $chain $logchain $logtarget "$ratelimit" "$logtag" -A $userandgroup \
$(fix_bang $proto $multiport $cli $dest_interface $sports $dports)
fi
if [ "$logtarget" != LOG ]; then
if [ -n "$nonat" ]; then
addnatrule $(dnat_chain $source) $proto $multiport \
$cli $sports $dports $ratelimit $userandgroup -j RETURN
fi
if [ "$logtarget" != NONAT ]; then
run_iptables2 -A $chain $proto $multiport $cli $dest_interface \
$sports $dports $ratelimit $userandgroup -j $target
fi
fi
fi
fi
fi
}
# # # # # F u n c t i o n B o d y # # # # #
[ "x$ratelimit" = "x-" ] && ratelimit= [ "x$ratelimit" = "x-" ] && ratelimit=
@ -5222,15 +5226,19 @@ process_rule() # $1 = target
clients="${clients#*:}" clients="${clients#*:}"
[ -z "$clientzone" -o -z "$clients" ] && \ [ -z "$clientzone" -o -z "$clients" ] && \
fatal_error "Empty source zone or qualifier: rule \"$rule\"" fatal_error "Empty source zone or qualifier: rule \"$rule\""
if [ $(list_count $clients) -gt 1 ]; then
case $clients in
!*)
fatal_error "Exclude lists not supported in the SOURCE column"
;;
esac
fi
fi fi
excludesource=
case $clients in
!*)
if [ $(list_count $clients) -gt 1 ]; then
excludesource=${clients#!}
clients=
fi
;;
esac
validate_zone $clientzone || fatal_error "Undefined Client Zone in rule \"$rule\"" validate_zone $clientzone || fatal_error "Undefined Client Zone in rule \"$rule\""
# Parse and validate destination # Parse and validate destination
@ -5271,6 +5279,17 @@ process_rule() # $1 = target
fi fi
fi fi
excludedest=
case $servers in
!*)
if [ $(list_count $servers) -gt 1 ]; then
excludedest=${servers#*!}
servers=
fi
;;
esac
if ! validate_zone $serverzone; then if ! validate_zone $serverzone; then
fatal_error "Undefined Server Zone in rule \"$rule\"" fatal_error "Undefined Server Zone in rule \"$rule\""
fi fi
@ -5290,16 +5309,25 @@ process_rule() # $1 = target
[ $policy = NONE ] && \ [ $policy = NONE ] && \
fatal_error "Rules may not override a NONE policy: rule \"$rule\"" fatal_error "Rules may not override a NONE policy: rule \"$rule\""
# Create the canonical chain if it doesn't already exist [ "x$protocol" = "x-" ] && protocol=all || protocol=${protocol:=all}
[ $COMMAND = check ] || ensurechain $chain if [ $COMMAND != check ]; then
ensurechain $chain
if [ -n "${excludesource}${excludedest}" ]; then
build_exclusion_chain newchain filter "$excludesource" "$excludedest"
run_iptables -A $chain -p $protocol -j $newchain
chain=$newchain
fi
fi
# Generate Netfilter rule(s) # Generate Netfilter rule(s)
protocol=${protocol:=all}
case $logtarget in case $logtarget in
DNAT*|SAME) DNAT*|SAME)
if [ -n "$XMULTIPORT" ] && \ if [ -n "$XMULTIPORT" ] && \
! list_search $protocol "icmp" "ICMP" "1" && \ ! list_search $protocol "icmp" "ICMP" "1" && \
[ $(( $(list_count $ports) + $(list_count1 $(split $ports ) ) )) -le 16 -a \ [ $(( $(list_count $ports) + $(list_count1 $(split $ports ) ) )) -le 16 -a \

View File

@ -331,3 +331,15 @@ New Features in Shorewall 2.5.*
9) Shorewall not generates an error if the 'norfc1918' option is 9) Shorewall not generates an error if the 'norfc1918' option is
specified for an interface with an RFC 1918 address. specified for an interface with an RFC 1918 address.
10) You may now specify "!" followed by a list of addresses in the
SOURCE and DEST columns of entries in /etc/shorewall/rules and
Shorewall will generate the rule that you expect.
Example:
#ACTION SOURCE DEST PROTO DEST PORT(S)
ACCEPT loc:!192.168.1.0/24,10.0.0.0/8 net tcp 80
That rule would allow loc->net HTTP access except for the local
networks 192.168.1.0/24 and 10.0.0.0/8.