diff --git a/Shorewall/action.template b/Shorewall/action.template new file mode 100644 index 000000000..b58ed1af3 --- /dev/null +++ b/Shorewall/action.template @@ -0,0 +1,127 @@ +# +# Shorewall 1.4 /etc/shorewall/action.template +# +# This file is a template for files with names of the form +# /etc/shorewall/action. where is an +# TARGET defined in /etc/shorewall/actions. +# +# To define a new action: +# +# 1. Add the to /etc/shorewall/actions +# 2. Copy this file to /etc/shorewall/action. +# 3. Add the desired rules to that file. +# +# Columns are: +# +# +# TARGET ACCEPT, DROP, REJECT, DNAT, DNAT-, REDIRECT, CONTINUE +# or LOG. +# +# ACCEPT -- allow the connection request +# DROP -- ignore the request +# REJECT -- disallow the request and return an +# icmp-unreachable or an RST packet. +# LOG -- Simply log the packet and continue. +# QUEUE -- Queue the packet to a user-space +# application such as p2pwall. +# +# The TARGET may optionally be followed +# by ":" and a syslog log level (e.g, REJECT:info or +# DNAT:debugging). This causes the packet to be +# logged at the specified level. +# +# You may also specify ULOG (must be in upper case) as a +# log level.This will log to the ULOG target for routing +# to a separate log through use of ulogd +# (http://www.gnumonks.org/projects/ulogd). +# +# SOURCE Source hosts to which the rule applies. +# A comma-separated list of subnets +# and/or hosts. Hosts may be specified by IP or MAC +# address; mac addresses must begin with "~" and must use +# "-" as a separator. +# +# 192.168.2.2 Host 192.168.2.2 +# +# 155.186.235.0/24 Subnet 155.186.235.0/24 +# +# 192.168.1.1,192.168.1.2 +# Hosts 192.168.1.1 and +# 192.168.1.2. +# ~00-A0-C9-15-39-78 Host with +# MAC address 00:A0:C9:15:39:78. +# +# Alternatively, clients may be specified by interface +# name. For example, eth1 specifies a +# client that communicates with the firewall system +# through eth1. This may be optionally followed by +# another colon (":") and an IP/MAC/subnet address +# as described above (e.g., eth1:192.168.1.5). +# +# DEST Location of Server. Same as above with the exception that +# MAC addresses are not allowed. +# +# Unlike in the SOURCE column, you may specify a range of +# up to 256 IP addresses using the syntax +# -. +# +# PROTO Protocol - Must be "tcp", "udp", "icmp", a number, or +# "all". +# +# DEST PORT(S) Destination Ports. A comma-separated list of Port +# names (from /etc/services), port numbers or port +# ranges; if the protocol is "icmp", this column is +# interpreted as the destination icmp-type(s). +# +# A port range is expressed as :. +# +# This column is ignored if PROTOCOL = all but must be +# entered if any of the following ields are supplied. +# In that case, it is suggested that this field contain +# "-" +# +# If your kernel contains multi-port match support, then +# only a single Netfilter rule will be generated if in +# this list and the CLIENT PORT(S) list below: +# 1. There are 15 or less ports listed. +# 2. No port ranges are included. +# Otherwise, a separate rule will be generated for each +# port. +# +# CLIENT PORT(S) (Optional) Port(s) used by the client. If omitted, +# any source port is acceptable. Specified as a comma- +# separated list of port names, port numbers or port +# ranges. +# +# If you don't want to restrict client ports but need to +# specify an ADDRESS in the next column, then place "-" +# in this column. +# +# If your kernel contains multi-port match support, then +# only a single Netfilter rule will be generated if in +# this list and the DEST PORT(S) list above: +# 1. There are 15 or less ports listed. +# 2. No port ranges are included. +# Otherwise, a separate rule will be generated for each +# port. +# +# RATE LIMIT You may rate-limit the rule by placing a value in +# this colume: +# +# /[:] +# +# where is the number of connections per +# ("sec" or "min") and is the +# largest burst permitted. If no is given, +# a value of 5 is assumed. There may be no +# no whitespace embedded in the specification. +# +# Example: 10/sec:20 +# +# If you place a rate limit in this column, you may not +# place a similar limit in the TARGET column. +# +###################################################################################### +#TARGET SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE +# PORT PORT(S) DEST LIMIT +#LAST LINE -- ADD YOUR ENTRIES BEFORE THIS ONE -- DO NOT REMOVE diff --git a/Shorewall/actions b/Shorewall/actions new file mode 100644 index 000000000..d48927a96 --- /dev/null +++ b/Shorewall/actions @@ -0,0 +1,16 @@ +# +# Shorewall 1.4 /etc/shorewall/actions +# +# This file allows you to define new ACTIONS for use in rules +# (/etc/shorewall/rules). You define the iptables rules to +# be performed in an ACTION in +# /etc/shorewall/action.. +# +# ACTION names should begin with an upper-case letter to +# distinguish them from Shorewall-generated chain names and +# they must need the requirements of a Netfilter chain +# name. +# +#ACTION + +#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE diff --git a/Shorewall/changelog.txt b/Shorewall/changelog.txt index 588f67ac4..53c05ae3d 100755 --- a/Shorewall/changelog.txt +++ b/Shorewall/changelog.txt @@ -14,3 +14,4 @@ Changes since 1.4.8 7) Added MODULE_SUFFIX option to shorewall.conf. +8) Add /etc/shorewall/actions and /etc/shorewall/action.template diff --git a/Shorewall/fallback.sh b/Shorewall/fallback.sh index 7c7612ab6..6fc2918b9 100755 --- a/Shorewall/fallback.sh +++ b/Shorewall/fallback.sh @@ -140,6 +140,10 @@ restore_file /etc/shorewall/usersets restore_file /etc/shorewall/users +restore_file /etc/shorewall/actions + +restore_file /etc/shorewall/action.template + if [ -f /usr/lib/shorewall/version-${VERSION}.bkout ]; then restore_file /usr/lib/shorewall/version oldversion="`cat /usr/lib/shorewall/version`" diff --git a/Shorewall/firewall b/Shorewall/firewall index 55b99d6ef..ea1dfb99b 100755 --- a/Shorewall/firewall +++ b/Shorewall/firewall @@ -2072,6 +2072,10 @@ check_config() { validate_policy + echo "Validating Actions..." + + process_actions + echo "Validating rules file..." rules=`find_file rules` @@ -2122,6 +2126,334 @@ refresh_tc() { } +# +# Add one Filter Rule from an action -- Helper function for the action file processor +# +# The caller has established the following variables: +# check = 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 +# chain = The chain for this rule +# ratelimit = Optional rate limiting clause +# +add_an_action() +{ + 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 + } + + # Set source variables. The 'cli' variable will hold the client match predicate(s). + + cli= + + case "$client" in + -) + ;; + *:*) + cli="-i ${client%:*} -s ${client#*:}" + ;; + *.*.*) + cli="-s $client" + ;; + ~*) + cli=`mac_match $client` + ;; + *) + [ -n "$client" ] && cli="-i $client" + ;; + 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" + ;; + *) + [ -n "$server" ] && dest_interface="-o $server" + ;; + esac + + # Setup protocol and port variables + + sports= + dports= + state="-m state --state NEW" + proto=$protocol + 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" + state= + ;; + all|ALL) + [ -n "$port" ] && \ + fatal_error "Port number not allowed with protocol \"all\"; rule: \"$rule\"" + proto= + ;; + *) + state= + [ -n "$port" ] && \ + fatal_error "Port number not allowed with protocol \"$proto\"; rule: \"$rule\"" + ;; + esac + + proto="${proto:+-p $proto}" + + # Some misc. setup + + case "$logtarget" in + LOG) + [ -z "$loglevel" ] && fatal_error "LOG requires log level" + ;; + esac + + if [ $command != check ]; then + if [ -n "${serv}" ]; then + for serv1 in `separate_list $serv`; do + for srv in `ip_range $serv1`; do + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain $logtarget "$ratelimit" \ + `fix_bang $proto $sports $multiport $state $cli -d $srv $dports` + fi + + run_iptables2 -A $chain $proto $multiport $state $cli $sports \ + -d $srv $dports $ratelimit -j $target + done + done + else + if [ -n "$loglevel" ]; then + log_rule_limit $loglevel $chain $logtarget "$ratelimit" \ + `fix_bang $proto $sports $multiport $state $cli $dports` + fi + + run_iptables2 -A $chain $proto $multiport $state $cli $sports \ + $dports $ratelimit -j $target + fi + fi +} + +# +# Process a record from the rules file for the 'start', 'restart' or 'check' commands +# +process_action() # $1 = target + # $2 = clients + # $3 = servers + # $4 = protocol + # $5 = ports + # $6 = cports + # $7 = ratelimit +{ + local target="$1" + local clients="$2" + local servers="$3" + local protocol="$4" + local ports="$5" + local cports="$6" + local ratelimit="$7" + local rule="`echo $target $clients $servers $protocol $ports $cports $ratelimit`" + + if [ -n "$ratelimit" ]; then + case $ratelimit in + -) + ratelimit= + ;; + *:*) + ratelimit="-m limit --limit ${ratelimit%:*} --limit-burst ${ratelimit#*:}" + ;; + *) + ratelimit="-m limit --limit $ratelimit" + ;; + esac + fi + + # Isolate log level + + if [ "$target" = "${target%:*}" ]; then + loglevel= + else + loglevel="${target#*:}" + target="${target%:*}" + expandv loglevel + fi + + chain="$action" + logtarget="$target" + + case $target in + ACCEPT|LOG) + ;; + REJECT) + target=reject + ;; + *) + ;; + esac + + # Generate Netfilter rule(s) + + protocol=${protocol:=all} + + if [ -n "$MULTIPORT" ] && \ + ! list_search $protocol "icmp" "ICMP" "1" && \ + [ "$ports" = "${ports%:*}" -a \ + "$cports" = "${cports%:*}" -a \ + `list_count $ports` -le 15 -a \ + `list_count $cports` -le 15 ] + then + # + # MULTIPORT is enabled, there are no port ranges in the rule and less than + # 16 ports are listed - use multiport match. + # + multioption="-m multiport" + for client in `separate_list ${clients:=-}`; do + for server in `separate_list ${servers:=-}`; do + # + # add_a_rule() modifies these so we must set their values each time + # + port=${ports:=-} + cport=${cports:=-} + add_an_action + done + done + else + # + # MULTIPORT is disabled or the rule isn't compatible with multiport match + # + multioption= + for client in `separate_list ${clients:=-}`; do + for server in `separate_list ${servers:=-}`; do + for port in `separate_list ${ports:=-}`; do + for cport in `separate_list ${cports:=-}`; do + add_an_action + done + done + done + done + fi + # + # Report Result + # + if [ $command = check ]; then + echo " Rule \"$rule\" checked." + else + echo " Rule \"$rule\" added." + fi +} + +process_actions() { + # + # Process a rule where the source or destination is "all" + # + process_wildcard_rule() { + local yclients yservers ysourcezone ydestzone ypolicy + + for yclients in $xclients; do + for yservers in $xservers; do + ysourcezone=${yclients%%:*} + ydestzone=${yservers%%:*} + if [ "${ysourcezone}" != "${ydestzone}" ] ; then + eval ypolicy=\$${ysourcezone}2${ydestzone}_policy + if [ "$ypolicy" != NONE ] ; then + process_action $xtarget $yclients $yservers $xprotocol $xports $xcports $xratelimit + fi + fi + done + done + } + + strip_file actions + + while read action rest; do + [ "x$rest" = x ] || fatal_error "Invalid Action: $action $rest" + [ "$command" = check ] || createchain $action No + ACTIONS="$ACTIONS $action" + done < $TMP_DIR/actions + + for action in $ACTIONS; do + f=action.$action + fn=`find_file $f` + + if [ -f $fn ]; then + strip_file $f $fn + while read xtarget xclients xservers xprotocol xports xcports xratelimit ; do + temp="${xtarget%:*}" + case "${temp%<*}" in + ACCEPT|DROP|REJECT|LOG|QUEUE) + expandv xclients xservers xprotocol xports xcports xratelimit + + if [ "x$xclients" = xall ]; then + xclients="$zones $FW" + if [ "x$xservers" = xall ]; then + xservers="$zones $FW" + fi + process_wildcard_rule + continue + fi + + if [ "x$xservers" = xall ]; then + xservers="$zones $FW" + process_wildcard_rule + continue + fi + + process_action $xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit + ;; + *) + rule="`echo $xtarget $xclients $xservers $xprotocol $xports $xcports $xratelimit`" + fatal_error "Invalid Action in rule \"$rule\"" + ;; + + esac + done < $TMP_DIR/$f + else + fatal_error "Missing Action File: $f" + fi + done +} + # # Add a NAT rule - Helper function for the rules file processor # @@ -2885,41 +3217,56 @@ process_rules() # Process a rule where the source or destination is "all" # process_wildcard_rule() { + local yclients yservers ysourcezone ydestzone ypolicy + for yclients in $xclients; do for yservers in $xservers; do - if [ "${yclients}" != "${yservers}" ] ; then - process_rule $xtarget $yclients $yservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserset + ysourcezone=${yclients%%:*} + ydestzone=${yservers%%:*} + if [ "${ysourcezone}" != "${ydestzone}" ] ; then + eval ypolicy=\$${ysourcezone}2${ydestzone}_policy + if [ "$ypolicy" != NONE ] ; then + process_rule $xtarget $yclients $yservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserset + fi fi done done } + do_it() { + expandv xclients xservers xprotocol xports xcports xaddress xratelimit xuserset + + if [ "x$xclients" = xall ]; then + xclients="$zones $FW" + if [ "x$xservers" = xall ]; then + xservers="$zones $FW" + fi + process_wildcard_rule + continue + fi + + if [ "x$xservers" = xall ]; then + xservers="$zones $FW" + process_wildcard_rule + continue + fi + + process_rule $xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserset + } + while read xtarget xclients xservers xprotocol xports xcports xaddress xratelimit xuserset; do temp="${xtarget%:*}" case "${temp%<*}" in ACCEPT|DROP|REJECT|DNAT|DNAT-|REDIRECT|REDIRECT-|LOG|CONTINUE|QUEUE) - expandv xclients xservers xprotocol xports xcports xaddress xratelimit xuserset - - if [ "x$xclients" = xall ]; then - xclients="$zones $FW" - if [ "x$xservers" = xall ]; then - xservers="$zones $FW" - fi - process_wildcard_rule - continue - fi - - if [ "x$xservers" = xall ]; then - xservers="$zones $FW" - process_wildcard_rule - continue - fi - - process_rule $xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserset + do_it ;; *) - rule="`echo $xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserset`" - fatal_error "Invalid Action in rule \"$rule\"" + if list_search $temp $ACTIONS; then + do_it + else + rule="`echo $xtarget $xclients $xservers $xprotocol $xports $xcports $xaddress $xratelimit $xuserset`" + fatal_error "Invalid Action in rule \"$rule\"" + fi ;; esac @@ -4534,6 +4881,10 @@ define_firewall() # $1 = Command (Start or Restart) rules=`find_file rules` + echo "Processing Actions..." + + process_actions + echo "Processing $rules..." process_rules @@ -5060,6 +5411,7 @@ do_initialize() { ADMINISABSENTMINDED= BLACKLISTNEWONLY= MODULE_SUFFIX= + ACTIONS= stopping= have_mutex= diff --git a/Shorewall/install.sh b/Shorewall/install.sh index 925546d38..b4b4414b0 100755 --- a/Shorewall/install.sh +++ b/Shorewall/install.sh @@ -586,6 +586,26 @@ else echo "Users file installed as ${PREFIX}/etc/shorewall/users" fi # +# Install the Actions file +# +if [ -f ${PREFIX}/etc/shorewall/actions ]; then + backup_file /etc/shorewall/actions +else + run_install -o $OWNER -g $GROUP -m 0600 actions ${PREFIX}/etc/shorewall/actions + echo + echo "Actions file installed as ${PREFIX}/etc/shorewall/actions" +fi +# +# Install the Action Template file +# +if [ -f ${PREFIX}/etc/shorewall/action.template ]; then + backup_file /etc/shorewall/action.template +else + run_install -o $OWNER -g $GROUP -m 0600 action.template ${PREFIX}/etc/shorewall/action.template + echo + echo "Action Template file installed as ${PREFIX}/etc/shorewall/action.template" +fi +# # Backup the version file # if [ -z "$PREFIX" ]; then diff --git a/Shorewall/releasenotes.txt b/Shorewall/releasenotes.txt index 710b9e772..485831d19 100755 --- a/Shorewall/releasenotes.txt +++ b/Shorewall/releasenotes.txt @@ -48,6 +48,33 @@ New Features: If all files end in ".kzo" then set MODULE_SUFFIX="kzo" If all files end in ".kz.o" then set MODULE_SUFFIX="kz.o" +4) Support for user defined rule ACTIONS has been implemented through + two new files: + + /etc/shorewall/actions - used to list the user-defined ACTIONS. + /etc/shorewall/action.template - For each user defined , copy + this file to + /etc/shorewall/action. and + add the appropriate rules for that + . + Once an has been defined, it may be used like any of the + builtin ACTIONS (ACCEPT, DROP, etc.) in /etc/shorewall/rules. + + Example: You want an action that logs a packet at the 'info' level + and accepts the connection. + + In /etc/shorewall/actions, you would add: + + LogAndAccept + + You would then copy /etc/shorewall/action.template to + /etc/shorewall/LogAndAccept and in that file, you would add the two + rules: + + LOG:info + ACCEPT + + diff --git a/Shorewall/rules b/Shorewall/rules index 463368608..2aef33877 100755 --- a/Shorewall/rules +++ b/Shorewall/rules @@ -48,6 +48,8 @@ # LOG -- Simply log the packet and continue. # QUEUE -- Queue the packet to a user-space # application such as p2pwall. +# -- The name of an action defined in +# /etc/shorewall/actions. # # You may rate-limit the rule by optionally # following ACCEPT, DNAT[-], REDIRECT[-] or LOG with diff --git a/Shorewall/shorewall.spec b/Shorewall/shorewall.spec index aa3ad3e80..d0ce8dd5b 100644 --- a/Shorewall/shorewall.spec +++ b/Shorewall/shorewall.spec @@ -100,6 +100,8 @@ fi %attr(0600,root,root) %config(noreplace) /etc/shorewall/accounting %attr(0600,root,root) %config(noreplace) /etc/shorewall/usersets %attr(0600,root,root) %config(noreplace) /etc/shorewall/users +%attr(0600,root,root) %config(noreplace) /etc/shorewall/actions +%attr(0600,root,root) %config(noreplace) /etc/shorewall/action.template %attr(0544,root,root) /sbin/shorewall %attr(0444,root,root) /usr/share/shorewall/functions %attr(0544,root,root) /usr/share/shorewall/firewall @@ -108,6 +110,8 @@ fi %doc COPYING INSTALL changelog.txt releasenotes.txt tunnel %changelog +* Wed Dec 03 2003 Tom Eastep +- Added User Defined Actions Files * Fri Nov 07 2003 Tom Eastep - Changed version to 1.4.8 * Sat Nov 01 2003 Tom Eastep