diff options
| -rw-r--r-- | package/firewall/Makefile | 12 | ||||
| -rw-r--r-- | package/firewall/files/20-firewall | 5 | ||||
| -rw-r--r-- | package/firewall/files/bin/fw | 49 | ||||
| -rw-r--r-- | package/firewall/files/firewall.hotplug | 19 | ||||
| -rwxr-xr-x | package/firewall/files/firewall.init | 21 | ||||
| -rw-r--r-- | package/firewall/files/lib/config.sh | 97 | ||||
| -rw-r--r-- | package/firewall/files/lib/core.sh | 136 | ||||
| -rw-r--r-- | package/firewall/files/lib/core_forwarding.sh | 40 | ||||
| -rw-r--r-- | package/firewall/files/lib/core_init.sh | 258 | ||||
| -rw-r--r-- | package/firewall/files/lib/core_interface.sh | 86 | ||||
| -rw-r--r-- | package/firewall/files/lib/core_redirect.sh | 61 | ||||
| -rw-r--r-- | package/firewall/files/lib/core_rule.sh | 66 | ||||
| -rw-r--r-- | package/firewall/files/lib/fw.sh | 182 | ||||
| -rw-r--r-- | package/firewall/files/lib/uci_firewall.sh | 5 | ||||
| -rwxr-xr-x | package/firewall/files/uci_firewall.sh | 530 | 
15 files changed, 1023 insertions, 544 deletions
diff --git a/package/firewall/Makefile b/package/firewall/Makefile index abc602043..22d359939 100644 --- a/package/firewall/Makefile +++ b/package/firewall/Makefile @@ -1,5 +1,5 @@  # -# Copyright (C) 2008-2009 OpenWrt.org +# Copyright (C) 2008-2010 OpenWrt.org  #  # This is free software, licensed under the GNU General Public License v2.  # See /LICENSE for more information. @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk  PKG_NAME:=firewall -PKG_VERSION:=1 -PKG_RELEASE:=10 +PKG_VERSION:=2 +PKG_RELEASE:=1  include $(INCLUDE_DIR)/package.mk @@ -36,13 +36,15 @@ endef  define Package/firewall/install  	$(INSTALL_DIR) $(1)/lib/firewall -	$(INSTALL_DATA) ./files/uci_firewall.sh $(1)/lib/firewall +	$(INSTALL_DATA) ./files/lib/*.sh $(1)/lib/firewall +	$(INSTALL_DIR) $(1)/sbin +	$(INSTALL_BIN) ./files/bin/fw $(1)/sbin  	$(INSTALL_DIR) $(1)/etc/config  	$(INSTALL_DATA) ./files/firewall.config $(1)/etc/config/firewall  	$(INSTALL_DIR) $(1)/etc/init.d/  	$(INSTALL_BIN) ./files/firewall.init $(1)/etc/init.d/firewall  	$(INSTALL_DIR) $(1)/etc/hotplug.d/iface -	$(INSTALL_DATA) ./files/20-firewall $(1)/etc/hotplug.d/iface +	$(INSTALL_DATA) ./files/firewall.hotplug $(1)/etc/hotplug.d/iface/20-firewall  	$(INSTALL_DIR) $(1)/etc  	$(INSTALL_DATA) ./files/firewall.user $(1)/etc  endef diff --git a/package/firewall/files/20-firewall b/package/firewall/files/20-firewall deleted file mode 100644 index 4b89326b5..000000000 --- a/package/firewall/files/20-firewall +++ /dev/null @@ -1,5 +0,0 @@ -. /lib/firewall/uci_firewall.sh -unset ZONE -config_get ifname $INTERFACE ifname -[ "$ifname" == "lo" ] && exit 0 -fw_event "$ACTION" "$INTERFACE" diff --git a/package/firewall/files/bin/fw b/package/firewall/files/bin/fw new file mode 100644 index 000000000..0f83b8eed --- /dev/null +++ b/package/firewall/files/bin/fw @@ -0,0 +1,49 @@ +#!/bin/sh +FW_LIBDIR=/lib/firewall + +. /etc/functions.sh +. ${FW_LIBDIR}/fw.sh + +case "$(type fw)" in +	*function) ;; +	*) exit 255;; +esac + +usage() { +	echo $0 "<command>" "<family>" "<table>" "<chain>" "<target>" "{" "<rules>" "}" +	exit 0 +} + +cmd=$1 +shift +case "$cmd" in +	--help|help) usage ;; +	start|stop|reload|restart) +		. ${FW_LIBDIR}/core.sh +		fw_$cmd +		exit $? +	;; +esac + +fam=$1 +shift +case "$fam" in +	ip) +		fam=i +		if [ $# -gt 2 ]; then +			for p in $(seq 2 $(($# - 1))); do +				if eval "[ \$$p == '}' ]"; then +					fam=I +					break +				fi +			done +		fi ;; +	ip4) fam=4 ;; +	ip6) fam=6 ;; +	arp) fam=a ;; +	eth) fam=e ;; +	-*) exec $0 $cmd ${fam##*-} "$@" ;; +esac + +fw "$cmd" "$fam" "$@" +exit $? diff --git a/package/firewall/files/firewall.hotplug b/package/firewall/files/firewall.hotplug new file mode 100644 index 000000000..fa5643a2b --- /dev/null +++ b/package/firewall/files/firewall.hotplug @@ -0,0 +1,19 @@ +#!/bin/sh +# This script is executed as part of the hotplug event with +# HOTPLUG_TYPE=iface, triggered by various scripts when an interface +# is configured (ACTION=ifup) or deconfigured (ACTION=ifdown).  The +# interface is available as INTERFACE, the real device as DEVICE. +. /etc/functions.sh + +[ "$DEVICE" == "lo" ] && exit 0 + +. /lib/firewall/core.sh +fw_is_loaded || exit 0 +fw_init + +case "$ACTION" in +	ifup) +		fw_configure_interface "$INTERFACE" add "$DEVICE" ;; +	ifdown) +		fw_configure_interface "$INTERFACE" del "$DEVICE" ;; +esac diff --git a/package/firewall/files/firewall.init b/package/firewall/files/firewall.init index 26855f39a..54742488e 100755 --- a/package/firewall/files/firewall.init +++ b/package/firewall/files/firewall.init @@ -3,12 +3,25 @@  START=45 +FW_LIBDIR=/lib/firewall + +fw() { +	. $FW_LIBDIR/core.sh +	fw_$1 +} +  start() { -	. /lib/firewall/uci_firewall.sh -	fw_init +	fw start  }  stop() { -	. /lib/firewall/uci_firewall.sh -	fw_stop	 +	fw stop +} + +restart() { +	fw restart +} + +reload() { +	fw reload  } diff --git a/package/firewall/files/lib/config.sh b/package/firewall/files/lib/config.sh new file mode 100644 index 000000000..1c5e03096 --- /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 000000000..3fd98d160 --- /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 000000000..766e48e38 --- /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 000000000..82939b941 --- /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 000000000..9da6739f0 --- /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 000000000..0f0ccffe0 --- /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 000000000..e6a276e5f --- /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 000000000..c06e86423 --- /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 000000000..7c95a7a93 --- /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 +} diff --git a/package/firewall/files/uci_firewall.sh b/package/firewall/files/uci_firewall.sh deleted file mode 100755 index 8d7538201..000000000 --- a/package/firewall/files/uci_firewall.sh +++ /dev/null @@ -1,530 +0,0 @@ -#!/bin/sh -# Copyright (C) 2008 John Crispin <blogic@openwrt.org> - -. /etc/functions.sh - -IPTABLES="echo iptables" -IPTABLES=iptables - -config_clear -include /lib/network -scan_interfaces - -CONFIG_APPEND=1 -config_load firewall - -config fw_zones -ZONE_LIST=$CONFIG_SECTION - -CUSTOM_CHAINS=1 -DEF_INPUT=DROP -DEF_OUTPUT=DROP -DEF_FORWARD=DROP -CONNTRACK_ZONES= -NOTRACK_DISABLED= - -find_item() { -	local item="$1"; shift -	for i in "$@"; do -		[ "$i" = "$item" ] && return 0 -	done -	return 1 -} - -load_policy() { -	config_get input $1 input -	config_get output $1 output -	config_get forward $1 forward - -	DEF_INPUT="${input:-$DEF_INPUT}" -	DEF_OUTPUT="${output:-$DEF_OUTPUT}" -	DEF_FORWARD="${forward:-$DEF_FORWARD}" -} - -create_zone() { -	local exists - -	[ "$1" == "loopback" ] && return - -	config_get exists $ZONE_LIST $1 -	[ -n "$exists" ] && return -	config_set $ZONE_LIST $1 1 - -	$IPTABLES -N zone_$1 -	$IPTABLES -N zone_$1_MSSFIX -	$IPTABLES -N zone_$1_ACCEPT -	$IPTABLES -N zone_$1_DROP -	$IPTABLES -N zone_$1_REJECT -	$IPTABLES -N zone_$1_forward -	[ "$4" ] && $IPTABLES -A output -j zone_$1_$4 -	$IPTABLES -N zone_$1_nat -t nat -	$IPTABLES -N zone_$1_prerouting -t nat -	$IPTABLES -t raw -N zone_$1_notrack -	[ "$6" == "1" ] && $IPTABLES -t nat -A POSTROUTING -j zone_$1_nat -	[ "$7" == "1" ] && $IPTABLES -I FORWARD 1 -j zone_$1_MSSFIX -} - - -addif() { -	local network="$1" -	local ifname="$2" -	local zone="$3" - -	local n_if n_zone -	config_get n_if core "${network}_ifname" -	config_get n_zone core "${network}_zone" -	[ -n "$n_zone" ] && { -		if [ "$n_zone" != "$zone" ]; then -			delif "$network" "$n_if" "$n_zone" -		else -			return -		fi -	} - -	logger "adding $network ($ifname) to firewall zone $zone" -	$IPTABLES -A input -i "$ifname" -j zone_${zone} -	$IPTABLES -I zone_${zone}_MSSFIX 1 -o "$ifname" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -	$IPTABLES -I zone_${zone}_ACCEPT 1 -o "$ifname" -j ACCEPT -	$IPTABLES -I zone_${zone}_DROP 1 -o "$ifname" -j DROP -	$IPTABLES -I zone_${zone}_REJECT 1 -o "$ifname" -j reject -	$IPTABLES -I zone_${zone}_ACCEPT 1 -i "$ifname" -j ACCEPT -	$IPTABLES -I zone_${zone}_DROP 1 -i "$ifname" -j DROP -	$IPTABLES -I zone_${zone}_REJECT 1 -i "$ifname" -j reject -	$IPTABLES -I zone_${zone}_nat 1 -t nat -o "$ifname" -j MASQUERADE -	$IPTABLES -I PREROUTING 1 -t nat -i "$ifname" -j zone_${zone}_prerouting -	$IPTABLES -A forward -i "$ifname" -j zone_${zone}_forward -	$IPTABLES -t raw -I PREROUTING 1 -i "$ifname" -j zone_${zone}_notrack -	uci_set_state firewall core "${network}_ifname" "$ifname" -	uci_set_state firewall core "${network}_zone" "$zone" -	ACTION=add ZONE="$zone" INTERFACE="$network" DEVICE="$ifname" /sbin/hotplug-call firewall -} - -delif() { -	local network="$1" -	local ifname="$2" -	local zone="$3" - -	logger "removing $network ($ifname) from firewall zone $zone" -	$IPTABLES -D input -i "$ifname" -j zone_$zone -	$IPTABLES -D zone_${zone}_MSSFIX -o "$ifname" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu -	$IPTABLES -D zone_${zone}_ACCEPT -o "$ifname" -j ACCEPT -	$IPTABLES -D zone_${zone}_DROP -o "$ifname" -j DROP -	$IPTABLES -D zone_${zone}_REJECT -o "$ifname" -j reject -	$IPTABLES -D zone_${zone}_ACCEPT -i "$ifname" -j ACCEPT -	$IPTABLES -D zone_${zone}_DROP -i "$ifname" -j DROP -	$IPTABLES -D zone_${zone}_REJECT -i "$ifname" -j reject -	$IPTABLES -D zone_${zone}_nat -t nat -o "$ifname" -j MASQUERADE -	$IPTABLES -D PREROUTING -t nat -i "$ifname" -j zone_${zone}_prerouting -	$IPTABLES -D forward -i "$ifname" -j zone_${zone}_forward -	uci_revert_state firewall core "${network}_ifname" -	uci_revert_state firewall core "${network}_zone" -	ACTION=remove ZONE="$zone" INTERFACE="$network" DEVICE="$ifname" /sbin/hotplug-call firewall -} - -load_synflood() { -	local rate=${1:-25} -	local burst=${2:-50} -	echo "Loading synflood protection" -	$IPTABLES -N syn_flood -	$IPTABLES -A syn_flood -p tcp --syn -m limit --limit $rate/second --limit-burst $burst -j RETURN -	$IPTABLES -A syn_flood -j DROP -	$IPTABLES -A INPUT -p tcp --syn -j syn_flood -} - -fw_set_chain_policy() { -	local chain=$1 -	local target=$2 -	[ "$target" == "REJECT" ] && { -		$IPTABLES -A $chain -j reject -		target=DROP -	} -	$IPTABLES -P $chain $target -} - -fw_clear() { -	$IPTABLES -F -	$IPTABLES -t nat -F -	$IPTABLES -t nat -X -	$IPTABLES -t raw -F -	$IPTABLES -t raw -X -	$IPTABLES -X -} - -fw_defaults() { -	[ -n "$DEFAULTS_APPLIED" ] && { -		echo "Error: multiple defaults sections detected" -		return; -	} -	DEFAULTS_APPLIED=1 - -	load_policy "$1" - -	echo 1 > /proc/sys/net/ipv4/tcp_syncookies -	for f in /proc/sys/net/ipv4/conf/*/accept_redirects -	do -		echo 0 > $f -	done -	for f in /proc/sys/net/ipv4/conf/*/accept_source_route -	do -		echo 0 > $f -	done - -	uci_revert_state firewall core -	uci_set_state firewall core "" firewall_state - -	$IPTABLES -P INPUT DROP -	$IPTABLES -P OUTPUT DROP -	$IPTABLES -P FORWARD DROP - -	fw_clear -	config_get_bool drop_invalid $1 drop_invalid 0 - -	[ "$drop_invalid" -gt 0 ] && { -		$IPTABLES -A INPUT -m state --state INVALID -j DROP -		$IPTABLES -A OUTPUT -m state --state INVALID -j DROP -		$IPTABLES -A FORWARD -m state --state INVALID -j DROP -		NOTRACK_DISABLED=1 -	} - -	$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -	$IPTABLES -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -	$IPTABLES -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT - -	$IPTABLES -A INPUT -i lo -j ACCEPT -	$IPTABLES -A OUTPUT -o lo -j ACCEPT - -	config_get syn_flood $1 syn_flood -	config_get syn_rate $1 syn_rate -	config_get syn_burst $1 syn_burst -	[ "$syn_flood" == "1" ] && load_synflood $syn_rate $syn_burst - -	echo "Adding custom chains" -	fw_custom_chains - -	$IPTABLES -N input -	$IPTABLES -N output -	$IPTABLES -N forward - -	$IPTABLES -A INPUT -j input -	$IPTABLES -A OUTPUT -j output -	$IPTABLES -A FORWARD -j forward - -	$IPTABLES -N reject -	$IPTABLES -A reject -p tcp -j REJECT --reject-with tcp-reset -	$IPTABLES -A reject -j REJECT --reject-with icmp-port-unreachable - -	fw_set_chain_policy INPUT "$DEF_INPUT" -	fw_set_chain_policy OUTPUT "$DEF_OUTPUT" -	fw_set_chain_policy FORWARD "$DEF_FORWARD" -} - -fw_zone_defaults() { -	local name -	local network -	local masq - -	config_get name $1 name -	config_get network $1 network -	config_get_bool masq $1 masq "0" -	config_get_bool conntrack $1 conntrack "0" -	config_get_bool mtu_fix $1 mtu_fix 0 - -	load_policy $1 -	[ "$forward" ] && $IPTABLES -A zone_${name}_forward -j zone_${name}_${forward} -	[ "$input" ] && $IPTABLES -A zone_${name} -j zone_${name}_${input} -} - -fw_zone() { -	local name -	local network -	local masq - -	config_get name $1 name -	config_get network $1 network -	config_get_bool masq $1 masq "0" -	config_get_bool conntrack $1 conntrack "0" -	config_get_bool mtu_fix $1 mtu_fix 0 - -	load_policy $1 -	[ "$conntrack" = "1" -o "$masq" = "1" ] && append CONNTRACK_ZONES "$name" -	[ -z "$network" ] && network=$name -	create_zone "$name" "$network" "$input" "$output" "$forward" "$masq" "$mtu_fix" -	fw_custom_chains_zone "$name" -} - -fw_rule() { -	local src -	local src_ip -	local src_mac -	local src_port -	local src_mac -	local dest -	local dest_ip -	local dest_port -	local proto -	local icmp_type -	local target -	local ruleset - -	config_get src $1 src -	config_get src_ip $1 src_ip -	config_get src_mac $1 src_mac -	config_get src_port $1 src_port -	config_get dest $1 dest -	config_get dest_ip $1 dest_ip -	config_get dest_port $1 dest_port -	config_get proto $1 proto -	config_get icmp_type $1 icmp_type -	config_get target $1 target -	config_get ruleset $1 ruleset - -	src_port_first=${src_port%-*} -	src_port_last=${src_port#*-} -	[ "$src_port_first" -ne "$src_port_last" ] && { \ -		src_port="$src_port_first:$src_port_last"; } - -	dest_port_first=${dest_port%-*} -	dest_port_last=${dest_port#*-} -	[ "$dest_port_first" -ne "$dest_port_last" ] && { \ -		dest_port="$dest_port_first:$dest_port_last"; } - -	ZONE=input -	TARGET=$target -	[ -z "$target" ] && target=DROP -	[ -n "$src" -a -z "$dest" ] && ZONE=zone_$src -	[ -n "$src" -a -n "$dest" ] && ZONE=zone_${src}_forward -	[ -n "$dest" ] && TARGET=zone_${dest}_$target - -	eval 'RULE_COUNT=$((++RULE_COUNT_'$ZONE'))' - -	add_rule() { -		$IPTABLES -I $ZONE $RULE_COUNT \ -			${proto:+-p $proto} \ -			${icmp_type:+--icmp-type $icmp_type} \ -			${src_ip:+-s $src_ip} \ -			${src_port:+--sport $src_port} \ -			${src_mac:+-m mac --mac-source $src_mac} \ -			${dest_ip:+-d $dest_ip} \ -			${dest_port:+--dport $dest_port} \ -			-j $TARGET -	} -	[ "$proto" == "tcpudp" -o -z "$proto" ] && { -		proto=tcp -		add_rule -		proto=udp -		add_rule -		return -	} -	add_rule -} - -fw_forwarding() { -	local src -	local dest -	local masq - -	config_get src $1 src -	config_get dest $1 dest -	[ -n "$src" ] && z_src=zone_${src}_forward || z_src=forward -	[ -n "$dest" ] && z_dest=zone_${dest}_ACCEPT || z_dest=ACCEPT -	$IPTABLES -I $z_src 1 -j $z_dest - -	# propagate masq zone flag -	find_item "$src" $CONNTRACK_ZONES && append CONNTRACK_ZONES $dest -	find_item "$dest" $CONNTRACK_ZONES && append CONNTRACK_ZONES $src -} - -fw_redirect() { -	local src -	local src_ip -	local src_port -	local src_dport -	local src_mac -	local dest_ip -	local dest_port dest_port2 -	local proto - -	config_get src $1 src -	config_get src_ip $1 src_ip -	config_get src_dip $1 src_dip -	config_get src_port $1 src_port -	config_get src_dport $1 src_dport -	config_get src_mac $1 src_mac -	config_get dest_ip $1 dest_ip -	config_get dest_port $1 dest_port -	config_get proto $1 proto -	[ -z "$src" -o -z "$dest_ip" ] && { \ -		echo "redirect needs src and dest_ip"; return ; } - -	src_port_first=${src_port%-*} -	src_port_last=${src_port#*-} -	[ "$src_port_first" != "$src_port_last" ] && { \ -		src_port="$src_port_first:$src_port_last"; } - -	src_dport_first=${src_dport%-*} -	src_dport_last=${src_dport#*-} -	[ "$src_dport_first" != "$src_dport_last" ] && { \ -		src_dport="$src_dport_first:$src_dport_last"; } - -	dest_port2=${dest_port:-$src_dport} -	dest_port_first=${dest_port2%-*} -	dest_port_last=${dest_port2#*-} -	[ "$dest_port_first" != "$dest_port_last" ] && { \ -		dest_port2="$dest_port_first:$dest_port_last"; } - -	add_rule() { -		$IPTABLES -A zone_${src}_prerouting -t nat \ -			${proto:+-p $proto} \ -			${src_ip:+-s $src_ip} \ -			${src_dip:+-d $src_dip} \ -			${src_port:+--sport $src_port} \ -			${src_dport:+--dport $src_dport} \ -			${src_mac:+-m mac --mac-source $src_mac} \ -			-j DNAT --to-destination $dest_ip${dest_port:+:$dest_port} - -		$IPTABLES -I zone_${src}_forward 1 \ -			${proto:+-p $proto} \ -			-d $dest_ip \ -			${src_ip:+-s $src_ip} \ -			${src_port:+--sport $src_port} \ -			${dest_port2:+--dport $dest_port2} \ -			${src_mac:+-m mac --mac-source $src_mac} \ -			-j ACCEPT -	} -	[ "$proto" == "tcpudp" -o -z "$proto" ] && { -		proto=tcp -		add_rule -		proto=udp -		add_rule -		return -	} -	add_rule -} - -fw_include() { -	local path -	config_get path $1 path -	[ -e $path ] && . $path -} - -get_interface_zones() { -	local interface="$2" -	local name -	local network -	config_get name $1 name -	config_get network $1 network -	[ -z "$network" ] && network=$name  -	for n in $network; do -		[ "$n" = "$interface" ] && append add_zone "$name" -	done -} - -fw_event() { -	local action="$1" -	local interface="$2" -	local ifname="$(sh -c ". /etc/functions.sh; include /lib/network; scan_interfaces; config_get "$interface" ifname")" -	add_zone= -	local up - -	[ -z "$ifname" ] && return 0 -	config_foreach get_interface_zones zone "$interface" -	[ -z "$add_zone" ] && return 0 - -	case "$action" in -		ifup) -			for z in $add_zone; do  -				local loaded -				config_get loaded core loaded -				[ -n "$loaded" ] && addif "$interface" "$ifname" "$z" -			done -		;; -		ifdown) -			config_get up "$interface" up - -			for z in $ZONE; do  -				[ "$up" == "1" ] && delif "$interface" "$ifname" "$z" -			done -		;; -	esac -} - -fw_addif() { -	local up -	local ifname -	config_get up $1 up -	[ -n "$up" ] || return 0 -	fw_event ifup "$1" -} - -fw_custom_chains() { -	[ -n "$CUSTOM_CHAINS" ] || return 0 -	$IPTABLES -N input_rule -	$IPTABLES -N output_rule -	$IPTABLES -N forwarding_rule -	$IPTABLES -N prerouting_rule -t nat -	$IPTABLES -N postrouting_rule -t nat - -	$IPTABLES -A INPUT -j input_rule -	$IPTABLES -A OUTPUT -j output_rule -	$IPTABLES -A FORWARD -j forwarding_rule -	$IPTABLES -A PREROUTING -t nat -j prerouting_rule -	$IPTABLES -A POSTROUTING -t nat -j postrouting_rule -} - -fw_custom_chains_zone() { -	local zone="$1" - -	[ -n "$CUSTOM_CHAINS" ] || return 0 -	$IPTABLES -N input_${zone} -	$IPTABLES -N forwarding_${zone} -	$IPTABLES -N prerouting_${zone} -t nat -	$IPTABLES -I zone_${zone} 1 -j input_${zone} -	$IPTABLES -I zone_${zone}_forward 1 -j forwarding_${zone} -	$IPTABLES -I zone_${zone}_prerouting 1 -t nat -j prerouting_${zone} -} - -fw_check_notrack() { -	local zone="$1" -	config_get name "$zone" name -	[ -n "$NOTRACK_DISABLED" ] || \ -		find_item "$name" $CONNTRACK_ZONES || \ -		$IPTABLES -t raw -A zone_${name}_notrack -j NOTRACK -} - -fw_init() { -	DEFAULTS_APPLIED= - -	echo "Loading defaults" -	config_foreach fw_defaults defaults -	echo "Loading zones" -	config_foreach fw_zone zone -	echo "Loading forwarding" -	config_foreach fw_forwarding forwarding -	echo "Loading redirects" -	config_foreach fw_redirect redirect -	echo "Loading rules" -	config_foreach fw_rule rule -	echo "Loading includes" -	config_foreach fw_include include -	echo "Loading zone defaults" -	config_foreach fw_zone_defaults zone -	uci_set_state firewall core loaded 1 -	config_set core loaded 1 -	config_foreach fw_check_notrack zone -	INTERFACES="$(sh -c ' -		. /etc/functions.sh; config_load network -		echo_up() { local up; config_get_bool up "$1" up 0; [ $up = 1 ] && echo "$1"; } -		config_foreach echo_up interface -	')" -	for interface in $INTERFACES; do -		fw_event ifup "$interface" -	done -} - -fw_stop() { -	fw_clear -	$IPTABLES -P INPUT ACCEPT -	$IPTABLES -P OUTPUT ACCEPT -	$IPTABLES -P FORWARD ACCEPT -	uci_revert_state firewall -}  | 
