From 4993294b6c6dbf6a703975f1b85c98ddfa7bd134 Mon Sep 17 00:00:00 2001 From: jow Date: Sat, 30 Jul 2011 00:53:09 +0000 Subject: [PATCH] [backfire] firewall: sync with trunk git-svn-id: svn://svn.openwrt.org/openwrt/branches/backfire@27837 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- package/firewall/Makefile | 2 +- package/firewall/files/firewall.config | 50 ++++++--- package/firewall/files/lib/core_interface.sh | 41 ++++--- package/firewall/files/lib/core_redirect.sh | 59 +++++----- package/firewall/files/lib/core_rule.sh | 77 +++++++++---- package/firewall/files/lib/fw.sh | 111 ++++++++++++++++--- package/firewall/files/reflection.hotplug | 21 +++- 7 files changed, 261 insertions(+), 100 deletions(-) diff --git a/package/firewall/Makefile b/package/firewall/Makefile index 2f732e610..6f38ee48b 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:=26 +PKG_RELEASE:=33 include $(INCLUDE_DIR)/package.mk diff --git a/package/firewall/files/firewall.config b/package/firewall/files/firewall.config index f842a970e..428c5a211 100644 --- a/package/firewall/files/firewall.config +++ b/package/firewall/files/firewall.config @@ -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 diff --git a/package/firewall/files/lib/core_interface.sh b/package/firewall/files/lib/core_interface.sh index bc9eb96dd..84e07e0e2 100644 --- a/package/firewall/files/lib/core_interface.sh +++ b/package/firewall/files/lib/core_interface.sh @@ -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() { diff --git a/package/firewall/files/lib/core_redirect.sh b/package/firewall/files/lib/core_redirect.sh index 87941a2a1..a3e70d40d 100644 --- a/package/firewall/files/lib/core_redirect.sh +++ b/package/firewall/files/lib/core_redirect.sh @@ -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 diff --git a/package/firewall/files/lib/core_rule.sh b/package/firewall/files/lib/core_rule.sh index 8c234a33a..de8cd8ea3 100644 --- a/package/firewall/files/lib/core_rule.sh +++ b/package/firewall/files/lib/core_rule.sh @@ -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 diff --git a/package/firewall/files/lib/fw.sh b/package/firewall/files/lib/fw.sh index 896947241..a13eb7eb1 100644 --- a/package/firewall/files/lib/fw.sh +++ b/package/firewall/files/lib/fw.sh @@ -137,10 +137,13 @@ fw__exec() { # { } 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() { #
{ } 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() { #
{ } $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 +} diff --git a/package/firewall/files/reflection.hotplug b/package/firewall/files/reflection.hotplug index 33d121cec..15e350082 100644 --- a/package/firewall/files/reflection.hotplug +++ b/package/firewall/files/reflection.hotplug @@ -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 -- 2.35.1