[backfire] firewall: sync with trunk
authorjow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sat, 30 Jul 2011 00:53:09 +0000 (00:53 +0000)
committerjow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sat, 30 Jul 2011 00:53:09 +0000 (00:53 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/branches/backfire@27837 3c298f89-4303-0410-b956-a3cf2f4a3e73

package/firewall/Makefile
package/firewall/files/firewall.config
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
package/firewall/files/reflection.hotplug

index 2f732e610bb22c789478d76bfe219e31b03df840..6f38ee48b0396f922e5a78f928616c0f9b96d69c 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 PKG_NAME:=firewall
 
 PKG_VERSION:=2
-PKG_RELEASE:=26
+PKG_RELEASE:=33
 
 include $(INCLUDE_DIR)/package.mk
 
index f842a970e0aae97aa61d7d3f509b28762d7a1b05..428c5a211c24870709a4c6ba14322f93ef724990 100644 (file)
@@ -8,23 +8,23 @@ config defaults
 
 config zone
        option name             lan
-       option network  'lan'
-       option input    ACCEPT 
-       option output   ACCEPT 
-       option forward  REJECT
+       option network          'lan'
+       option input            ACCEPT 
+       option output           ACCEPT 
+       option forward          REJECT
 
 config zone
        option name             wan
-       option network  'wan'
-       option input    REJECT
-       option output   ACCEPT 
-       option forward  REJECT
+       option network          'wan'
+       option input            REJECT
+       option output           ACCEPT 
+       option forward          REJECT
        option masq             1 
-       option mtu_fix  1
+       option mtu_fix          1
 
 config forwarding 
-       option src      lan
-       option dest     wan
+       option src              lan
+       option dest             wan
 
 # We need to accept udp packets on port 68,
 # see https://dev.openwrt.org/ticket/4108
@@ -33,14 +33,30 @@ config rule
        option proto            udp
        option dest_port        68
        option target           ACCEPT
-       option family   ipv4
+       option family           ipv4
 
-#Allow ping
+# Allow IPv4 ping
 config rule
-       option src wan
-       option proto icmp
-       option icmp_type echo-request
-       option target ACCEPT
+       option src              wan
+       option proto            icmp
+       option icmp_type        echo-request
+       option family           ipv4
+       option target           ACCEPT
+
+# Allow essential incoming IPv6 ICMP traffic
+config rule                                   
+       option src              wan
+       option dest             *
+       option proto            icmp
+       list icmp_type          echo-request
+       list icmp_type          destination-unreachable
+       list icmp_type          packet-too-big
+       list icmp_type          time-exceeded
+       list icmp_type          bad-header
+       list icmp_type          unknown-header-type
+       option limit            1000/sec
+       option family           ipv6
+       option target           ACCEPT
 
 # include a file with users custom iptables rules
 config include
index bc9eb96ddedc2faa349ccc40d72fa63203229a00..84e07e0e25d69d7a07c0107374e9b9fa46b95c8b 100644 (file)
@@ -1,27 +1,34 @@
-# Copyright (C) 2009-2010 OpenWrt.org
+# Copyright (C) 2009-2011 OpenWrt.org
 
 fw__uci_state_add() {
        local var="$1"
        local item="$2"
 
-       local val=" $(uci_get_state firewall core $var) "
-       val="${val// $item / }"
-       val="${val# }"
-       val="${val% }"
-       uci_revert_state firewall core $var
-       uci_set_state firewall core $var "${val:+$val }$item"
+       local val="$(uci_get_state firewall core $var)"
+       local e1; for e1 in $item; do
+               local e2; for e2 in $val; do
+                       [ "$e1" = "$e2" ] && e1=""
+               done
+               val="${val:+$val${e1:+ }}$e1"
+       done
+
+       uci_toggle_state firewall core $var "$val"
 }
 
 fw__uci_state_del() {
        local var="$1"
        local item="$2"
 
-       local val=" $(uci_get_state firewall core $var) "
-       val="${val// $item / }"
-       val="${val# }"
-       val="${val% }"
-       uci_revert_state firewall core $var
-       uci_set_state firewall core $var "$val"
+       local rest=""
+       local val="$(uci_get_state firewall core $var)"
+       local e1; for e1 in $val; do
+               local e2; for e2 in $item; do
+                       [ "$e1" = "$e2" ] && e1=""
+               done
+               rest="${rest:+$rest${e1:+ }}$e1"
+       done
+
+       uci_toggle_state firewall core $var "$val"
 }
 
 fw_configure_interface() {
@@ -154,14 +161,14 @@ fw_configure_interface() {
                fw_sysctl_interface $ifname
                fw_callback post interface
 
-               uci_set_state firewall core "${iface}_aliases" "$aliases"
+               uci_toggle_state firewall core "${iface}_aliases" "$aliases"
        } || {
                local subnets=
                config_get subnets core "${iface}_subnets"
                append subnets "$aliasnet"
 
                config_set core "${iface}_subnets" "$subnets"
-               uci_set_state firewall core "${iface}_subnets" "$subnets"
+               uci_toggle_state firewall core "${iface}_subnets" "$subnets"
        }
 
        local new_zones=
@@ -180,8 +187,8 @@ fw_configure_interface() {
        }
        config_foreach load_zone zone
 
-       uci_set_state firewall core "${iface}_zone" "$new_zones"
-       uci_set_state firewall core "${iface}_ifname" "$ifname"
+       uci_toggle_state firewall core "${iface}_zone" "$new_zones"
+       uci_toggle_state firewall core "${iface}_ifname" "$ifname"
 }
 
 fw_sysctl_interface() {
index 87941a2a174d3425a5acb49eb076657ce90da6d5..a3e70d40d74fd6b051c51a9375f600240dbf75a8 100644 (file)
@@ -13,11 +13,11 @@ fw_config_get_redirect() {
                string src_dport "" \
                string dest "" \
                ipaddr dest_ip "" \
-               string dest_mac "" \
                string dest_port "" \
                string proto "tcpudp" \
                string family "" \
                string target "DNAT" \
+               string extra "" \
        } || return
        [ -n "$redirect_name" ] || redirect_name=$redirect__name
 }
@@ -29,26 +29,27 @@ fw_load_redirect() {
 
        local fwdchain natchain natopt nataddr natports srcdaddr srcdports
        if [ "$redirect_target" == "DNAT" ]; then
-               [ -n "$redirect_src" -a -n "$redirect_dest_ip$redirect_dest_port" ] || {
+               [ -n "${redirect_src#*}" -a -n "$redirect_dest_ip$redirect_dest_port" ] || {
                        fw_log error "DNAT redirect ${redirect_name}: needs src and dest_ip or dest_port, skipping"
                        return 0
                }
 
-               fwdchain="zone_${redirect_src}_forward"
+               fwdchain="zone_${redirect_src}${redirect_dest_ip:+_forward}"
 
                natopt="--to-destination"
                natchain="zone_${redirect_src}_prerouting"
                nataddr="$redirect_dest_ip"
-               fw_get_port_range natports "$redirect_dest_port" "-"
+               fw_get_port_range natports "${redirect_dest_port#!}" "-"
 
                fw_get_negation srcdaddr '-d' "${redirect_src_dip:+$redirect_src_dip/$redirect_src_dip_prefixlen}"
                fw_get_port_range srcdports "$redirect_src_dport" ":"
+               fw_get_negation srcdports '--dport' "$srcdports"
 
                list_contains FW_CONNTRACK_ZONES $redirect_src || \
                        append FW_CONNTRACK_ZONES $redirect_src
 
        elif [ "$redirect_target" == "SNAT" ]; then
-               [ -n "$redirect_dest" -a -n "$redirect_src_dip" ] || {
+               [ -n "${redirect_dest#*}" -a -n "$redirect_src_dip" ] || {
                        fw_log error "SNAT redirect ${redirect_name}: needs dest and src_dip, skipping"
                        return 0
                }
@@ -58,10 +59,11 @@ fw_load_redirect() {
                natopt="--to-source"
                natchain="zone_${redirect_dest}_nat"
                nataddr="$redirect_src_dip"
-               fw_get_port_range natports "$redirect_src_dport" "-"
+               fw_get_port_range natports "${redirect_src_dport#!}" "-"
 
                fw_get_negation srcdaddr '-d' "${redirect_dest_ip:+$redirect_dest_ip/$redirect_dest_ip_prefixlen}"
                fw_get_port_range srcdports "$redirect_dest_port" ":"
+               fw_get_negation srcdports '--dport' "$srcdports"
 
                list_contains FW_CONNTRACK_ZONES $redirect_dest || \
                        append FW_CONNTRACK_ZONES $redirect_dest
@@ -79,35 +81,38 @@ fw_load_redirect() {
 
        local srcports
        fw_get_port_range srcports "$redirect_src_port" ":"
+       fw_get_negation srcports '--sport' "$srcports"
 
        local destaddr
        fw_get_negation destaddr '-d' "${redirect_dest_ip:+$redirect_dest_ip/$redirect_dest_ip_prefixlen}"
 
        local destports
        fw_get_port_range destports "${redirect_dest_port:-$redirect_src_dport}" ":"
+       fw_get_negation destports '--dport' "$destports"
 
        [ "$redirect_proto" == "tcpudp" ] && redirect_proto="tcp udp"
-       for redirect_proto in $redirect_proto; do
-               local pos
-               eval 'pos=$((++FW__REDIR_COUNT_'${mode#G}'_'$natchain'))'
-
-               fw add $mode n $natchain $redirect_target $pos { $redirect_src_ip $redirect_dest_ip } { \
-                       $srcaddr $srcdaddr \
-                       ${redirect_proto:+-p $redirect_proto} \
-                       ${srcports:+--sport $srcports} \
-                       ${srcdports:+--dport $srcdports} \
-                       ${redirect_src_mac:+-m mac --mac-source $redirect_src_mac} \
-                       $natopt $nataddr${natports:+:$natports} \
-               }
-
-               [ -n "$destaddr" ] && \
-               fw add $mode f ${fwdchain:-forward} ACCEPT ^ { $redirect_src_ip $redirect_dest_ip } { \
-                       $srcaddr $destaddr \
-                       ${redirect_proto:+-p $redirect_proto} \
-                       ${srcports:+--sport $srcports} \
-                       ${destports:+--dport $destports} \
-                       ${redirect_src_mac:+-m mac --mac-source $redirect_src_mac} \
-               }
+       local pr; for pr in $redirect_proto; do
+               fw_get_negation pr '-p' "$pr"
+               local sm; for sm in ${redirect_src_mac:-""}; do
+                       fw_get_negation sm '--mac-source' "$sm"
+                       fw add $mode n $natchain $redirect_target + \
+                               { $redirect_src_ip $redirect_dest_ip } { \
+                               $srcaddr $srcdaddr $pr \
+                               $srcports $srcdports \
+                               ${sm:+-m mac $sm} \
+                               $natopt $nataddr${natports:+:$natports} \
+                               $redirect_options \
+                       }
+
+                       fw add $mode f ${fwdchain:-forward} ACCEPT + \
+                               { $redirect_src_ip $redirect_dest_ip } { \
+                               $srcaddr ${destaddr:--m conntrack --ctstate DNAT} \
+                               $pr \
+                               $srcports $destports \
+                               ${sm:+-m mac $sm} \
+                               $redirect_extra \
+                       }
+               done
        done
 
        fw_callback post redirect
index 8c234a33a13e9e6a9984521be34516492674a314..de8cd8ea359b39eef25f6f0e5b6ea53c55814ef0 100644 (file)
@@ -16,24 +16,23 @@ fw_config_get_rule() {
                string proto "tcpudp" \
                string target "" \
                string family "" \
+               string limit "" \
+               string limit_burst "" \
+               string extra "" \
        } || return
        [ -n "$rule_name" ] || rule_name=$rule__name
-       [ "$rule_proto" == "icmp" ] || rule_icmp_type=
 }
 
 fw_load_rule() {
        fw_config_get_rule "$1"
 
-       [ "$rule_target" != "NOTRACK" ] || [ -n "$rule_src" ] || {
+       [ "$rule_target" != "NOTRACK" ] || [ -n "$rule_src" ] || [ "$rule_src" != "*" ] || {
                fw_log error "NOTRACK rule ${rule_name}: needs src, skipping"
                return 0
        }
 
        fw_callback pre rule
 
-       fw_get_port_range rule_src_port $rule_src_port
-       fw_get_port_range rule_dest_port $rule_dest_port
-
        local table=f
        local chain=input
        local target="${rule_target:-REJECT}"
@@ -41,8 +40,22 @@ fw_load_rule() {
                table=r
                chain="zone_${rule_src}_notrack"
        else
-               [ -n "$rule_src" ] && chain="zone_${rule_src}${rule_dest:+_forward}"
-               [ -n "$rule_dest" ] && target="zone_${rule_dest}_${target}"
+               if [ -n "$rule_src" ]; then
+                       if [ "$rule_src" != "*" ]; then
+                               chain="zone_${rule_src}${rule_dest:+_forward}"
+                       else
+                               chain="${rule_dest:+forward}"
+                               chain="${chain:-input}"
+                       fi
+               fi
+
+               if [ -n "$rule_dest" ]; then
+                       if [ "$rule_dest" != "*" ]; then
+                               target="zone_${rule_dest}_${target}"
+                       elif [ "$target" = REJECT ]; then
+                               target=reject
+                       fi
+               fi
        fi
 
        local mode
@@ -53,18 +66,44 @@ fw_load_rule() {
        fw_get_negation dest_spec '-d' "${rule_dest_ip:+$rule_dest_ip/$rule_dest_ip_prefixlen}"
 
        [ "$rule_proto" == "tcpudp" ] && rule_proto="tcp udp"
-       for rule_proto in $rule_proto; do
-               local rule_pos
-               eval 'rule_pos=$((++FW__RULE_COUNT_'${mode#G}'_'$chain'))'
-
-               fw add $mode $table $chain $target $rule_pos { $rule_src_ip $rule_dest_ip } { \
-                       $src_spec $dest_spec \
-                       ${rule_proto:+-p $rule_proto} \
-                       ${rule_src_port:+--sport $rule_src_port} \
-                       ${rule_src_mac:+-m mac --mac-source $rule_src_mac} \
-                       ${rule_dest_port:+--dport $rule_dest_port} \
-                       ${rule_icmp_type:+--icmp-type $rule_icmp_type} \
-               }
+       local pr; for pr in $rule_proto; do
+               local sports dports itypes
+               case "$pr" in
+                       icmp|icmpv6|1|58)
+                               sports=""; dports=""
+                               itypes="$rule_icmp_type"
+                       ;;
+                       *)
+                               sports="$rule_src_port"
+                               dports="$rule_dest_port"
+                               itypes=""
+                       ;;
+               esac
+       
+               fw_get_negation pr '-p' "$pr"
+               local sp; for sp in ${sports:-""}; do
+                       fw_get_port_range sp $sp
+                       fw_get_negation sp '--sport' "$sp"
+                       local dp; for dp in ${dports:-""}; do
+                               fw_get_port_range dp $dp
+                               fw_get_negation dp '--dport' "$dp"
+                               local sm; for sm in ${rule_src_mac:-""}; do
+                                       fw_get_negation sm '--mac-source' "$sm"
+                                       local it; for it in ${itypes:-""}; do
+                                               fw_get_negation it '--icmp-type' "$it"
+                                               fw add $mode $table $chain $target + \
+                                                       { $rule_src_ip $rule_dest_ip } { \
+                                                       $src_spec $dest_spec \
+                                                       $pr $sp $dp $it \
+                                                       ${sm:+-m mac $sm} \
+                                                       ${rule_limit:+-m limit --limit $rule_limit \
+                                                               ${rule_limit_burst:+--limit-burst $rule_limit_burst}} \
+                                                       $rule_extra \
+                                               }
+                                       done
+                               done
+                       done
+               done
        done
 
        fw_callback post rule
index 896947241a525bdf8d383dd41ce3f34610ef2c6b..a13eb7eb13ff782faadf07ae5f97701dc135a255 100644 (file)
@@ -137,10 +137,13 @@ fw__exec() { # <action> <family> <table> <chain> <target> <position> { <rules> }
        case "$tgt" in
                -) tgt= ;;
        esac
+
+       local rule_offset
        case "$pos" in
                ^) pos=1 ;;
                $) pos= ;;
                -) pos= ;;
+               +) eval "rule_offset=\${FW__RULE_OFS_${app}_${tab}_${chn}:-1}" ;;
        esac
 
        if ! fw__has - family || ! fw__has $tab ; then
@@ -159,13 +162,29 @@ fw__exec() { # <action> <family> <table> <chain> <target> <position> { <rules> }
                fi
        fi
 
-       local cmdline="$app --table ${tab} --${cmd} ${chn} ${pol} ${pos} ${tgt:+--jump "$tgt"}"
+       local cmdline="$app --table ${tab} --${cmd} ${chn} ${pol} ${rule_offset:-${pos}} ${tgt:+--jump "$tgt"}"
        while [ $# -gt 1 ]; do
-               case "$app:$1" in
-                       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" ;;
+               # special parameter handling
+               case "$1:$2" in
+                       -p:icmp*|-p:1|-p:58|--protocol:icmp*|--protocol:1|--protocol:58)
+                               [ "$app" = ip6tables ] && \
+                                       cmdline="$cmdline -p icmpv6" || \
+                                       cmdline="$cmdline -p icmp"
+                               shift
+                       ;;
+                       --icmp-type:*|--icmpv6-type:*)
+                               local icmp_type
+                               if [ "$app" = ip6tables ] && fw_check_icmptype6 icmp_type "$2"; then
+                                       cmdline="$cmdline $icmp_type"
+                               elif [ "$app" = iptables ] && fw_check_icmptype4 icmp_type "$2"; then
+                                       cmdline="$cmdline $icmp_type"
+                               else
+                                       local fam=IPv4; [ "$app" = ip6tables ] && fam=IPv6
+                                       fw_log info "ICMP type '$2' is not valid for $fam address family, skipping rule"
+                                       return 1
+                               fi
+                               shift   
+                       ;;
                        *) cmdline="$cmdline $1" ;;
                esac
                shift
@@ -175,7 +194,10 @@ fw__exec() { # <action> <family> <table> <chain> <target> <position> { <rules> }
 
        $cmdline
 
-       fw__rc $?
+       local rv=$?
+       [ $rv -eq 0 ] && [ -n "$rule_offset" ] && \
+               export -- "FW__RULE_OFS_${app}_${tab}_${chn}=$(($rule_offset + 1))"
+       fw__rc $rv
 }
 
 fw_get_port_range() {
@@ -189,8 +211,8 @@ fw_get_port_range() {
 
        local _first=${_ports%-*}
        local _last=${_ports#*-}
-       if [ "$_first" != "$_last" ]; then
-               export -- "$_var=$_first$_delim$_last"
+       if [ "${_first#!}" != "${_last#!}" ]; then
+               export -- "$_var=$_first$_delim${_last#!}"
        else
                export -- "$_var=$_first"
        fi
@@ -221,11 +243,11 @@ fw_get_family_mode() {
 fw_get_negation() {
        local _var="$1"
        local _flag="$2"
-       local _ipaddr="$3"
+       local _value="$3"
 
-       [ "${_ipaddr#!}" != "$_ipaddr" ] && \
-               export -n -- "$_var=! $_flag ${_ipaddr#!}" || \
-               export -n -- "$_var=${_ipaddr:+$_flag $_ipaddr}"
+       [ "${_value#!}" != "$_value" ] && \
+               export -n -- "$_var=! $_flag ${_value#!}" || \
+               export -n -- "$_var=${_value:+$_flag $_value}"
 }
 
 fw_get_subnet4() {
@@ -245,3 +267,66 @@ fw_get_subnet4() {
                *) export -n -- "$_var=" ;;
        esac
 }
+
+fw_check_icmptype4() {
+       local _var="$1"
+       local _type="$2"
+       case "$_type" in
+               ![0-9]*) export -n -- "$_var=! --icmp-type ${_type#!}"; return 0 ;;
+               [0-9]*)  export -n -- "$_var=--icmp-type $_type";       return 0 ;;
+       esac
+
+       [ -z "$FW_ICMP4_TYPES" ] && \
+               export FW_ICMP4_TYPES=$(
+                       iptables -p icmp -h 2>/dev/null | \
+                       sed -n -e '/^Valid ICMP Types:/ {
+                               n; :r;
+                               /router-advertisement/d;
+                               /router-solicitation/d;
+                               s/[()]/ /g; s/[[:space:]]\+/\n/g; p; n; b r
+                       }' | sort -u
+               )
+
+       local _check
+       for _check in $FW_ICMP4_TYPES; do
+               if [ "$_check" = "${_type#!}" ]; then
+                       [ "${_type#!}" != "$_type" ] && \
+                               export -n -- "$_var=! --icmp-type ${_type#!}" || \
+                               export -n -- "$_var=--icmp-type $_type"
+                       return 0
+               fi
+       done
+
+       export -n -- "$_var="
+       return 1
+}
+
+fw_check_icmptype6() {
+       local _var="$1"
+       local _type="$2"
+       case "$_type" in
+               ![0-9]*) export -n -- "$_var=! --icmpv6-type ${_type#!}"; return 0 ;;
+               [0-9]*)  export -n -- "$_var=--icmpv6-type $_type";       return 0 ;;
+       esac
+
+       [ -z "$FW_ICMP6_TYPES" ] && \
+               export FW_ICMP6_TYPES=$(
+                       ip6tables -p icmpv6 -h 2>/dev/null | \
+                       sed -n -e '/^Valid ICMPv6 Types:/ {
+                               n; :r; s/[()]/ /g; s/[[:space:]]\+/\n/g; p; n; b r
+                       }' | sort -u
+               )
+
+       local _check
+       for _check in $FW_ICMP6_TYPES; do
+               if [ "$_check" = "${_type#!}" ]; then
+                       [ "${_type#!}" != "$_type" ] && \
+                               export -n -- "$_var=! --icmpv6-type ${_type#!}" || \
+                               export -n -- "$_var=--icmpv6-type $_type"
+                       return 0
+               fi
+       done
+
+       export -n -- "$_var="
+       return 1
+}
index 33d121cec41e8b6fc8284b6d980e279d53257cb3..15e350082a1230084565d2d8bbc3e9b0b09d556b 100644 (file)
@@ -56,6 +56,7 @@ if [ "$ACTION" = "add" ] && [ "$INTERFACE" = "wan" ]; then
                [ "$src" = wan ] && [ "$target" = DNAT ] && {
                        local dest
                        config_get dest "$cfg" dest "lan"
+                       [ "$dest" != "*" ] || return
 
                        local net
                        for net in $(find_networks "$dest"); do
@@ -70,13 +71,13 @@ if [ "$ACTION" = "add" ] && [ "$INTERFACE" = "wan" ]; then
                                [ -n "$extport" ] || return
 
                                epmin="${extport%[-:]*}"; epmax="${extport#*[-:]}"
-                               [ "$epmin" != "$epmax" ] || epmax=""
+                               [ "${epmin#!}" != "$epmax" ] || epmax=""
 
                                local ipmin ipmax intport
                                config_get intport "$cfg" dest_port "$extport"
 
                                ipmin="${intport%[-:]*}"; ipmax="${intport#*[-:]}"
-                               [ "$ipmin" != "$ipmax" ] || ipmax=""
+                               [ "${ipmin#!}" != "$ipmax" ] || ipmax=""
 
                                local exthost
                                config_get exthost "$cfg" src_dip "$wanip"
@@ -90,23 +91,31 @@ if [ "$ACTION" = "add" ] && [ "$INTERFACE" = "wan" ]; then
                                [ "${inthost#!}" = "$inthost" ] || return 0
                                [ "${exthost#!}" = "$exthost" ] || return 0
 
+                               [ "${epmin#!}" != "$epmin" ] && \
+                                       extport="! --dport ${epmin#!}${epmax:+:$epmax}" || \
+                                       extport="--dport $epmin${epmax:+:$epmax}"
+
+                               [ "${ipmin#!}" != "$ipmin" ] && \
+                                       intport="! --dport ${ipmin#!}${ipmax:+:$ipmax}" || \
+                                       intport="--dport $ipmin${ipmax:+:$ipmax}"
+
                                local p
                                for p in ${proto:-tcp udp}; do
                                        case "$p" in
                                                tcp|udp)
                                                        iptables -t nat -A nat_reflection_in \
                                                                -s $lanip/$lanmk -d $exthost \
-                                                               -p $p --dport $epmin${epmax:+:$epmax} \
-                                                               -j DNAT --to $inthost:$ipmin${ipmax:+-$ipmax}
+                                                               -p $p $extport \
+                                                               -j DNAT --to $inthost:${ipmin#!}${ipmax:+-$ipmax}
 
                                                        iptables -t nat -A nat_reflection_out \
                                                                -s $lanip/$lanmk -d $inthost \
-                                                               -p $p --dport $ipmin${ipmax:+:$ipmax} \
+                                                               -p $p $intport \
                                                                -j SNAT --to-source $lanip
 
                                                        iptables -t filter -A nat_reflection_fwd \
                                                                -s $lanip/$lanmk -d $inthost \
-                                                               -p $p --dport $ipmin${ipmax:+:$ipmax} \
+                                                               -p $p $intport \
                                                                -j ACCEPT
                                                ;;
                                        esac