summaryrefslogtreecommitdiffstats
path: root/package/firewall/files/lib
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2010-05-01 18:22:01 +0000
committerJo-Philipp Wich <jow@openwrt.org>2010-05-01 18:22:01 +0000
commitc284cb51c00625f52090f3fe3d475450eaab7b21 (patch)
tree02c49883956e50f28055df479accfa35c3c6fcdd /package/firewall/files/lib
parent085b2b9ad6216508ff357dcb49757173d269fbb9 (diff)
downloadmaster-31e0f0ae-c284cb51c00625f52090f3fe3d475450eaab7b21.tar.gz
master-31e0f0ae-c284cb51c00625f52090f3fe3d475450eaab7b21.tar.bz2
master-31e0f0ae-c284cb51c00625f52090f3fe3d475450eaab7b21.zip
firewall: - replace uci firewall with a modular dual stack implementation developed by Malte S. Stretz - bump version to 2
SVN-Revision: 21286
Diffstat (limited to 'package/firewall/files/lib')
-rw-r--r--package/firewall/files/lib/config.sh97
-rw-r--r--package/firewall/files/lib/core.sh136
-rw-r--r--package/firewall/files/lib/core_forwarding.sh40
-rw-r--r--package/firewall/files/lib/core_init.sh258
-rw-r--r--package/firewall/files/lib/core_interface.sh86
-rw-r--r--package/firewall/files/lib/core_redirect.sh61
-rw-r--r--package/firewall/files/lib/core_rule.sh66
-rw-r--r--package/firewall/files/lib/fw.sh182
-rw-r--r--package/firewall/files/lib/uci_firewall.sh5
9 files changed, 931 insertions, 0 deletions
diff --git a/package/firewall/files/lib/config.sh b/package/firewall/files/lib/config.sh
new file mode 100644
index 0000000000..1c5e030961
--- /dev/null
+++ b/package/firewall/files/lib/config.sh
@@ -0,0 +1,97 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+# Copyright (C) 2009 Malte S. Stretz <http://msquadrat.de>
+#
+# This is a temporary file, I hope to have some of this stuff merged into
+# /lib/functions.sh (without the fw_ prefix of course) one day.
+
+fw_config_append() { # <package>
+ CONFIG_APPEND=1 config_load "$@"
+ unset CONFIG_APPEND
+}
+
+fw_config_once() { # <function> <type>
+ local func=$1
+ local type=$2
+ shift 2
+
+ local config=cfg00nil
+ fw_config__once() {
+ config=$1
+ }
+ config_foreach fw_config__once "$type"
+
+ $func $config "$@"
+}
+
+fw_config_get_section() { # <config> <prefix> <type> <name> <default> ...
+ local config=$1
+ local prefix=$2
+ shift 2
+
+ [ -n "$config" ] || return 1
+ [ -n "$prefix" ] && {
+ prefix="${prefix}_"
+ export ${NO_EXPORT:+-n} -- "${prefix}NAME"="${config}"
+ config_get "${prefix}TYPE" "$config" TYPE
+ }
+
+ [ "$1" == '{' ] && shift
+ while [ $# -ge 3 ]; do
+ local type=$1
+ local name=$2
+ local dflt=$3
+ shift 3
+ # TODO: Move handling of defaults to /lib/functions.sh
+ # and get replace the case block with the following
+ # two lines:
+ # type=${type#string}
+ # config_get${type:+_${type}} "${prefix}${name}" "$config" "$name" "$dflt" || return
+ case "$type" in
+ string)
+ local tmp
+ config_get tmp "$config" "$name" || return
+ [ -z "$tmp" ] && tmp=$dflt
+ export ${NO_EXPORT:+-n} -- "${prefix}${name}=${tmp}"
+ continue
+ ;;
+ boolean)
+ type=bool
+ ;;
+ esac;
+
+ local cmd=${prefix}config_get_${type}
+ type $cmd > /dev/null || {
+ cmd=config_get_${type}
+ }
+ type $cmd > /dev/null || {
+ echo "config type $type (for $name) not supported" >&2
+ return 1
+ }
+ $cmd "${prefix}${name}" "$config" "$name" "$dflt" || return
+ done
+}
+
+config_get_ipaddr() {
+ local varn=$1
+ local conf=$2
+ local name=$3
+ local dflt=$4
+
+ local addr
+ config_get addr "$conf" "$name" || return
+ [ -n "$addr" ] || addr=$dflt
+
+ local mask=${addr#*/}
+ [ "$mask" != "$addr" ] || mask=
+ addr=${addr%/*}
+
+ local vers=
+ case "$addr" in
+ *.*) vers=4 ;;
+ *:*) vers=6 ;;
+ esac
+
+ export ${NO_EXPORT:+-n} -- "${varn}=${addr}"
+ export ${NO_EXPORT:+-n} -- "${varn}_prefixlen=${mask}"
+ export ${NO_EXPORT:+-n} -- "${varn}_version=${vers}"
+}
diff --git a/package/firewall/files/lib/core.sh b/package/firewall/files/lib/core.sh
new file mode 100644
index 0000000000..3fd98d1602
--- /dev/null
+++ b/package/firewall/files/lib/core.sh
@@ -0,0 +1,136 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+
+FW_LIBDIR=${FW_LIBDIR:-/lib/firewall}
+
+. $FW_LIBDIR/fw.sh
+include /lib/network
+
+fw_start() {
+ fw_init
+
+ FW_DEFAULTS_APPLIED=
+
+ fw_is_loaded && {
+ echo "firewall already loaded" >&2
+ exit 1
+ }
+ uci_set_state firewall core "" firewall_state
+
+ fw_clear DROP
+
+ fw_callback pre core
+
+ echo "Loading defaults"
+ fw_config_once fw_load_defaults defaults
+
+ echo "Loading zones"
+ config_foreach fw_load_zone zone
+
+ echo "Loading forwardings"
+ config_foreach fw_load_forwarding forwarding
+
+ echo "Loading redirects"
+ config_foreach fw_load_redirect redirect
+
+ echo "Loading rules"
+ config_foreach fw_load_rule rule
+
+ echo "Loading includes"
+ config_foreach fw_load_include include
+
+ [ -n "$FW_NOTRACK_DISABLED" ] && {
+ echo "Optimizing conntrack"
+ config_foreach fw_load_notrack_zone zone
+ }
+
+ echo "Loading interfaces"
+ config_foreach fw_configure_interface interface add
+
+ fw_callback post core
+
+ uci_set_state firewall core loaded 1
+}
+
+fw_stop() {
+ fw_init
+
+ fw_callback pre stop
+
+ fw_clear ACCEPT
+
+ fw_callback post stop
+
+ uci_revert_state firewall
+ config_clear
+ unset FW_INITIALIZED
+}
+
+fw_restart() {
+ fw_stop
+ fw_start
+}
+
+fw_reload() {
+ fw_restart
+}
+
+fw_is_loaded() {
+ local bool
+ config_get_bool bool core loaded 0
+ return $((! $bool))
+}
+
+
+fw_die() {
+ echo "Error:" "$@" >&2
+ fw_log error "$@"
+ fw_stop
+ exit 1
+}
+
+fw_log() {
+ local level="$1"
+ [ -n "$2" ] || {
+ shift
+ level=notice
+ }
+ logger -t firewall -p user.$level "$@"
+}
+
+
+fw_init() {
+ [ -z "$FW_INITIALIZED" ] || return 0
+
+ . $FW_LIBDIR/config.sh
+
+ scan_interfaces
+ fw_config_append firewall
+
+ local hooks="core stop defaults zone notrack synflood"
+ local file lib hk pp
+ for file in $FW_LIBDIR/core_*.sh; do
+ . $file
+ hk=$(basename $file .sh)
+ hk=${hk#core_}
+ append hooks $hk
+ done
+ for file in $FW_LIBDIR/*.sh; do
+ lib=$(basename $file .sh)
+ lib=${lib##[0-9][0-9]_}
+ case $lib in
+ core*|fw|config|uci_firewall) continue ;;
+ esac
+ . $file
+ for hk in $hooks; do
+ for pp in pre post; do
+ type ${lib}_${pp}_${hk}_cb >/dev/null &&
+ append FW_CB_${pp}_${hk} ${lib}
+ done
+ done
+ done
+
+ fw_callback post init
+
+ FW_INITIALIZED=1
+ return 0
+}
diff --git a/package/firewall/files/lib/core_forwarding.sh b/package/firewall/files/lib/core_forwarding.sh
new file mode 100644
index 0000000000..766e48e38e
--- /dev/null
+++ b/package/firewall/files/lib/core_forwarding.sh
@@ -0,0 +1,40 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+
+fw_config_get_forwarding() {
+ [ "${forwarding_NAME}" != "$1" ] || return
+ fw_config_get_section "$1" forwarding { \
+ string _name "$1" \
+ string name "" \
+ string src "" \
+ string dest "" \
+ } || return
+ [ -n "$forwarding_name" ] || forwarding_name=$forwarding__name
+}
+
+fw_load_forwarding() {
+ fw_config_get_forwarding "$1"
+
+ fw_callback pre forwarding
+
+ local chain=forward
+ [ -n "$forwarding_src" ] && {
+ chain=zone_${forwarding_src}_forward
+ }
+
+ local target=ACCEPT
+ [ -n "$forwarding_dest" ] && {
+ target=zone_${forwarding_dest}_ACCEPT
+ }
+
+ fw add i f $chain $target ^
+
+ # propagate masq zone flag
+ [ -n "$forwarding_src" ] && list_contains CONNTRACK_ZONES $forwarding_src && {
+ append CONNTRACK_ZONES $forwarding_dest
+ }
+ [ -n "$forwarding_dest" ] && list_contains CONNTRACK_ZONES $forwarding_dest && {
+ append CONNTRACK_ZONES $forwarding_src
+ }
+
+ fw_callback post forwarding
+}
diff --git a/package/firewall/files/lib/core_init.sh b/package/firewall/files/lib/core_init.sh
new file mode 100644
index 0000000000..82939b9416
--- /dev/null
+++ b/package/firewall/files/lib/core_init.sh
@@ -0,0 +1,258 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+# Copyright (C) 2008 John Crispin <blogic@openwrt.org>
+
+FW_INITIALIZED=
+
+FW_ZONES=
+FW_CONNTRACK_ZONES=
+FW_NOTRACK_DISABLED=
+
+FW_DEFAULTS_APPLIED=
+FW_ADD_CUSTOM_CHAINS=
+FW_ACCEPT_REDIRECTS=
+FW_ACCEPT_SRC_ROUTE=
+
+FW_DEFAULT_INPUT_POLICY=REJECT
+FW_DEFAULT_OUTPUT_POLICY=REJECT
+FW_DEFAULT_FORWARD_POLICY=REJECT
+
+
+fw_load_defaults() {
+ fw_config_get_section "$1" defaults { \
+ string input $FW_DEFAULT_INPUT_POLICY \
+ string output $FW_DEFAULT_OUTPUT_POLICY \
+ string forward $FW_DEFAULT_FORWARD_POLICY \
+ boolean drop_invalid 0 \
+ boolean syn_flood 0 \
+ boolean synflood_protect 0 \
+ string synflood_rate 25 \
+ string synflood_burst 50 \
+ boolean tcp_syncookies 1 \
+ boolean tcp_ecn 0 \
+ boolean tcp_westwood 0 \
+ boolean tcp_window_scaling 1 \
+ boolean accept_redirects 0 \
+ boolean accept_source_route 0 \
+ boolean custom_chains 1 \
+ } || return
+ [ -n "$FW_DEFAULTS_APPLIED" ] && {
+ echo "Error: multiple defaults sections detected"
+ return 1
+ }
+ FW_DEFAULTS_APPLIED=1
+
+ FW_DEFAULT_INPUT_POLICY=$defaults_input
+ FW_DEFAULT_OUTPUT_POLICY=$defaults_output
+ FW_DEFAULT_FORWARD_POLICY=$defaults_forward
+
+ FW_ADD_CUSTOM_CHAINS=$defaults_custom_chains
+
+ FW_ACCEPT_REDIRECTS=$defaults_accept_redirects
+ FW_ACCEPT_SRC_ROUTE=$defaults_accept_source_route
+
+ fw_callback pre defaults
+
+ # Seems like there are only one sysctl for both IP versions.
+ for s in syncookies ecn westwood window_scaling; do
+ eval "sysctl -e -w net.ipv4.tcp_${s}=\$defaults_tcp_${s}" >/dev/null
+ done
+ fw_sysctl_interface all
+
+ [ $defaults_drop_invalid == 1 ] && {
+ fw add i f INPUT DROP { -m state --state INVALID }
+ fw add i f OUTPUT DROP { -m state --state INVALID }
+ fw add i f FORWARD DROP { -m state --state INVALID }
+ FW_NOTRACK_DISABLED=1
+ }
+
+ fw add i f INPUT ACCEPT { -m state --state RELATED,ESTABLISHED }
+ fw add i f OUTPUT ACCEPT { -m state --state RELATED,ESTABLISHED }
+ fw add i f FORWARD ACCEPT { -m state --state RELATED,ESTABLISHED }
+
+ fw add i f INPUT ACCEPT { -i lo }
+ fw add i f OUTPUT ACCEPT { -o lo }
+
+ # Compatibility to old 'syn_flood' parameter
+ [ $defaults_syn_flood == 1 ] && \
+ defaults_synflood_protect=1
+
+ [ $defaults_synflood_protect == 1 ] && {
+ echo "Loading synflood protection"
+ fw_callback pre synflood
+ fw add i f syn_flood
+ fw add i f syn_flood RETURN { \
+ -p tcp --syn \
+ -m limit --limit "${defaults_synflood_rate}/second" --limit-burst "${defaults_synflood_burst}" \
+ }
+ fw add i f syn_flood DROP
+ fw add i f INPUT syn_flood { -p tcp --syn }
+ fw_callback post synflood
+ }
+
+ [ $defaults_custom_chains == 1 ] && {
+ echo "Adding custom chains"
+ fw add i f input_rule
+ fw add i f output_rule
+ fw add i f forwarding_rule
+ fw add i n prerouting_rule
+ fw add i n postrouting_rule
+
+ fw add i f INPUT input_rule
+ fw add i f OUTPUT output_rule
+ fw add i f FORWARD forwarding_rule
+ fw add i n PREROUTING prerouting_rule
+ fw add i n POSTROUTING postrouting_rule
+ }
+
+ fw add i f input
+ fw add i f output
+ fw add i f forward
+
+ fw add i f INPUT input
+ fw add i f OUTPUT output
+ fw add i f FORWARD forward
+
+ fw add i f reject
+ fw add i f reject REJECT { --reject-with tcp-reset -p tcp }
+ fw add i f reject REJECT { --reject-with port-unreach }
+
+ fw_set_filter_policy
+
+ fw_callback post defaults
+}
+
+
+fw_config_get_zone() {
+ [ "${zone_NAME}" != "$1" ] || return
+ fw_config_get_section "$1" zone { \
+ string name "$1" \
+ string network "" \
+ string input "$FW_DEFAULT_INPUT_POLICY" \
+ string output "$FW_DEFAULT_OUTPUT_POLICY" \
+ string forward "$FW_DEFAULT_FORWARD_POLICY" \
+ boolean masq 0 \
+ boolean conntrack 0 \
+ boolean mtu_fix 0 \
+ boolean custom_chains "$FW_ADD_CUSTOM_CHAINS" \
+ } || return
+ [ -n "$zone_name" ] || zone_name=$zone_NAME
+ [ -n "$zone_network" ] || zone_network=$zone_name
+}
+
+fw_load_zone() {
+ fw_config_get_zone "$1"
+
+ list_contains FW_ZONES $zone_name && {
+ fw_die "zone ${zone_name}: duplicated zone"
+ }
+ append FW_ZONES $zone_name
+
+ fw_callback pre zone
+
+ [ $zone_conntrack = 1 -o $zone_masq = 1 ] && \
+ append FW_CONNTRACK_ZONES "$zone_NAME"
+
+ local chain=zone_${zone_name}
+
+ fw add i f ${chain}_ACCEPT
+ fw add i f ${chain}_DROP
+ fw add i f ${chain}_REJECT
+ fw add i f ${chain}_MSSFIX
+
+ # TODO: Rename to ${chain}_input
+ fw add i f ${chain}
+ fw add i f ${chain} ${chain}_${zone_input} $
+
+ fw add i f ${chain}_forward
+ fw add i f ${chain}_forward ${chain}_${zone_forward} $
+
+ # TODO: add ${chain}_output
+ fw add i f output ${chain}_${zone_output} $
+
+ # TODO: Rename to ${chain}_MASQUERADE
+ fw add i n ${chain}_nat
+ fw add i n ${chain}_prerouting
+
+ fw add i r ${chain}_notrack
+ [ $zone_masq == 1 ] && \
+ fw add i n POSTROUTING ${chain}_nat $
+
+ [ $zone_mtu_fix == 1 ] && \
+ fw add i f FORWARD ${chain}_MSSFIX ^
+
+ [ $zone_custom_chains == 1 ] && {
+ [ $FW_ADD_CUSTOM_CHAINS == 1 ] || \
+ fw_die "zone ${zone_name}: custom_chains globally disabled"
+
+ fw add i f input_${zone_name}
+ fw add i f ${chain} input_${zone_name} ^
+
+ fw add i f forwarding_${zone_name}
+ fw add i f ${chain}_forward forwarding_${zone_name} ^
+
+ fw add i n prerouting_${zone_name}
+ fw add i n ${chain}_prerouting prerouting_${zone_name} ^
+ }
+
+ fw_callback post zone
+}
+
+fw_load_notrack_zone() {
+ list_contains FW_CONNTRACK_ZONES "$1" && return
+
+ fw_config_get_zone "$1"
+
+ fw_callback pre notrack
+
+ fw add i f zone_${zone_name}_notrack NOTRACK $
+
+ fw_callback post notrack
+}
+
+
+fw_load_include() {
+ local name="$1"
+
+ local path; config_get path ${name} path
+ [ -e $path ] && . $path
+}
+
+
+fw_clear() {
+ local policy=$1
+
+ fw_set_filter_policy $policy
+
+ local tab
+ for tab in f n r; do
+ fw del i $tab
+ done
+}
+
+fw_set_filter_policy() {
+ local policy=$1
+
+ local chn tgt
+ for chn in INPUT OUTPUT FORWARD; do
+ eval "tgt=\${policy:-\${FW_DEFAULT_${chn}_POLICY}}"
+ [ $tgt == "REJECT" ] && tgt=reject
+ [ $tgt == "ACCEPT" -o $tgt == "DROP" ] || {
+ fw add i f $chn $tgt $
+ tgt=DROP
+ }
+ fw policy i f $chn $tgt
+ done
+}
+
+
+fw_callback() {
+ local pp=$1
+ local hk=$2
+
+ local libs lib
+ eval "libs=\$FW_CB_${pp}_${hk}"
+ [ -n "$libs" ] || return
+ for lib in $libs; do
+ ${lib}_${pp}_${hk}_cb
+ done
+}
diff --git a/package/firewall/files/lib/core_interface.sh b/package/firewall/files/lib/core_interface.sh
new file mode 100644
index 0000000000..9da6739f0e
--- /dev/null
+++ b/package/firewall/files/lib/core_interface.sh
@@ -0,0 +1,86 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+
+fw_configure_interface() {
+ local iface=$1
+ local action=$2
+ local ifname=$3
+
+ local status;
+ config_get_bool status "$iface" up "0"
+ [ "$status" == 1 ] || return 0
+
+ [ -n "$ifname" ] || {
+ config_get ifname "$iface" ifname
+ ifname=${ifname:-$iface}
+ }
+ [ "$ifname" == "lo" ] && return 0
+
+ fw_callback pre interface
+
+ fw__do_rules() {
+ local action=$1
+ local chain=$2
+ local ifname=$3
+
+ fw $action i f ${chain}_ACCEPT ACCEPT ^ { -o "$ifname" }
+ fw $action i f ${chain}_ACCEPT ACCEPT ^ { -i "$ifname" }
+ fw $action i f ${chain}_DROP DROP ^ { -o "$ifname" }
+ fw $action i f ${chain}_DROP DROP ^ { -i "$ifname" }
+ fw $action i f ${chain}_REJECT reject ^ { -o "$ifname" }
+ fw $action i f ${chain}_REJECT reject ^ { -i "$ifname" }
+
+ fw $action i n ${chain}_nat MASQUERADE ^ { -o "$ifname" }
+ fw $action i f ${chain}_MSSFIX TCPMSS ^ { -o "$ifname" -p tcp --tcp-flags SYN,RST SYN --clamp-mss-to-pmtu }
+
+ fw $action i f input ${chain} $ { -i "$ifname" }
+ fw $action i f forward ${chain}_forward $ { -i "$ifname" }
+ fw $action i n PREROUTING ${chain}_prerouting ^ { -i "$ifname" }
+ fw $action i r PREROUTING ${chain}_notrack ^ { -i "$ifname" }
+ }
+
+ local old_zones old_ifname
+ config_get old_zones core "${iface}_zone"
+ [ -n "$old_zones" ] && {
+ config_get old_ifname core "${iface}_ifname"
+ for z in $old_zones; do
+ fw_log info "removing $iface ($old_ifname) from zone $z"
+ fw__do_rules del zone_$z $old_ifname
+
+ ACTION=remove ZONE="$z" INTERFACE="$iface" DEVICE="$ifname" /sbin/hotplug-call firewall
+ done
+ uci_revert_state firewall core "${iface}_zone"
+ uci_revert_state firewall core "${iface}_ifname"
+ }
+ [ "$action" == del ] && return
+
+ local new_zones
+ load_zone() {
+ fw_config_get_zone "$1"
+ list_contains zone_network "$iface" || return
+
+ fw_log info "adding $iface ($ifname) to zone $zone_name"
+ fw__do_rules add zone_${zone_name} "$ifname"
+ append new_zones $zone_name
+
+ ACTION=add ZONE="$zone_name" INTERFACE="$iface" DEVICE="$ifname" /sbin/hotplug-call firewall
+ }
+ config_foreach load_zone zone
+
+ uci_set_state firewall core "${iface}_zone" "$new_zones"
+ uci_set_state firewall core "${iface}_ifname" "$ifname"
+
+ fw_sysctl_interface $ifname
+
+ fw_callback post interface
+}
+
+fw_sysctl_interface() {
+ local ifname=$1
+ {
+ sysctl -w net.ipv4.conf.${ifname}.accept_redirects=$FW_ACCEPT_REDIRECTS
+ sysctl -w net.ipv6.conf.${ifname}.accept_redirects=$FW_ACCEPT_REDIRECTS
+ sysctl -w net.ipv4.conf.${ifname}.accept_source_route=$FW_ACCEPT_SRC_ROUTE
+ sysctl -w net.ipv6.conf.${ifname}.accept_source_route=$FW_ACCEPT_SRC_ROUTE
+ } >/dev/null 2>/dev/null
+}
+
diff --git a/package/firewall/files/lib/core_redirect.sh b/package/firewall/files/lib/core_redirect.sh
new file mode 100644
index 0000000000..0f0ccffe00
--- /dev/null
+++ b/package/firewall/files/lib/core_redirect.sh
@@ -0,0 +1,61 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+
+fw_config_get_redirect() {
+ [ "${redirect_NAME}" != "$1" ] || return
+ fw_config_get_section "$1" redirect { \
+ string _name "$1" \
+ string name "" \
+ string src "" \
+ ipaddr src_ip "" \
+ ipaddr src_dip "" \
+ string src_mac "" \
+ string src_port "" \
+ string src_dport "" \
+ string dest "" \
+ ipaddr dest_ip "" \
+ string dest_mac "" \
+ string dest_port "" \
+ string proto "tcpudp" \
+ } || return
+ [ -n "$redirect_name" ] || redirect_name=$redirect__name
+}
+
+fw_load_redirect() {
+ fw_config_get_redirect "$1"
+
+ fw_callback pre redirect
+
+ [ -n "$redirect_src" -a -n "$redirect_dest_ip" ] || {
+ fw_die "redirect ${redirect_name}: needs src and dest_ip"
+ }
+
+ 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}
+
+ [ "$redirect_proto" == "tcpudp" ] && redirect_proto="tcp udp"
+ for redirect_proto in $redirect_proto; do
+ fw add I n zone_${redirect_src}_prerouting DNAT $ { $redirect_src_ip $redirect_dest_ip } { \
+ ${redirect_proto:+-p $redirect_proto} \
+ ${redirect_src_ip:+-s $redirect_src_ip} \
+ ${redirect_src_dip:+-d $redirect_src_dip} \
+ ${redirect_src_port:+--sport $redirect_src_port} \
+ ${redirect_src_dport:+--dport $redirect_src_dport} \
+ ${redirect_src_mac:+-m mac --mac-source $redirect_src_mac} \
+ --to-destination ${redirect_dest_ip}${redirect_dest_port:+:$nat_dest_port} \
+ }
+
+ fw add I f zone_${redirect_src}_forward ACCEPT ^ { $redirect_src_ip $redirect_dest_ip } { \
+ -d $redirect_dest_ip \
+ ${redirect_proto:+-p $redirect_proto} \
+ ${redirect_src_ip:+-s $redirect_src_ip} \
+ ${redirect_src_port:+--sport $redirect_src_port} \
+ ${fwd_dest_port:+--dport $fwd_dest_port} \
+ ${redirect_src_mac:+-m mac --mac-source $redirect_src_mac} \
+ }
+ done
+
+ fw_callback post redirect
+}
diff --git a/package/firewall/files/lib/core_rule.sh b/package/firewall/files/lib/core_rule.sh
new file mode 100644
index 0000000000..e6a276e5f3
--- /dev/null
+++ b/package/firewall/files/lib/core_rule.sh
@@ -0,0 +1,66 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+
+fw_config_get_rule() {
+ [ "${rule_NAME}" != "$1" ] || return
+ fw_config_get_section "$1" rule { \
+ string _name "$1" \
+ string name "" \
+ string src "" \
+ ipaddr src_ip "" \
+ string src_mac "" \
+ string src_port "" \
+ string dest "" \
+ ipaddr dest_ip "" \
+ string dest_mac "" \
+ string dest_port "" \
+ string icmp_type "" \
+ string proto "tcpudp" \
+ string target "" \
+ } || return
+ [ -n "$rule_name" ] || rule_name=$rule__name
+ [ "$rule_proto" == "icmp" ] || rule_icmp_type=
+}
+
+fw_load_rule() {
+ fw_config_get_rule "$1"
+
+ fw_callback pre rule
+
+ rule_src_port=$(fw_get_port_range $rule_src_port)
+ rule_dest_port=$(fw_get_port_range $rule_dest_port)
+
+ local chain=input
+ [ -n "$rule_src" ] && {
+ [ -z "$rule_dest" ] && {
+ chain=zone_${rule_src}
+ } || {
+ chain=zone_${rule_src}_forward
+ }
+ }
+
+ local target=$rule_target
+ [ -z "$target" ] && {
+ target=REJECT
+ }
+ [ -n "$dest" ] && {
+ target=zone_${rule_dest}_${target}
+ }
+
+ local rule_pos
+ eval 'rule_pos=$((++FW__RULE_COUNT_'$chain'))'
+
+ [ "$rule_proto" == "tcpudp" ] && rule_proto="tcp udp"
+ for rule_proto in $rule_proto; do
+ fw add I f $chain $target $rule_pos { $rule_src_ip $rule_dest_ip } { \
+ ${rule_proto:+-p $rule_proto} \
+ ${rule_src_ip:+-s $rule_src_ip} \
+ ${rule_src_port:+--sport $rule_src_port} \
+ ${rule_src_mac:+-m mac --mac-source $rule_src_mac} \
+ ${rule_dest_ip:+-d $rule_dest_ip} \
+ ${rule_dest_port:+--dport $rule_dest_port} \
+ ${rule_icmp_type:+--icmp-type $rule_icmp_type} \
+ }
+ done
+
+ fw_callback post rule
+}
diff --git a/package/firewall/files/lib/fw.sh b/package/firewall/files/lib/fw.sh
new file mode 100644
index 0000000000..c06e864236
--- /dev/null
+++ b/package/firewall/files/lib/fw.sh
@@ -0,0 +1,182 @@
+# Copyright (C) 2009-2010 OpenWrt.org
+# Copyright (C) 2009 Malte S. Stretz
+
+export FW_4_ERROR=0
+export FW_6_ERROR=0
+export FW_i_ERROR=0
+export FW_e_ERROR=0
+export FW_a_ERROR=0
+
+#TODO: remove this
+[ "${-#*x}" == "$-" ] && {
+ fw() {
+ fw__exec "$@"
+ }
+} || {
+ fw() {
+ local os=$-
+ set +x
+ fw__exec "$@"
+ local rc=$?
+ set -$os
+ return $rc
+ }
+}
+
+fw__exec() { # <action> <family> <table> <chain> <target> <position> { <rules> }
+ local cmd fam tab chn tgt pos
+ local i
+ for i in cmd fam tab chn tgt pos; do
+ if [ "$1" -a "$1" != '{' ]; then
+ eval "$i='$1'"
+ shift
+ else
+ eval "$i=-"
+ fi
+ done
+
+ fw__rc() {
+ export FW_${fam}_ERROR=$1
+ return $1
+ }
+
+ fw__dualip() {
+ fw $cmd 4 $tab $chn $tgt $pos "$@"
+ fw $cmd 6 $tab $chn $tgt $pos "$@"
+ fw__rc $((FW_4_ERROR | FW_6_ERROR))
+ }
+
+ fw__autoip() {
+ local ip4 ip6
+ shift
+ while [ "$1" != '}' ]; do
+ case "$1" in
+ *.*.*.*) ip4=1 ;;
+ *:*) ip6=1 ;;
+ esac
+ shift
+ done
+ shift
+ if [ "${ip4:-4}" == "${ip6:-6}" ]; then
+ echo "fw: can't mix ip4 and ip6" >&2
+ return 1
+ fi
+ local ver=${ip4:+4}${ip6:+6}
+ fam=i
+ fw $cmd ${ver:-i} $tab $chn $tgt $pos "$@"
+ fw__rc $?
+ }
+
+ fw__has() {
+ local tab=${1:-$tab}
+ if [ $tab == '-' ]; then
+ type $app > /dev/null 2> /dev/null
+ fw__rc $(($? & 1))
+ return
+ fi
+ local mod
+ eval "mod=\$FW_${fam}_${tab}"
+ if [ "$mod" ]; then
+ fw__rc $mod
+ return
+ fi
+ case "$fam" in
+ 4) mod=iptable_${tab} ;;
+ 6) mod=ip6table_${tab} ;;
+ *) mod=. ;;
+ esac
+ grep "^${mod} " /proc/modules > /dev/null
+ mod=$?
+ export FW_${fam}_${tab}=$mod
+ fw__rc $mod
+ }
+
+ fw__err() {
+ local err
+ eval "err=\$FW_${fam}_ERROR"
+ fw__rc $err
+ }
+
+ local app=
+ local pol=
+ case "$fam" in
+ 4) app=iptables ;;
+ 6) app=ip6tables ;;
+ i) fw__dualip "$@"; return ;;
+ I) fw__autoip "$@"; return ;;
+ e) app=ebtables ;;
+ a) app=arptables ;;
+ -) fw $cmd i $tab $chn $tgt $pos "$@"; return ;;
+ *) return 254 ;;
+ esac
+ case "$tab" in
+ f) tab=filter ;;
+ m) tab=mangle ;;
+ n) tab=nat ;;
+ r) tab=raw ;;
+ -) tab=filter ;;
+ esac
+ case "$cmd:$chn:$tgt:$pos" in
+ add:*:-:*) cmd=new-chain ;;
+ add:*:*:-) cmd=append ;;
+ add:*:*:$) cmd=append ;;
+ add:*:*:*) cmd=insert ;;
+ del:-:*:*) cmd=delete-chain; fw flush $fam $tab ;;
+ del:*:-:*) cmd=delete-chain; fw flush $fam $tab $chn ;;
+ del:*:*:*) cmd=delete ;;
+ flush:*) ;;
+ policy:*) pol=$tgt; tgt=- ;;
+ has:*) fw__has; return ;;
+ err:*) fw__err; return ;;
+ list:*) cmd="numeric --verbose --$cmd" ;;
+ *) return 254 ;;
+ esac
+ case "$chn" in
+ -) chn= ;;
+ esac
+ case "$tgt" in
+ -) tgt= ;;
+ esac
+ case "$pos" in
+ ^) pos=1 ;;
+ $) pos= ;;
+ -) pos= ;;
+ esac
+
+ if ! fw__has - family || ! fw__has $tab ; then
+ export FW_${fam}_ERROR=0
+ return 0
+ fi
+
+ if [ $# -gt 0 ]; then
+ shift
+ if [ $cmd == del ]; then
+ pos=-
+ fi
+ fi
+ while [ $# -gt 1 ]; do
+ echo -n "$1"
+ echo -ne "\0"
+ shift
+ done | xargs -0 ${FW_TRACE:+-t} \
+ $app --table ${tab} --${cmd} ${chn} ${pol} ${pos} ${tgt:+--jump "$tgt"}
+ fw__rc $?
+}
+
+fw_get_port_range() {
+ local ports=$1
+ local delim=${2:-:}
+ if [ "$3" ]; then
+ fw_get_port_range "${ports}-${3}" $delim
+ return
+ fi
+
+ local first=${ports%-*}
+ local last=${ports#*-}
+ if [ "$first" != "$last" ]; then
+ echo "$first$delim$last"
+ else
+ echo "$first"
+ fi
+}
+
diff --git a/package/firewall/files/lib/uci_firewall.sh b/package/firewall/files/lib/uci_firewall.sh
new file mode 100644
index 0000000000..7c95a7a939
--- /dev/null
+++ b/package/firewall/files/lib/uci_firewall.sh
@@ -0,0 +1,5 @@
+# This file is here for backwards compatibility and to override the
+# uci_firewall.sh from an earlier version.
+type fw_is_loaded >/dev/null || {
+ . /lib/firewall/core.sh
+}