From f3dd8278bbc3cc62c35239a2721144e220b24004 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 11 Sep 2010 20:04:34 +0000 Subject: [PATCH] firewall: - 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 | 2 +- package/firewall/files/lib/core_forwarding.sh | 3 +- package/firewall/files/lib/core_init.sh | 15 +++- package/firewall/files/lib/core_interface.sh | 33 ++------ package/firewall/files/lib/core_redirect.sh | 84 ++++++++++++------- package/firewall/files/lib/core_rule.sh | 7 +- package/firewall/files/lib/fw.sh | 64 +++++++------- 7 files changed, 114 insertions(+), 94 deletions(-) diff --git a/package/firewall/Makefile b/package/firewall/Makefile index b6d42cebad..00badcb85e 100644 --- a/package/firewall/Makefile +++ b/package/firewall/Makefile @@ -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 diff --git a/package/firewall/files/lib/core_forwarding.sh b/package/firewall/files/lib/core_forwarding.sh index b62e18a76e..c4a968143d 100644 --- a/package/firewall/files/lib/core_forwarding.sh +++ b/package/firewall/files/lib/core_forwarding.sh @@ -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 ^ diff --git a/package/firewall/files/lib/core_init.sh b/package/firewall/files/lib/core_init.sh index bce94afe02..e1f80ba3fc 100644 --- a/package/firewall/files/lib/core_init.sh +++ b/package/firewall/files/lib/core_init.sh @@ -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 } diff --git a/package/firewall/files/lib/core_interface.sh b/package/firewall/files/lib/core_interface.sh index c2a5bd7f33..889dcc9047 100644 --- a/package/firewall/files/lib/core_interface.sh +++ b/package/firewall/files/lib/core_interface.sh @@ -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() { diff --git a/package/firewall/files/lib/core_redirect.sh b/package/firewall/files/lib/core_redirect.sh index 2f0e38f393..72364a99e9 100644 --- a/package/firewall/files/lib/core_redirect.sh +++ b/package/firewall/files/lib/core_redirect.sh @@ -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 diff --git a/package/firewall/files/lib/core_rule.sh b/package/firewall/files/lib/core_rule.sh index e1f8d2ae15..1e4afe5aff 100644 --- a/package/firewall/files/lib/core_rule.sh +++ b/package/firewall/files/lib/core_rule.sh @@ -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'))' diff --git a/package/firewall/files/lib/fw.sh b/package/firewall/files/lib/fw.sh index aaf3d14ef0..3549f8aa4c 100644 --- a/package/firewall/files/lib/fw.sh +++ b/package/firewall/files/lib/fw.sh @@ -159,56 +159,62 @@ fw__exec() { # { } 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 } -- 2.25.1