From c284cb51c00625f52090f3fe3d475450eaab7b21 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 1 May 2010 18:22:01 +0000 Subject: [PATCH] firewall: - replace uci firewall with a modular dual stack implementation developed by Malte S. Stretz - bump version to 2 SVN-Revision: 21286 --- package/firewall/Makefile | 12 +- package/firewall/files/20-firewall | 5 - package/firewall/files/bin/fw | 49 ++ package/firewall/files/firewall.hotplug | 19 + package/firewall/files/firewall.init | 21 +- package/firewall/files/lib/config.sh | 97 ++++ package/firewall/files/lib/core.sh | 136 +++++ package/firewall/files/lib/core_forwarding.sh | 40 ++ package/firewall/files/lib/core_init.sh | 258 +++++++++ package/firewall/files/lib/core_interface.sh | 86 +++ package/firewall/files/lib/core_redirect.sh | 61 ++ package/firewall/files/lib/core_rule.sh | 66 +++ package/firewall/files/lib/fw.sh | 182 ++++++ package/firewall/files/lib/uci_firewall.sh | 5 + package/firewall/files/uci_firewall.sh | 530 ------------------ 15 files changed, 1023 insertions(+), 544 deletions(-) delete mode 100644 package/firewall/files/20-firewall create mode 100644 package/firewall/files/bin/fw create mode 100644 package/firewall/files/firewall.hotplug create mode 100644 package/firewall/files/lib/config.sh create mode 100644 package/firewall/files/lib/core.sh create mode 100644 package/firewall/files/lib/core_forwarding.sh create mode 100644 package/firewall/files/lib/core_init.sh create mode 100644 package/firewall/files/lib/core_interface.sh create mode 100644 package/firewall/files/lib/core_redirect.sh create mode 100644 package/firewall/files/lib/core_rule.sh create mode 100644 package/firewall/files/lib/fw.sh create mode 100644 package/firewall/files/lib/uci_firewall.sh delete mode 100755 package/firewall/files/uci_firewall.sh diff --git a/package/firewall/Makefile b/package/firewall/Makefile index abc6020434..22d359939f 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 4b89326b51..0000000000 --- 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 0000000000..0f83b8eed8 --- /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 "" "" "" "" "" "{" "" "}" + 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 0000000000..fa5643a2bf --- /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 26855f39ad..54742488e8 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 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 +# +# 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() { # + CONFIG_APPEND=1 config_load "$@" + unset CONFIG_APPEND +} + +fw_config_once() { # + 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() { # ... + 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 + +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() { #
{ } + 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 +} diff --git a/package/firewall/files/uci_firewall.sh b/package/firewall/files/uci_firewall.sh deleted file mode 100755 index 8d7538201b..0000000000 --- a/package/firewall/files/uci_firewall.sh +++ /dev/null @@ -1,530 +0,0 @@ -#!/bin/sh -# Copyright (C) 2008 John Crispin - -. /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 -} -- 2.30.2