[package] firewall:
authorJo-Philipp Wich <jow@openwrt.org>
Sat, 11 Sep 2010 20:04:34 +0000 (20:04 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sat, 11 Sep 2010 20:04:34 +0000 (20:04 +0000)
- simplify masquerade rule setup
- remove various subshell invocations
- speedup fw() by not relying on xargs and pipes
- rework SNAT support - attach to dest zone, use src_dip/src_dport as snat source

SVN-Revision: 23024

package/firewall/Makefile
package/firewall/files/lib/core_forwarding.sh
package/firewall/files/lib/core_init.sh
package/firewall/files/lib/core_interface.sh
package/firewall/files/lib/core_redirect.sh
package/firewall/files/lib/core_rule.sh
package/firewall/files/lib/fw.sh

index b6d42ce..00badcb 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 PKG_NAME:=firewall
 
 PKG_VERSION:=2
-PKG_RELEASE:=12
+PKG_RELEASE:=13
 
 include $(INCLUDE_DIR)/package.mk
 
index b62e18a..c4a9681 100644 (file)
@@ -27,7 +27,8 @@ fw_load_forwarding() {
                target=zone_${forwarding_dest}_ACCEPT
        }
 
-       local mode=$(fw_get_family_mode ${forwarding_family:-x} ${forwarding_dest:-${forwarding_src:--}} i)
+       local mode
+       fw_get_family_mode mode ${forwarding_family:-x} ${forwarding_dest:-${forwarding_src:--}} i
 
        fw add $mode f $chain $target ^
 
index bce94af..e1f80ba 100644 (file)
@@ -212,9 +212,6 @@ fw_load_zone() {
 
        fw add $mode r ${chain}_notrack
 
-       [ $zone_masq == 1 ] && \
-               fw add $mode n POSTROUTING ${chain}_nat $
-
        [ $zone_mtu_fix == 1 ] && \
                fw add $mode f FORWARD ${chain}_MSSFIX ^
 
@@ -243,6 +240,18 @@ fw_load_zone() {
                done
        }
 
+       # NB: if MASQUERADING for IPv6 becomes available we'll need a family check here
+       if [ "$zone_masq" == 1 ]; then
+               local msrc mdst
+               for msrc in ${zone_masq_src:-0.0.0.0/0}; do
+                       [ "${msrc#!}" != "$msrc" ] && msrc="! -s ${msrc#!}" || msrc="-s $msrc"
+                       for mdst in ${zone_masq_dest:-0.0.0.0/0}; do
+                               [ "${mdst#!}" != "$mdst" ] && mdst="! -d ${mdst#!}" || mdst="-d $mdst"
+                               fw add $mode n ${chain}_nat MASQUERADE $ { $msrc $mdst }
+                       done
+               done
+       fi
+
        fw_callback post zone
 }
 
index c2a5bd7..889dcc9 100644 (file)
@@ -27,11 +27,9 @@ fw_configure_interface() {
                local chain=zone_${zone}
                local ifname=$3
                local subnet=$4
-               local masq_src=$5
-               local masq_dest=$6
 
-               local inet onet
-               local mode=$(fw_get_family_mode x $zone i)
+               local inet onet mode
+               fw_get_family_mode mode x $zone i
 
                case "$mode/$subnet" in
                        # Zone supports v6 only or dual, need v6
@@ -62,38 +60,27 @@ fw_configure_interface() {
                fw $action $mode f ${chain}_REJECT reject $ { -o "$ifname" $onet }
                fw $action $mode f ${chain}_REJECT reject $ { -i "$ifname" $inet }
 
-               # NB: if MASQUERADING for IPv6 becomes available we'll need a family check here
-               local msrc mdst
-               for msrc in ${masq_src:-0.0.0.0/0}; do
-                       [ "${msrc#!}" != "$msrc" ] && msrc="! -s ${msrc#!}" || msrc="-s $msrc"
-                       for mdst in ${subnet:-${masq_dest:-0.0.0.0/0}}; do
-                               [ "${mdst#!}" != "$mdst" ] && mdst="! -d ${mdst#!}" || mdst="-d $mdst"
-                               fw $action $mode n ${chain}_nat MASQUERADE $ { -o "$ifname" $msrc $mdst }
-                       done
-               done
-
                fw $action $mode f ${chain}_MSSFIX TCPMSS  $ { -o "$ifname" -p tcp --tcp-flags SYN,RST SYN --clamp-mss-to-pmtu $onet }
 
                fw $action $mode f input   ${chain}         $ { -i "$ifname" $inet }
                fw $action $mode f forward ${chain}_forward $ { -i "$ifname" $inet }
                fw $action $mode n PREROUTING ${chain}_prerouting $ { -i "$ifname" $inet }
                fw $action $mode r PREROUTING ${chain}_notrack    $ { -i "$ifname" $inet }
+               fw $action $mode n POSTROUTING ${chain}_nat       $ { -o "$ifname" $onet }
        }
 
-       local old_zones old_ifname old_subnets old_masq_src old_masq_dest
+       local old_zones old_ifname old_subnets
        config_get old_zones core "${iface}_zone"
        [ -n "$old_zones" ] && {
                config_get old_ifname core "${iface}_ifname"
                config_get old_subnets core "${iface}_subnets"
-               config_get old_masq_src core "${iface}_masq_src"
-               config_get old_masq_dest core "${iface}_masq_dest"
 
                local z
                for z in $old_zones; do
                        local n
                        for n in ${old_subnets:-""}; do
                                fw_log info "removing $iface ($old_ifname${n:+ alias $n}) from zone $z"
-                               fw__do_rules del $z $old_ifname $n "$old_masq_src" "$old_masq_dest"
+                               fw__do_rules del $z $old_ifname $n
                        done
 
                        [ -n "$old_subnets" ] || ACTION=remove ZONE="$z" INTERFACE="$iface" DEVICE="$ifname" /sbin/hotplug-call firewall
@@ -111,8 +98,6 @@ fw_configure_interface() {
                uci_revert_state firewall core "${iface}_ifname"
                uci_revert_state firewall core "${iface}_subnets"
                uci_revert_state firewall core "${iface}_aliases"
-               uci_revert_state firewall core "${iface}_masq_src"
-               uci_revert_state firewall core "${iface}_masq_dest"
        }
 
        [ "$action" == del ] && return
@@ -146,17 +131,13 @@ fw_configure_interface() {
        }
 
        local new_zones=
-       local new_masq_src=
-       local new_masq_dest=
        load_zone() {
                fw_config_get_zone "$1"
                list_contains zone_network "$iface" || return
 
                fw_log info "adding $iface ($ifname${aliasnet:+ alias $aliasnet}) to zone $zone_name"
-               fw__do_rules add ${zone_name} "$ifname" "$aliasnet" "$zone_masq_src" "$zone_masq_dest"
+               fw__do_rules add ${zone_name} "$ifname" "$aliasnet"
                append new_zones $zone_name
-               append new_masq_src "$zone_masq_src"
-               append new_masq_dest "$zone_masq_dest"
 
                [ -n "$aliasnet" ] || ACTION=add ZONE="$zone_name" INTERFACE="$iface" DEVICE="$ifname" /sbin/hotplug-call firewall
        }
@@ -164,8 +145,6 @@ fw_configure_interface() {
 
        uci_set_state firewall core "${iface}_zone" "$new_zones"
        uci_set_state firewall core "${iface}_ifname" "$ifname"
-       uci_set_state firewall core "${iface}_masq_src" "$new_masq_src"
-       uci_set_state firewall core "${iface}_masq_dest" "$new_masq_dest"
 }
 
 fw_sysctl_interface() {
index 2f0e38f..72364a9 100644 (file)
@@ -27,53 +27,77 @@ fw_load_redirect() {
 
        fw_callback pre redirect
 
-       [ -n "$redirect_src" -a -n "$redirect_dest_ip$redirect_dest_port" ] || {
-               fw_die "redirect ${redirect_name}: needs src and dest_ip or dest_port"
-       }
-
-       local chain destopt destaddr
+       local fwdchain natchain natopt nataddr natports srcdaddr srcdports
        if [ "$redirect_target" == "DNAT" ]; then
-               chain="zone_${redirect_src}_prerouting"
-               destopt="--to-destination"
-               destaddr="$redirect_dest_ip"
+               [ -n "$redirect_src" -a -n "$redirect_dest_ip$redirect_dest_port" ] || {
+                       fw_die "DNAT redirect ${redirect_name}: needs src and dest_ip or dest_port"
+               }
+
+               fwdchain="zone_${redirect_src}_forward"
+
+               natopt="--to-destination"
+               natchain="zone_${redirect_src}_prerouting"
+               nataddr="$redirect_dest_ip"
+               fw_get_port_range natports "$redirect_dest_port" "-"
+
+               srcdaddr="${redirect_src_dip:+$redirect_src_dip/$redirect_src_dip_prefixlen}"
+               fw_get_port_range srcdports "$redirect_src_dport" ":"
+
+               list_contains FW_CONNTRACK_ZONES $redirect_src || \
+                       append FW_CONNTRACK_ZONES $redirect_src
+
        elif [ "$redirect_target" == "SNAT" ]; then
-               chain="zone_${redirect_src}_nat"
-               destopt="--to-source"
-               destaddr="$redirect_src_dip"
+               [ -n "$redirect_dest" -a -n "$redirect_src_dip" ] || {
+                       fw_die "SNAT redirect ${redirect_name}: needs dest and src_dip"
+               }
+
+               fwdchain="${redirect_src:+zone_${redirect_src}_forward}"
+
+               natopt="--to-source"
+               natchain="zone_${redirect_dest}_nat"
+               nataddr="$redirect_src_dip"
+               fw_get_port_range natports "$redirect_src_dport" "-"
+
+               srcdaddr="${redirect_dest_ip:+$redirect_dest_ip/$redirect_dest_ip_prefixlen}"
+               fw_get_port_range srcdports "$redirect_dest_port" ":"
+
+               list_contains FW_CONNTRACK_ZONES $redirect_dest || \
+                       append FW_CONNTRACK_ZONES $redirect_dest
+
        else
                fw_die "redirect ${redirect_name}: target must be either DNAT or SNAT"
        fi
 
-       list_contains FW_CONNTRACK_ZONES $redirect_src || \
-               append FW_CONNTRACK_ZONES $redirect_src
+       local mode
+       fw_get_family_mode mode ${redirect_family:-x} ${redirect_src:-$redirect_dest} I
 
-       local mode=$(fw_get_family_mode ${redirect_family:-x} $redirect_src I)
+       local srcaddr="${redirect_src_ip:+$redirect_src_ip/$redirect_src_ip_prefixlen}"
+       local srcports
+       fw_get_port_range srcports "$redirect_src_port" ":"
 
-       local nat_dest_port=$redirect_dest_port
-       redirect_dest_port=$(fw_get_port_range $redirect_dest_port)
-       redirect_src_port=$(fw_get_port_range $redirect_src_port)
-       redirect_src_dport=$(fw_get_port_range $redirect_src_dport)
-       local fwd_dest_port=${redirect_dest_port:-$redirect_src_dport}
+       local destaddr="${redirect_dest_ip:+$redirect_dest_ip/$redirect_dest_ip_prefixlen}"
+       local destports
+       fw_get_port_range destports "${redirect_dest_port:-$redirect_src_dport}" ":"
 
        [ "$redirect_proto" == "tcpudp" ] && redirect_proto="tcp udp"
        for redirect_proto in $redirect_proto; do
-               fw add $mode n $chain $redirect_target $ { $redirect_src_ip $redirect_dest_ip } { \
+               fw add $mode n $natchain $redirect_target ^ { $redirect_src_ip $redirect_dest_ip } { \
                        ${redirect_proto:+-p $redirect_proto} \
-                       ${redirect_src_ip:+-s $redirect_src_ip/$redirect_src_ip_prefixlen} \
-                       ${redirect_src_dip:+-d $redirect_src_dip/$redirect_src_dip_prefixlen} \
-                       ${redirect_src_port:+--sport $redirect_src_port} \
-                       ${redirect_src_dport:+--dport $redirect_src_dport} \
+                       ${srcaddr:+-s $srcaddr} \
+                       ${srcports:+--sport $srcports} \
+                       ${srcdaddr:+-d $srcdaddr} \
+                       ${srcdports:+--dport $srcdports} \
                        ${redirect_src_mac:+-m mac --mac-source $redirect_src_mac} \
-                       $destopt ${redirect_dest_ip}${redirect_dest_port:+:$nat_dest_port} \
+                       $natopt $nataddr${natports:+:$natports} \
                }
 
                [ -n "$destaddr" ] && \
-               fw add $mode f zone_${redirect_src}_forward ACCEPT ^ { $redirect_src_ip $redirect_dest_ip } { \
-                       -d $destaddr \
+               fw add $mode f ${fwdchain:-forward} ACCEPT ^ { $redirect_src_ip $redirect_dest_ip } { \
                        ${redirect_proto:+-p $redirect_proto} \
-                       ${redirect_src_ip:+-s $redirect_src_ip/$redirect_src_ip_prefixlen} \
-                       ${redirect_src_port:+--sport $redirect_src_port} \
-                       ${fwd_dest_port:+--dport $fwd_dest_port} \
+                       ${srcaddr:+-s $srcaddr} \
+                       ${srcports:+--sport $srcports} \
+                       ${destaddr:+-d $destaddr} \
+                       ${destports:+--dport $destports} \
                        ${redirect_src_mac:+-m mac --mac-source $redirect_src_mac} \
                }
        done
index e1f8d2a..1e4afe5 100644 (file)
@@ -26,8 +26,8 @@ fw_load_rule() {
 
        fw_callback pre rule
 
-       rule_src_port=$(fw_get_port_range $rule_src_port)
-       rule_dest_port=$(fw_get_port_range $rule_dest_port)
+       fw_get_port_range rule_src_port $rule_src_port
+       fw_get_port_range rule_dest_port $rule_dest_port
 
        local chain=input
        [ -n "$rule_src" ] && {
@@ -46,7 +46,8 @@ fw_load_rule() {
                target=zone_${rule_dest}_${target}
        }
 
-       local mode=$(fw_get_family_mode ${rule_family:-x} $rule_src I)
+       local mode
+       fw_get_family_mode mode ${rule_family:-x} $rule_src I
 
        local rule_pos
        eval 'rule_pos=$((++FW__RULE_COUNT_'$mode'_'$chain'))'
index aaf3d14..3549f8a 100644 (file)
@@ -159,56 +159,62 @@ fw__exec() { # <action> <family> <table> <chain> <target> <position> { <rules> }
                fi
        fi
 
+       local cmdline="$app --table ${tab} --${cmd} ${chn} ${pol} ${pos} ${tgt:+--jump "$tgt"}"
        while [ $# -gt 1 ]; do
                case "$app:$1" in
-                       ip6tables:--icmp-type) echo -n "--icmpv6-type" ;;
-                       ip6tables:icmp|ip6tables:ICMP) echo -n "icmpv6" ;;
-                       iptables:--icmpv6-type) echo -n "--icmp-type" ;;
-                       iptables:icmpv6) echo -n "icmp" ;;
-                       *) echo -n "$1" ;;
+                       ip6tables:--icmp-type) cmdline="$cmdline --icmpv6-type" ;;
+                       ip6tables:icmp|ip6tables:ICMP) cmdline="$cmdline icmpv6" ;;
+                       iptables:--icmpv6-type) cmdline="$cmdline --icmp-type" ;;
+                       iptables:icmpv6) cmdline="$cmdline icmp" ;;
+                       *) cmdline="$cmdline $1" ;;
                esac
-               echo -ne "\0"
                shift
-       done | xargs -0 ${FW_TRACE:+-t} \
-               $app --table ${tab} --${cmd} ${chn} ${pol} ${pos} ${tgt:+--jump "$tgt"}
+       done
+
+       [ -n "$FW_TRACE" ] && echo $cmdline >&2
+
+       $cmdline
+
        fw__rc $?
 }
 
 fw_get_port_range() {
-       local ports=$1
-       local delim=${2:-:}
-       if [ "$3" ]; then
-               fw_get_port_range "${ports}-${3}" $delim
+       local _var=$1
+       local _ports=$2
+       local _delim=${3:-:}
+       if [ "$4" ]; then
+               fw_get_port_range $_var "${_ports}-${4}" $_delim
                return
        fi
 
-       local first=${ports%-*}
-       local last=${ports#*-}
-       if [ "$first" != "$last" ]; then
-               echo "$first$delim$last"
+       local _first=${_ports%-*}
+       local _last=${_ports#*-}
+       if [ "$_first" != "$_last" ]; then
+               export -- "$_var=$_first$_delim$_last"
        else
-               echo "$first"
+               export -- "$_var=$_first"
        fi
 }
 
 fw_get_family_mode() {
-       local hint="$1"
-       local zone="$2"
-       local mode="$3"
+       local _var="$1"
+       local _hint="$2"
+       local _zone="$3"
+       local _mode="$4"
 
-       local ipv4 ipv6
+       local _ipv4 _ipv6
        [ -n "$FW_ZONES4$FW_ZONES6" ] && {
-               list_contains FW_ZONES4 $zone && ipv4=1 || ipv4=0
-               list_contains FW_ZONES6 $zone && ipv6=1 || ipv6=0
+               list_contains FW_ZONES4 $_zone && _ipv4=1 || _ipv4=0
+               list_contains FW_ZONES6 $_zone && _ipv6=1 || _ipv6=0
        } || {
-               ipv4=$(uci_get_state firewall core ${zone}_ipv4 0)
-               ipv6=$(uci_get_state firewall core ${zone}_ipv6 0)
+               _ipv4=$(uci_get_state firewall core ${_zone}_ipv4 0)
+               _ipv6=$(uci_get_state firewall core ${_zone}_ipv6 0)
        }
 
-       case "$hint:$ipv4:$ipv6" in
-               *4:1:*|*:1:0) echo G4 ;;
-               *6:*:1|*:0:1) echo G6 ;;
-               *) echo $mode ;;
+       case "$_hint:$_ipv4:$_ipv6" in
+               *4:1:*|*:1:0) export -n -- "$_var=G4" ;;
+               *6:*:1|*:0:1) export -n -- "$_var=G6" ;;
+               *) export -n -- "$_var=$_mode" ;;
        esac
 }