#!/bin/bash # # firewall-lib firewalling library # # $Id: firewall-lib,v 1.59 2007/07/04 15:18:20 peter Exp $ # # (P) & (C) 2004-2008 by # Dr. Peter Bieringer # AERAsec Network Services and Security GmbH # and # Peter Bieringer # Requirements: # Red Hat Enterprise Linux / CentOS / Fedora Core # RPMs: # - iptables # - iptables-ipv6 (in case of IPv6 is in use) # # OpenWRT: # software packages: # - iptables # - iptables-mod-extra # kernel module packages: # - kmod-ip6tables (in case of IPv6 is in use) # - kmod-ipt-nat-default # - kmod-ipt-extra # Changes: # 20040130/PB: take some parts of firewall-ipv4(wallace) # 20040130/PB: complete redesign as function library # 20041227/PB: migration two versions # 20050111/PB: IPv6 fixes # 20050306/PB: add support for cups/browser # 20050428/PB: add support for ICMP accounting # 20050729/PB: also add https traffic in accHTTP # do not check source ports for accounting (except on FTP) # add support for BITTORRENT # 20050901/PB: improve FTP accounting # add support for NFS, improve DHCP # improve REALAUDIO support # add IPv6 PIM rule # 20050906/PB: add support for dhcpv6-client, support any/icmp # 20051008/PB: add support for IPv6 FTP DATA without conntrack # 20051111/PB: replace use of awk/sed with Bash2 operators # 20060222/PB: improve connection tracking filtering (NEW now requires TCP/SYN set for TCP) # load ip_nat_ftp also now for FTP connection tracking # fix bug in IPv6 connection tracking ruleset (still not used because of missing support) # disable connection tracking for lpr (buggy external print servers) # 20060224/PB: allow also ACK,RST on tcp/RELATED # 20060313/PB: add global variables for workaround selections # introduce pre-post step for accounting, add fallback if missing in config # adjust kernel version for FIREWALL_LIB_WORKAROUND_BUGGY_AMANDA_CONNTRACK # more graceful handling on outgoing late packets # 20060322/PB: silent drop of incoming out-of-state RST packages # 20060403/PB: enable syslog/udp from same src port, fix typo, make difference between 514/udp & tcp # 20060407/PB: add support for FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6 and FIREWALL_LIB_DEBUG # 20060413/PB: src port and special handling of dst port only for action=ACCEPT # 20060426/PB: autodetect availability of REJECT target for IPv6, switch to drop afterwards # map ICMP "echo" to "echo-request", minor improvements # add new funtion firewall_lib_insert_rule_useraddr # 20060503/PB: fix nfs case # 20060809/PB: add support for AH # 20060810/PB: fix ESP and AH and FTP accounting for FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6 # 20060817/PB: [fix] re-add support for proto 'ipv6 (tunneled IPv6) - lost in release 20060809 # 20060821/PB: [enh] add internal support for multiport # [imp] add src port 371 for dst port 370 (F-Secure AV update checker) # 20060928/PB: [enh] workaround for broken connection tracking on NFS # [enh] allow priv src ports for 137/138 # [enh] accept RST packages on established connections # 20070109/PB: [enh] support stateless FTP active data for IPv6 # 20070117/PB: [enh] support 259/udp (Check Point FW-1 RDP) # 20070412/PB: [enh] enable IPv6 connection tracking on kernel >= 2.6.20 # [imp] skip owner match option on not outgoing connection instead of skip whole rule creation # [enh] support icmp type/code as much as possible for FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6 # [enh] support FTP accounting also for IPv6, if connection tracking is available # [enh] introduce 2 new variables for FTP accounting: FIREWALL_LIB_FTP_ACCOUNTING_PASSIVE_PORTS, FIREWALL_LIB_FTP_ACCOUNTING_SERVER_PORTS # [fix] select proper ICMP type/code for IPv6 rejects, support IPv6 tcp-reset only on supported kernels (>= 2.6.14) and fall back to port-unreachable, if needed # [fix] do not set conntrack option in case of any/icmp, makes no sense and is unexpected # 20070529/PB: [enh] add support for OpenWRT, add some extensions and workarounds # 20070702/PB: [fix] syslog/udp does not require backward rule (increase security on stateless filters) # [imp] accounting: skip creation of IPv6 chains in FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6=1 mode # [imp] ICMP limit: rename chain to protocol independed name # 20070704/PB: [imp] do not load already loaded modules # [enh] add support for FIREWALL_LIB_FTP_PASSIVE_PORTS for non-connection tracking FTP rules # 20071124/PB: [imp] add missing rule for ICMPv6 RS # [fix] fix not working connection tracking for DHCPv4 # 20071231/PB: [imp] add missing rule for ICMPv6 RA # 20080106/PB: [imp] load nf_conntrack_tftp if needed # 20080127/PB: [imp] add additonal rules for NFS # 20080204/PB: [imp] add missing rule for ICMPv6 RS # 20080207/PB: [imp] check also nf_-module, if ip_ is specified # 20080212/PB: [imp] load nf_conntrack_sane on demand # [fix] for REALAUDIO, open dst ports on src port 6970 # 20080321/PB: [imp] add icmpv6/131 for ff05::/16 # 20080321/PB: [imp] add workaround for not matching option header on 2.6.9 # 20080729/PB: [adj] remove hop limit = 1 check for icmp 130 # 20080817/PB: [imp] add next ICMPv6/133 # 20080927/PB: [imp] replace use of local port range with high ports for DNS (BIND changes behavior) in outgoing mode # 20090101/PB: [imp] allow also low ports for tftp # 20090217/PB: [fix] fix description in BITTORRENT # 20090217/PB: [fix] allow outgoing UDP source 6881 to nonprivportrange for BITTORRENT # 20090217/PB: [fix] not working *-port-* feature ## Global variables # FIREWALL_LIB_WORKAROUND_BUGGY_AMANDA_CONNTRACK # workaround for buggy amanda IPv4 conntrack module in kernel 2.6.9 (fixed since 2.6.9-22.6) # default: 1 in non fixed versions, must be set explicitly to 0 in config # # FIREWALL_LIB_WORKAROUND_BUGGY_LPR_CONNTRACK # workaround for buggy LPR IPv4 conntrack module in kernel 2.6.9 (at least -5.*EL, -22.*EL) # default: 1, must be set explicitly to 0 in config # # FIREWALL_LIB_FEATURE_IPV4_STATE_SUPPORT # enable/disable state support for IPv4 # default: 1, must be set explicitly to 0 in config to disable # # FIREWALL_LIB_FEATURE_IPV6_STATE_SUPPORT # enable/disable state support for IPv4 # default: 1 (if supported by kernel), must be set explicitly to 0 in config to disable # # FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6 # treat /{tcp,udp} for both protocols (IPv4 and IPv6) # treat /icmp for both protocols (IPv4 and IPv6) as much as possible # default: 0, must be set explicitly to 1 in config # # FIREWALL_LIB_FTP_PASSIVE_PORTS # passive ports for FTP data connection without connection tracking (to be defined in server configuration) # default: 49152:53247 # # FIREWALL_LIB_FTP_ACCOUNTING_PASSIVE_PORTS # passive ports for FTP accounting (to be defined in server configuration) # default: 49152:53247 # # FIREWALL_LIB_FTP_ACCOUNTING_SERVER_PORTS # server ports for FTP accounting # default: "21" # example: "21 4021 4031 4041 4051 4061 4071 4081" # # FIREWALL_LIB_DEBUG # debug library calls # default: 0, must be set explicitly to 1 in config # 0x100 / 256: detected IP version of src and dst address iptables="/sbin/iptables" # Default if [ -x /usr/sbin/iptables ]; then iptables="/usr/sbin/iptables" fi ip6tables="/sbin/ip6tables" # Default if [ -x /usr/sbin/iptables ]; then ip6tables="/usr/sbin/ip6tables" fi SETCOLOR_SUCCESS="echo -en \\033[1;32m" SETCOLOR_ERROR="echo -en \\033[1;31m" SETCOLOR_WARN="echo -en \\033[1;33m" SETCOLOR_NORMAL="echo -en \\033[0;39m" echo_error() { $SETCOLOR_ERROR echo -en "\a" echo "$*" $SETCOLOR_NORMAL } echo_warn() { $SETCOLOR_WARN echo "$*" $SETCOLOR_NORMAL } ## modprobe handling # arg1: module name to load modprobe="modprobe" modprobe() { if /sbin/lsmod | grep -q "^$1 "; then return 0 fi if /sbin/lsmod | grep -q "^${1/ip_/nf_} "; then return 0 fi if [ -x /sbin/modprobe ]; then echo "INFO: load module (modprobe): $1" /sbin/modprobe $1 elif [ -f /etc/openwrt_version -o -x /sbin/insmod ]; then echo "INFO: load module (insmod): $1" /sbin/insmod $1 else echo_error "ERROR: can't load module (missing module loader binary): $1" fi } # Kernel version uname_r="`uname -r`" kversion=${uname_r/-*} i=1 for p in ${kversion//./ }; do kversion_part[i]=$p i=$[ $i + 1 ] done kversion_dist=${uname_r/*-} i=1 for p in ${kversion_dist//./ }; do kversion_dist_part[i]=$p i=$[ $i + 1 ] done ## ICMP mapping # # supported IPv4 ICMP types (iptables 1.3.5): # # any # echo-reply (pong) = # destination-unreachable = # network-unreachable -> no-route # host-unreachable -> address-unreachable # protocol-unreachable # port-unreachable = # fragmentation-needed -> packet-too-big # source-route-failed # network-unknown # host-unknown # network-prohibited # host-prohibited # TOS-network-unreachable # TOS-host-unreachable # communication-prohibited = # host-precedence-violation # precedence-cutoff # source-quench # redirect = # network-redirect # host-redirect -> redirect # TOS-network-redirect # TOS-host-redirect # echo-request (ping) = # router-advertisement = # router-solicitation = # time-exceeded (ttl-exceeded) = # ttl-zero-during-transit = # ttl-zero-during-reassembly = # parameter-problem = # ip-header-bad -> bad-header # required-option-missing # timestamp-request # timestamp-reply # address-mask-request # address-mask-reply # # supported IPv6 ICMP types (ip6tables 1.3.5): # destination-unreachable = # no-route <- network-unreachable # communication-prohibited = # address-unreachable <- host-unreachable # port-unreachable = # packet-too-big <- fragmentation-needed # time-exceeded (ttl-exceeded) = # ttl-zero-during-transit = # ttl-zero-during-reassembly = # parameter-problem = # bad-header <- ip-header-bad # unknown-header-type # unknown-option # echo-request (ping) = # echo-reply (pong) = # router-solicitation = # router-advertisement = # neighbour-solicitation (neighbor-solicitation) # neighbour-advertisement (neighbor-advertisement) # redirect = & <- host-redirect # # Convert ICMPv4 type to IPv6, if supported icmp_conv_ipv4_to_ipv6() { local icmp_type_ipv4="$1" local icmp_type_ipv6="" case "$icmp_type_ipv4" in 'any') # no conversion needed local icmp_type_ipv6="$icmp_type_ipv4" ;; 'echo') # iptables is more relaxed than ip6tables local icmp_type_ipv6="echo-request" ;; 'echo-request'|'echo-reply') # no conversion needed local icmp_type_ipv6="$icmp_type_ipv4" ;; 'port-unreachable'|'communication-prohibited'|'destination-unreachable') # no conversion needed local icmp_type_ipv6="$icmp_type_ipv4" ;; 'time-exceeded'|'ttl-zero-during-transit'|'ttl-zero-during-reassembly') # no conversion needed local icmp_type_ipv6="$icmp_type_ipv4" ;; 'router-solicitation'|'router-advertisement') # no conversion needed local icmp_type_ipv6="$icmp_type_ipv4" ;; 'host-unreachable') # best match local icmp_type_ipv6="address-unreachable" ;; 'network-unreachable') # best match local icmp_type_ipv6="no-route" ;; 'fragmentation-needed') # best match local icmp_type_ipv6="packet-too-big" ;; 'redirect') # no conversion needed local icmp_type_ipv6="$icmp_type_ipv4" ;; 'host-redirect') # no conversion needed local icmp_type_ipv6="redirect" ;; 'parameter-problem') # no conversion needed local icmp_type_ipv6="$icmp_type_ipv4" ;; 'ip-header-bad') # no conversion needed local icmp_type_ipv6="bad-header" ;; *) echo ;; esac echo "$icmp_type_ipv6" if [ -z "$icmp_type_ipv6" ]; then return 1 else return 0 fi } ## Check for IPv6 # Options # (none) # Return code # 0: IPv6 is enabled on this host # 1: IPv6 is not enabled on this host firewall_check_ipv6() { if [ -f /proc/net/if_inet6 ]; then return 0 else return 1 fi } # Debug if [ -z "$FIREWALL_LIB_DEBUG" ]; then FIREWALL_LIB_DEBUG=0 else if [ $FIREWALL_LIB_DEBUG -gt 0 ]; then echo "DEBUG : debug value: $FIREWALL_LIB_DEBUG" fi fi # IPv4 state support if [ "$FIREWALL_LIB_FEATURE_IPV4_STATE_SUPPORT" = "0" ]; then state_support_ipv4=0 else state_support_ipv4=1 fi # IPv6 state support if [ "$FIREWALL_LIB_FEATURE_IPV6_STATE_SUPPORT" = "0" ]; then state_support_ipv6=0 else # IPv6 connection tracking is supported since 2.6.20 if [ ${kversion_part[1]} -ge 2 -a ${kversion_part[2]} -ge 6 -a ${kversion_part[3]} -ge 20 ]; then state_support_ipv6=1 else state_support_ipv6=0 fi fi # Passive ports for FTP if [ -z "$FIREWALL_LIB_FTP_PASSIVE_PORTS" ]; then FIREWALL_LIB_FTP_PASSIVE_PORTS="49152:53247" fi # Passive ports for FTP accounting if [ -z "$FIREWALL_LIB_FTP_ACCOUNTING_PASSIVE_PORTS" ]; then FIREWALL_LIB_FTP_ACCOUNTING_PASSIVE_PORTS="49152:53247" fi # Server ports for FTP accounting if [ -z "$FIREWALL_LIB_FTP_ACCOUNTING_SERVER_PORTS" ]; then FIREWALL_LIB_FTP_ACCOUNTING_SERVER_PORTS="21" fi ## Global flags depending on kernel version if [ "$kversion" = "2.6.9" ]; then if [ ${kversion_dist_part[1]} -gt 22 ]; then true elif [ ${kversion_dist_part[1]} -eq 22 -a ${kversion_dist_part[2]} -ge 6 ]; then true else # * Mon Oct 24 2005 Jason Baron [2.6.9-22.6] # -fix packet corruption in ip_conntrack_amanda (Jeff Layton) [152036] # workaround for kernel version < 2.6.9-22.6 FIREWALL_LIB_WORKAROUND_BUGGY_AMANDA_CONNTRACK=1 fi FIREWALL_LIB_WORKAROUND_BUGGY_LPR_CONNTRACK=1 fi ## Local Flags # conntrack module already loaded flag_load_module_ipv4_conntrack=0 flag_load_module_ipv6_conntrack=0 # accounting ruleset pre/post step flag_firewall_ipv4_add_accounting_ruleset_prepost=0 flag_firewall_ipv6_add_accounting_ruleset_prepost=0 # IPv6 reject target available flag_ip6tables_support_target_reject=1 ## Check for IPv6 address # Options # (none) # Return code # 0: unspecified (any) # 4: is a IPv4 address # 6: is a IPv6 address # 9: unknown firewall_get_address_proto() { if [ "$1" = "any" ]; then return 0 fi # very simple check for 3 dots if [ "${1//[0-9\/]/}" = "..." ]; then return 4 fi return 6 } ## Execute iptables, show rule if error occurs # Options # $*: arguments to iptables # Return code # (return code of iptables) firewall_iptables() { local arguments="$*" #echo "DEBUG(iptables): $rule" #local OUTPUT="`$iptables $rule`" firewall_init_basics IPv4 $iptables $arguments if [ "$FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6" = "1" ]; then if firewall_check_ipv6; then # map IPv4 to IPv6 for dedicated commands case $1 in '--new-chain'|'-N') echo "execute command also for ip6tables: $*" firewall_ip6tables $* ;; esac fi fi if [ $? -gt 0 ]; then echo "FW4: iptables: Error executing: $arguments" return 1 fi } ## Execute ip6tables, show rule if error occurs # Options # $*: arguments to ip6tables # Return code # (return code of ip6tables) firewall_ip6tables() { if ! firewall_check_ipv6; then return 0 fi local arguments="$*" #echo "DEBUG(ip6tables): $rule" #local OUTPUT="`$ip6tables $rule`" firewall_init_basics IPv6 $ip6tables $arguments if [ $? -gt 0 ]; then echo "FW6: ip6tables: Error executing: $arguments" return 1 fi } ## Local checks if firewall_check_ipv6; then # Check for reject target firewall_ip6tables -A FORWARD -s ::1 -d ::1 -j REJECT >/dev/null 2>&1 if [ $? -ne 0 ]; then flag_ip6tables_support_target_reject=0 fi fi ## Get local port range and set variable # Options # (none) # Return code # 0: ok # 1: problem # Environment # firewall_local_portrange=start:stop firewall_get_local_portrange() { if [ -n "$firewall_local_portrange" ]; then return fi if [ -f /proc/sys/net/ipv4/ip_local_port_range ]; then local startstop="`cat /proc/sys/net/ipv4/ip_local_port_range`" local start="`echo "$startstop" | cut -f 1`" local stop="`echo "$startstop" | cut -f 2`" else echo_error "ERROR: can't retrieve 'ip_local_port_range'" return 1 fi firewall_local_portrange="${start}:${stop}" return 0 } ## Check firewalling # Options # $1: [IPv4|IPv6] (optional) # Return code # 0: ok (or IPv6 skipped) # 3: IP protocol version not supported # 4: no firewalling for IP protocol supported firewall_init_basics() { local ip="$1" if [ -z "$ip" ]; then # Run through all available protocols firewall_init_basics IPv4 || return $? firewall_init_basics IPv6 || return $? return fi case "$ip" in '4'|'IPv4'|'ipv4') local table_names="/proc/net/ip_tables_names" local table_matches="/proc/net/ip_tables_matches" local table_targets="/proc/net/ip_tables_targets" local module_tables="ip_tables" local modules_names="iptable_filter iptable_nat" local modules_matches="ipt_owner ipt_limit" local modules_targets="ipt_LOG" local proto=4 ;; '6'|'IPv6'|'ipv6') if ! firewall_check_ipv6; then return 0 fi local table_names="/proc/net/ip6_tables_names" local table_matches="/proc/net/ip6_tables_matches" local table_targets="/proc/net/ip6_tables_targets" local module_tables="ip6_tables" local modules_names="ip6table_filter" local modules_matches="ip6t_owner ip6t_limit" local modules_targets="ip6t_LOG" local proto=6 ;; *) echo_error "ERROR: unsupported IP protocol version: $ip" return 3 ;; esac local name="firewall_init_basics_${proto}" if [ "${!name}" == "1" ]; then # already done return 0 fi if [ ! -f $table_names ]; then $modprobe $module_tables if [ $? -ne 0 ]; then echo_error "ERROR: can't load required module: $module_tables" return 4 fi fi # Check for basic modules for module in $modules_names; do if [ -f $table_names ]; then if grep -q "${module/*_}" $table_names; then continue fi fi $modprobe $module if [ $? -ne 0 ]; then echo_error "ERROR: can't load required module: $module" return 4 fi done # Check for target modules for module in $modules_targets; do if [ -f $table_targets ]; then if grep -q "${module/*_}" $table_targets; then continue fi fi $modprobe $module if [ $? -ne 0 ]; then echo_error "ERROR: can't load required module: $module" return 4 fi done # Check for match modules for module in $modules_matches; do if [ -f $table_matches ]; then if grep -q "${module/*_}" $table_matches; then continue fi fi $modprobe $module if [ $? -ne 0 ]; then echo_error "ERROR: can't load required module: $module" return 4 fi done # Set flag let ${name}=1 return 0 } ## Remove all rules from rulebase # Options # $1: [IPv4|IPv6] (optional) # Return code # 0: ok (or IPv6 skipped) # 3: IP protocol version not supported firewall_remove_rules() { local ip="$1" if [ -z "$ip" ]; then # Run through all available protocols firewall_remove_rules IPv4 || return $? firewall_remove_rules IPv6 || return $? return fi case "$ip" in '4'|'IPv4'|'ipv4') local table_names="/proc/net/ip_tables_names" local iptables_call="iptables" local prefix="FW4" ;; '6'|'IPv6'|'ipv6') if ! firewall_check_ipv6; then return fi local table_names="/proc/net/ip6_tables_names" local iptables_call="ip6tables" local prefix="FW6" ;; *) echo_error "ERROR: unsupported IP protocol version: $ip" return 3 ;; esac # Do the work echo -n "$prefix: remove all rules from table:" cat $table_names | while read table; do echo -n " $table" $iptables_call -t $table -F done echo # Get list of user defined chains cat $table_names | while read table; do echo -n "$prefix: delete user chains in table $table:" case $table in 'filter') $iptables_call -t $table -n -L | grep "^Chain" | cut -d " " -f 2 | egrep -v 'INPUT|FORWARD|OUTPUT' | while read chain; do echo -n " $chain" $iptables_call -t $table -X $chain done ;; 'nat') $iptables_call -t $table -n -L | grep "^Chain" | cut -d " " -f 2 | egrep -v 'PREROUTING|POSTROUTING|OUTPUT' | while read chain; do echo -n " $chain" $iptables_call -t $table -X $chain done ;; 'mangle') $iptables_call -t $table -n -L | grep "^Chain" | cut -d " " -f 2 | egrep -v 'PREROUTING|POSTROUTING|INPUT|FORWARD|OUTPUT' | while read chain; do echo -n " $chain" $iptables_call -t $table -X $chain done ;; *) echo_error "ERROR: unsupported table: $table" return 3 ;; esac echo done echo } ## Insert a rule # Options # $1: direction: incoming|outgoing|forwarding # $2: chain name # $3: portproto combination: port/proto # port: number,name(resolvable by /etc/services),icmp-type # proto: # tcp,udp (depending on FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6 # rules for IPv4 *and* IPv6 would be created) # proto: icmp (TODO: also dual protocol treatment) # proto: tcp4,udp4,tcp6,udp6,icmp4,icmp6 # special: all, all4, all6 # $4: source address # $5: destination address # $6: action # $7: additional options # Return code # 0: ok (or IPv6 skipped) # 3: Parameter not supported # 5: Missing parameter firewall_insert_rule() { local fn="firewall_insert_rule" local direction="$1" shift local chain="$1" shift local portproto="$1" shift local src="$1" shift local dst="$1" shift local action="$1" shift local options="$*" if [ -z "$direction" ]; then echo_error "ERROR: missing direction (arg1)" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 5 fi if [ -z "$chain" ]; then echo_error "ERROR: missing chain name (arg2)" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 5 fi if [ -z "$portproto" ]; then echo_error "ERROR: missing port/protocol name (arg3)" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 5 fi if [ -z "$src" ]; then echo_error "ERROR: missing src address (arg4)" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 5 fi if [ -z "$dst" ]; then echo_error "ERROR: missing dst address (arg5)" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 5 fi if [ -z "$action" ]; then echo_error "ERROR: missing action (arg6)" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 5 fi # split portproto local dport="${portproto/\/*}" local proto="${portproto/$dport}" local proto="${proto/\/}" # Get local port range if [ -z "$firewall_local_portrange" ]; then firewall_get_local_portrange fi # Shift (e.g. "all") if [ -z "$proto" ]; then local proto="$dport" local dport="" fi # split chain local chain_init="${chain/\/*}" local chain_back="${chain/$chain_init}" local chain_back="${chain_back/\/}" # get type of addresses firewall_get_address_proto $src local src_proto=$? firewall_get_address_proto $dst local dst_proto=$? if [ $[ $FIREWALL_LIB_DEBUG & 256 ] -ne 0 ]; then if [ $src_proto -ne 0 -o $dst_proto -ne 0 ]; then echo "DEBUG : detected IP protocols src $src=$src_proto dst $dst=$dst_proto" fi fi # check for IPv4 or IPv6 local ip="4" case $proto in 'any') if [ "$FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6" = "1" ]; then if [ \( $src_proto -eq 0 -o $src_proto -eq 4 \) -a \( $dst_proto -eq 0 -o $dst_proto -eq 4 \) ]; then firewall_insert_rule ${direction} $chain "${portproto}4" $src $dst $action $options fi if [ \( $src_proto -eq 0 -o $src_proto -eq 6 \) -a \( $dst_proto -eq 0 -o $dst_proto -eq 6 \) ]; then firewall_insert_rule ${direction} $chain "${portproto}6" $src $dst $action $options fi if [ $src_proto -eq 9 -o $dst_proto -eq 9 ]; then echo_error "ERROR: can't recognize protocol of src/dst addresses: $src - $dst" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 3 fi return else local ip="4" fi ;; 'any4') local ip="4" local proto="${proto%4}" ;; 'any6') local ip="6" local proto="${proto%6}" ;; 'esp6'|'ah6'|'ipv6-auth6') local ip="6" local proto="${proto%6}" local state_support_ipv6=0 ;; 'icmp6') local ip="6" local proto="ipv6-icmp" ;; 'ipv6-icmp') local ip="6" ;; 'tcp6'|'udp6'|'all6'|'all6'|'esp6'|'ah6'|'ipv6-auth6') local ip="6" local proto="${proto%6}" ;; 'tcp4'|'udp4'|'icmp4'|'all4'|'esp4'|'ah4'|'ipv6-auth4') local ip="4" local proto="${proto%4}" ;; 'tcp'|'udp'|'all'|'esp'|'ah'|'ipv6-auth') if [ "$FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6" = "1" ]; then if [ \( $src_proto -eq 0 -o $src_proto -eq 4 \) -a \( $dst_proto -eq 0 -o $dst_proto -eq 4 \) ]; then firewall_insert_rule ${direction} $chain "${portproto}4" $src $dst $action $options fi if [ \( $src_proto -eq 0 -o $src_proto -eq 6 \) -a \( $dst_proto -eq 0 -o $dst_proto -eq 6 \) ]; then firewall_insert_rule ${direction} $chain "${portproto}6" $src $dst $action $options fi if [ $src_proto -eq 9 -o $dst_proto -eq 9 ]; then echo_error "ERROR: can't recognize protocol of src/dst addresses: $src - $dst" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 3 fi return else local ip="4" fi ;; 'icmp') if [ "$FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6" = "1" ]; then if [ \( $src_proto -eq 0 -o $src_proto -eq 4 \) -a \( $dst_proto -eq 0 -o $dst_proto -eq 4 \) ]; then firewall_insert_rule ${direction} $chain "${portproto}4" $src $dst $action $options fi if [ \( $src_proto -eq 0 -o $src_proto -eq 6 \) -a \( $dst_proto -eq 0 -o $dst_proto -eq 6 \) ]; then local icmp_type_ipv4="${portproto/\/icmp}" local icmp_type_ipv6="`icmp_conv_ipv4_to_ipv6 ${icmp_type_ipv4}`" if [ -n "$icmp_type_ipv6" ]; then firewall_insert_rule ${direction} $chain "${icmp_type_ipv6}/icmp6" $src $dst $action $options else echo_error "ERROR: ICMPv4 type $icmp_type_ipv4 can't be converted to ICMPv6" fi fi if [ $src_proto -eq 9 -o $dst_proto -eq 9 ]; then echo_error "ERROR: can't recognize protocol of src/dst addresses: $src - $dst" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 3 fi return else local ip="4" fi ;; 'igmp') local ip="4" ;; 'tcp4'|'udp4'|'icmp4'|'all4') local ip="4" local proto="${proto%4}" ;; 'esp'|'ipv6') local ip="4" local state_support_ipv4=0 ;; 'REALAUDIO') # RTSP (port 554/tcp) firewall_insert_rule ${direction} $chain rtsp/tcp $src $dst $action # RTSP (port 554/udp) firewall_insert_rule ${direction} $chain rtsp/udp $src $dst $action # port 5050/tcp firewall_insert_rule ${direction} $chain 5050/tcp $src $dst $action # port 7070/tcp firewall_insert_rule ${direction} $chain 7070/tcp $src $dst $action return ;; 'BITTORRENT') # Traffic firewall_insert_rule ${direction} $chain 6881:7002/tcp $src $dst $action # Notifications firewall_insert_rule ${direction}-equal $chain 6881/udp $src $dst $action firewall_insert_rule ${direction}-port-6881 $chain 1:65535/udp $src $dst $action return ;; 'NFS') if [ "$kversion" = "2.6.9" ]; then # broken connection tracking local state_support_ipv4=0 fi # to nfs tcp & udp firewall_insert_rule ${direction} $chain nfs/tcp $src $dst $action firewall_insert_rule ${direction} $chain nfs/udp $src $dst $action # to fixed rpc.mountd tcp&udp firewall_insert_rule ${direction}-priv $chain 892/tcp $src $dst $action firewall_insert_rule ${direction} $chain 892/tcp $src $dst $action firewall_insert_rule ${direction}-priv $chain 892/udp $src $dst $action firewall_insert_rule ${direction} $chain 892/udp $src $dst $action # to fixed rpc.statd tcp&udp firewall_insert_rule ${direction}-priv $chain 662/tcp $src $dst $action firewall_insert_rule ${direction}-priv $chain 662/udp $src $dst $action # to fixed rpc.rquotad tcp&udp firewall_insert_rule ${direction}-priv $chain 875/tcp $src $dst $action firewall_insert_rule ${direction}-priv $chain 875/udp $src $dst $action # to fixed rpc.lockd tcp&udp firewall_insert_rule ${direction}-priv $chain 32803/tcp $src $dst $action firewall_insert_rule ${direction}-priv $chain 32769/udp $src $dst $action # to privportrange/tcp #firewall_insert_rule ${direction}-priv $chain privportrange/tcp $src $dst $action #firewall_insert_rule ${direction} $chain privportrange/tcp $src $dst $action # to privportrange/udp #firewall_insert_rule ${direction}-priv $chain privportrange/udp $src $dst $action #firewall_insert_rule ${direction} $chain privportrange/udp $src $dst $action # to RPC ports from privportrange/tcp #firewall_insert_rule ${direction}-priv $chain nonprivportrange/tcp $src $dst $action # to RPC ports from privportrange/udp #firewall_insert_rule ${direction}-priv $chain nonprivportrange/udp $src $dst $action return ;; *) echo_error "ERROR: unsupported protocol: $proto" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 3 ;; esac # Disable state support case $proto in 'esp'|'ah'|'ipv6-auth'|'ipv6') case $ip in '4') local state_support_ipv4=0 ;; '6') local state_support_ipv6=0 ;; esac ;; esac # Remap action, if not available if [ "$ip" = "6" -a $flag_ip6tables_support_target_reject -eq 0 -a "$action" = "REJECT" ]; then echo "target REJECT for IPv6 not supported on this system, use DROP for now" action="DROP" fi # Map special port keywords case $dport in 'localportrange') # set local port range local dport="$firewall_local_portrange" ;; 'privportrange') # set priv port range local dport="512:1023" ;; 'nonprivportrange') # set priv port range local dport="1024:65535" ;; 'TRACEROUTE') local sport="$firewall_local_portrange" local dport="33434:33499" ;; esac # Catch/remap TCP/UDP issues (only in ACCEPT case) if [ \( "$proto" = "udp" -o "$proto" = "tcp" \) -a "$action" = "ACCEPT" ]; then # set default sender ports case $direction in outgoing-port-*|incoming-port-*|forwarding-port-*) local sport="${direction/*-port-}" ;; 'incoming-no-sport'|'forwarding-no-sport'|'outgoing-no-sport') local sport="" ;; 'incoming'|'forwarding') local sport="1024:65535" ;; 'outgoing') local sport="$firewall_local_portrange" ;; 'incoming-priv'|'outgoing-priv'|'forwarding-priv') local sport="512:1023" ;; 'incoming-equal'|'outgoing-equal'|'forwarding-equal') local sport="$dport" ;; *) echo_error "ERROR: unsupported direction: $direction" echo "Called: $fn $direction $chain $portproto $src $dst $action $options" return 3 ;; esac # catch special ports I case $dport in 'syslog'|'514') if [ "$proto" = "udp" ]; then # Disable backward rule, not needed local chain_back="" fi ;; esac # catch special ports II case $direction in 'incoming'|'outgoing'|'forwarding') case $dport in "$firewall_local_portrange") firewall_insert_rule ${direction}-priv $chain $portproto $src $dst $action $options ;; '512:1023') firewall_insert_rule ${direction}-priv $chain $portproto $src $dst $action $options ;; 'ssh'|'22') # secure shell # need an additional rule if [ "$direction" = "incoming" ]; then local options_limit="--match limit --limit 5/minute --limit-burst 1" fi # need an additional rule firewall_insert_rule ${direction}-priv $chain $portproto $src $dst $action $options ;; 'domain'|'53') # rewrite source ports local sport="1024:65535" ;; '259') # Check Point FW-1 Reliable Data Protocol (RDP) if [ "$proto" = "udp" ]; then local sport="259" fi ;; 'shell'|'514') if [ "$proto" = "tcp" ]; then # rshell # rewrite source ports local sport="512:1023" fi ;; 'syslog'|'514') if [ "$proto" = "udp" ]; then # syslog # need an additional rule firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options fi ;; 'printer'|515) # lpr if [ "$FIREWALL_LIB_WORKAROUND_BUGGY_LPR_CONNTRACK" = "1" ]; then # broken connection to some external printer spooler at least in this kernel version #if [ `sysctl -n net.ipv4.netfilter.ip_conntrack_tcp_be_liberal` -ne 1 ]; then # sysctl won't help # echo "NOITCE: set net.ipv4.netfilter.ip_conntrack_tcp_be_liberal=1 to support broken external printer spoolers" # sysctl -w net.ipv4.netfilter.ip_conntrack_tcp_be_liberal=1 #fi # buggy LPR produces invalid state packages echo_warn "WARN: disable state support for broken connection tracking of lpr" local state_support_ipv4=0 fi firewall_insert_rule ${direction}-priv $chain $portproto $src $dst $action $options ;; 'sunrpc'|'111') # need an additional rule firewall_insert_rule ${direction}-priv $chain $portproto $src $dst $action $options ;; 'nfs'|'2049') # need an additional rule firewall_insert_rule ${direction}-priv $chain $portproto $src $dst $action $options if [ "$kversion" = "2.6.9" ]; then # broken connection tracking local state_support_ipv4=0 fi ;; 'bootps'|'67') if [ "$ip" != "4" ]; then # IPv4 only return fi # DHCP request # rewrite source ports local sport="68" # connection tracking won't work for this local state_support_ipv4=0 ;; 'bootpc'|'68') if [ "$ip" != "4" ]; then # IPv4 only return fi # DHCP replies # rewrite source ports local sport="67" # connection tracking won't work for this local state_support_ipv4=0 ;; 'dhcpv6-server'|'547'|'dhcpv6-client'|'546') # DHCPv6 request, reply # rewrite source ports local sport="$dport" ;; 'amanda'|'10080') # amanda backup if [ "$FIREWALL_LIB_WORKAROUND_BUGGY_AMANDA_CONNTRACK" = "1" ]; then echo_warn "WARN: add workaround for broken connection tracking of amanda" firewall_insert_rule ${direction} $chain nonprivportrange/tcp $src $dst $action $options fi # rewrite source ports local sport="512:1023" ;; 'ntp'|'123') # network time protocol # need an additional ruleset firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options ;; 'domain'|'53') # DNS # need an additional ruleset firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options ;; 'netbios-ns'|'137'|'netbios-dgm'|'138') # netbios-* # need additional rulesets firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options firewall_insert_rule ${direction}-priv $chain $portproto $src $dst $action $options ;; 'isakmp'|'500') # IKE # need an additional ruleset firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options ;; '3483') # SlimServer # need an additional ruleset firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options ;; 'ftp'|'21') # FTP # need an additional ruleset local check="state_support_ipv${ip}" if [ "$proto" = "tcp" -a ${!check} -ne 1 ]; then echo_warn "WARN: add workaround for not available connection tracking of FTP for IPv${ip} (use destination ports: $FIREWALL_LIB_FTP_PASSIVE_PORTS)" ## Passive FTP data connection firewall_insert_rule ${direction} $chain $FIREWALL_LIB_FTP_PASSIVE_PORTS/tcp${ip} $src $dst $action ## Active FTP data connection case ${direction} in 'incoming') local rdirection="outgoing" ;; 'outgoing') local rdirection="incoming" ;; 'forwarding') local rdirection="forwarding" ;; esac firewall_insert_rule ${rdirection}-no-sport ${chain_back} nonprivportrange/tcp${ip} $src $dst $action --sport 20 firewall_insert_rule ${direction} ${chain_init} 20/tcp${ip} $src $dst $action ! --syn fi ;; '370') # F-Secure automatic update if [ "$proto" = "udp" ]; then local sport="371,9370" fi ;; '69'|'tftp') # tftp # need an additional ruleset firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options ;; '631'|'ipp') # cups # need an additional ruleset firewall_insert_rule ${direction}-equal $chain $portproto $src $dst $action $options ;; '554'|'rtsp') # Real Audio if [ "$proto" = "udp" ]; then local sport="6970" local dport="1024:65535" fi ;; 'any') # Shortcut local dport="" ;; esac ;; esac fi # fix src / dst / dport case "$ip" in '4') if [ "$src" = "any" ]; then local src="0.0.0.0/0" fi if [ "$dst" = "any" ]; then local dst="0.0.0.0/0" fi ;; '6') if [ "$src" = "any" ]; then local src="::/0" fi if [ "$dst" = "any" ]; then local dst="::/0" fi if [ "$proto" = "ipv6-icmp" -a "$dport" = "echo" ]; then local dport="echo-request" fi ;; esac # additionals for action case "$action" in 'REJECT'|'DROP') case "$proto" in 'tcp'|'udp') local sport="" ;; esac ;; esac case "$action" in 'REJECT') case "$proto" in 'tcp') case "$ip" in '4') local options2="${options2} --reject-with tcp-reset" ;; '6') # according to ip6tables man page, tcp-reset is only supported on kernel >= 2.6.14 if [ ${kversion_part[1]} -ge 2 -a ${kversion_part[2]} -ge 6 -a ${kversion_part[3]} -ge 14 ]; then local options2="${options2} --reject-with tcp-reset" else local options2="${options2} --reject-with icmp6-port-unreachable" fi ;; esac ;; 'udp') case "$ip" in '4') local options2="${options2} --reject-with icmp-port-unreachable" ;; '6') local options2="${options2} --reject-with icmp6-port-unreachable" ;; esac ;; 'any') # Add rule for tcp protocol firewall_insert_rule ${direction} $chain tcp $src $dst $action $options # Add rule for udp protocol firewall_insert_rule ${direction} $chain udp $src $dst $action $options # Add rule for other protocols case "$ip" in '4') local options2="${options2} --reject-with icmp-proto-unreachable" ;; '6') # IPv6 addr-unreachable is the best match for IPv4 proto-unreachable local options2="${options2} --reject-with icmp6-addr-unreachable" ;; esac ;; esac ;; esac ## additionals for proto icmp # remaps case "$proto" in 'icmp') case "$dport" in 'echo') local dport="echo-request" ;; esac ;; esac case "$proto" in 'icmp') case "$dport" in 'echo-request') local sport="echo-reply" ;; 'any') local dport="" ;; esac ;; 'ipv6-icmp') case "$dport" in 'echo-request') local sport="echo-reply" ;; 'any') local dport="" ;; esac ;; esac if [ -n "$proto" ]; then if [ "$proto" != "any" -a "$proto" != "any6" ]; then local option_proto="-p $proto" fi fi local flag_multiport=0 if [ "$proto" = "udp" -o "$proto" = "tcp" ]; then if [ -n "$sport" ]; then if [ "$sport" = "${sport//,}" ]; then local option_sport="--sport $sport" local option_dport_back="--dport $sport" else local options4="--match multiport --sports $sport" local options4_back="--match multiport --dports $sport" local flag_multiport=1 fi fi if [ -n "$dport" ]; then if [ "$dport" = "${dport//,}" ]; then local option_dport="--dport $dport" local option_sport_back="--sport $dport" else if [ $flag_multiport -ne 1 ]; then local options4="--match multiport" local options4_back="--match multiport" fi local options4="$options4 --dports $dport" local options4_back="$option4_back --sports $dport" fi fi fi # Create rules if [ -n "$chain_init" ]; then firewall_init_basics $ip case "$ip" in '4') if [ "$action" = "ACCEPT" -a $state_support_ipv4 -eq 1 ]; then # put initial state rule into #echo "DEBUG: check for state rule" local name="ssipv4a_${chain_init}" if [ -z "${!name}" ]; then if [ $flag_load_module_ipv4_conntrack -ne 1 ]; then # Load conntrack module if [ ! -f /proc/net/ip_conntrack ]; then $modprobe ip_conntrack fi flag_load_module_ipv4_conntrack=1 fi # create ESTABLISHED,RELATED rules firewall_iptables -A $chain_init -p tcp --tcp-flags ACK ACK --match state --state ESTABLISHED -j ACCEPT firewall_iptables -A $chain_init -p tcp --tcp-flags SYN,FIN,ACK,RST RST --match state --state ESTABLISHED -j ACCEPT firewall_iptables -A $chain_init -p tcp --tcp-flags FIN,SYN,RST,ACK SYN --match state --state RELATED -j ACCEPT firewall_iptables -A $chain_init -p tcp --tcp-flags FIN,SYN,RST,ACK ACK,RST --match state --state RELATED -j ACCEPT firewall_iptables -A $chain_init -p udp --match state --state ESTABLISHED -j ACCEPT firewall_iptables -A $chain_init -p udp --match state --state RELATED -j ACCEPT firewall_iptables -A $chain_init --match state --state ESTABLISHED -j ACCEPT firewall_iptables -A $chain_init --match state --state RELATED -j ACCEPT # Set flag let ssipv4a_${chain_init}=1 #echo #echo "FW4: insert state match rule ESTABLISHED,RELATED on chain: ${chain_init}" fi # Define protocol related options if [ "$proto" = "udp" ]; then local options3="$option_sport $option_dport --match state --state NEW" elif [ "$proto" = "tcp" ]; then local options3="$option_sport $option_dport --tcp-flags FIN,SYN,RST,ACK SYN --match state --state NEW" elif [ "$proto" = "icmp" ]; then if [ -n "$dport" ]; then local options3="--icmp-type $dport" fi elif [ "$proto" = "esp" -o "$proto" = "ipv6" -o "$proto" = "any" ]; then local options3="" else local options3="--match state --state NEW" fi # Append rule firewall_iptables -A $chain_init $option_proto -s $src -d $dst -j $action $options $options2 $options3 $options4 # Check for additional helper modules case "$dport" in 'ftp'|'21') $modprobe ip_conntrack_ftp $modprobe ip_nat_ftp ;; 'tftp'|'69') $modprobe ip_conntrack_tftp $modprobe ip_nat_tftp ;; 'sane-port'|'6566') $modprobe nf_conntrack_sane ;; 'amanda'|'10080') if [ "$FIREWALL_LIB_WORKAROUND_BUGGY_AMANDA_CONNTRACK" = "1" ]; then $modprobe --remove ip_conntrack_amanda else $modprobe ip_conntrack_amanda fi ;; esac else # Define protocol related options if [ "$proto" = "udp" -o "$proto" = "tcp" ]; then local options3="$option_sport $option_dport" elif [ "$proto" = "icmp" -a -n "$dport" ]; then local options3="--icmp-type $dport" fi # Append rule firewall_iptables -A $chain_init $option_proto -s $src -d $dst -j $action $options $options2 $options3 $options4 fi ;; '6') if ! firewall_check_ipv6; then return fi if [ "$action" = "ACCEPT" -a $state_support_ipv6 -eq 1 ]; then # put initial state rule into local name="ssipv6a_${chain_init}" if [ -z "${!name}" ]; then # create ESTABLISHED,RELATED rules firewall_ip6tables -A $chain_init -p tcp --tcp-flags ACK ACK --match state --state ESTABLISHED -j ACCEPT firewall_ip6tables -A $chain_init -p tcp --tcp-flags FIN,SYN,RST,ACK SYN --match state --state RELATED -j ACCEPT firewall_ip6tables -A $chain_init -p tcp --tcp-flags FIN,SYN,RST,ACK ACK,RST --match state --state RELATED -j ACCEPT firewall_ip6tables -A $chain_init -p udp --match state --state ESTABLISHED -j ACCEPT firewall_ip6tables -A $chain_init -p udp --match state --state RELATED -j ACCEPT firewall_ip6tables -A $chain_init --match state --state ESTABLISHED -j ACCEPT firewall_ip6tables -A $chain_init --match state --state RELATED -j ACCEPT let ssipv6a_${chain_init}=1 #echo "FW6: insert state match rule ESTABLISHED,RELATED on chain: ${chain_init}" fi # Define protocol related options if [ "$proto" = "udp" ]; then local options3="$option_sport $option_dport --match state --state NEW" elif [ "$proto" = "tcp" ]; then local options3="$option_sport $option_dport --tcp-flags FIN,SYN,RST,ACK SYN --match state --state NEW" elif [ "$proto" = "ipv6-icmp" ]; then if [ -n "$dport" ]; then local options3="--icmpv6-type $dport" fi elif [ "$proto" = "esp" -o "$proto" = "ipv6" -o "$proto" = "any" ]; then local options3="" else local options3="--match state --state NEW" fi case "$dport" in 'ftp'|'21') $modprobe nf_conntrack_ftp ;; 'tftp'|'69') $modprobe nf_conntrack_tftp ;; esac # Append rule firewall_ip6tables -A $chain_init $option_proto -s $src -d $dst -j $action $options $options2 $options3 $options4 else # Define protocol related options if [ "$proto" = "udp" -o "$proto" = "tcp" ]; then local options3="$option_sport $option_dport" elif [ "$proto" = "ipv6-icmp" -a -n "$dport" ]; then local options3="--icmpv6-type $dport" fi # Append rule firewall_ip6tables -A $chain_init $option_proto -s $src -d $dst -j $action $options $options2 $options3 $options4 fi ;; esac fi if [ -n "$chain_back" ]; then case "$ip" in '4') if [ "$action" = "ACCEPT" -a $state_support_ipv4 -eq 1 ]; then # put initial state rule into local name="ssipv4a_${chain_back}" if [ -z "${!name}" ]; then # create ESTABLISHED,RELATED rules firewall_iptables -A $chain_back -p tcp --tcp-flags ACK ACK --match state --state ESTABLISHED -j ACCEPT firewall_iptables -A $chain_back -p tcp --tcp-flags FIN,SYN,RST,ACK SYN --match state --state RELATED -j ACCEPT firewall_iptables -A $chain_back -p tcp --tcp-flags FIN,SYN,RST,ACK ACK,RST --match state --state RELATED -j ACCEPT firewall_iptables -A $chain_back ! -p tcp --match state --state ESTABLISHED -j ACCEPT firewall_iptables -A $chain_back ! -p tcp --match state --state RELATED -j ACCEPT # set flag let ssipv4a_${chain_back}=1 #echo "FW4: insert state match rule ESTABLISHED,RELATED on chain: ${chain_back}" fi # Nothing more to do else # Define protocol related options if [ "$proto" = "udp" ]; then local options3="$option_sport_back $option_dport_back" elif [ "$proto" = "tcp" ]; then local options3="$option_sport_back $option_dport_back ! --syn" elif [ "$proto" = "icmp" -a -n "$sport" ]; then local options3="--icmp-type $sport" fi # Append rule firewall_iptables -A $chain_back $option_proto -s $dst -d $src -j $action $options $options2 $options3 $options4_back fi ;; '6') if ! firewall_check_ipv6; then return fi if [ "$action" = "ACCEPT" -a $state_support_ipv6 -eq 1 ]; then # put initial state rule into local name="ssipv6a_${chain_back}" if [ -z "${!name}" ]; then # create ESTABLISHED,RELATED rules firewall_ip6tables -A $chain_back -p tcp --tcp-flags ACK ACK --match state --state ESTABLISHED -j ACCEPT firewall_ip6tables -A $chain_back -p tcp --tcp-flags FIN,SYN,RST,ACK SYN --match state --state RELATED -j ACCEPT firewall_ip6tables -A $chain_back -p tcp --tcp-flags FIN,SYN,RST,ACK ACK,RST --match state --state RELATED -j ACCEPT firewall_ip6tables -A $chain_back ! -p tcp --match state --state ESTABLISHED -j ACCEPT firewall_ip6tables -A $chain_back ! -p tcp --match state --state RELATED -j ACCEPT # set flag let ssipv6a_${chain_back}=1 #echo "FW6: insert state match rule ESTABLISHED,RELATED on chain: ${chain_back}" fi # Nothing more to do else # Define protocol related options if [ "$proto" = "udp" ]; then local options3="$option_sport_back $option_dport_back" elif [ "$proto" = "tcp" ]; then local options3="$option_sport_back $option_dport_back ! --syn" elif [ "$proto" = "ipv6-icmp" -a -n "$sport" ]; then local options3="--icmpv6-type $sport" fi # Append rule firewall_ip6tables -A $chain_back $option_proto -s $dst -d $src -j $action $options $options2 $options3 $options4_back fi ;; esac fi } ## Insert a rule with user/address support # Options # $1: direction: incoming|outgoing # $2: chain name # $3: userportprotoaddr combination: user@port/proto%addr # user: userid (optional) # port/proto: see firewall_insert_rule # # depending on direction: # "incoming" : addr = source address # "outgoing" : addr = destination address # "forwarding": addr-addr = source/destination address # # $4: action # $5: additional options # Return code # 0: ok (or IPv6 skipped) # 3: Parameter not supported # 5: Missing parameter firewall_insert_rule_useraddr() { local fn="firewall_insert_rule_useraddr" #echo "DEBUG: firewall_insert_rule_useraddr: $*" local direction="$1" shift local chain="$1" shift local userportprotoaddr="$1" shift local action="$1" shift local options="$*" if [ -z "$direction" ]; then echo_error "ERROR: missing direction (arg1)" echo "Called: $fn $direction $chain $userportprotoaddr $action $options" return 5 fi if [ -z "$chain" ]; then echo_error "ERROR: missing chain name (arg2)" echo "Called: $fn $direction $chain $userportprotoaddr $action $options" return 5 fi if [ -z "$userportprotoaddr" ]; then echo_error "ERROR: missing user@port/protocol%address token (arg3)" echo "Called: $fn $direction $chain $userportprotoaddr $action $options" return 5 fi if [ -z "$action" ]; then echo_error "ERROR: missing action (arg6)" echo "Called: $fn $direction $chain $userportprotoaddr $action $options" return 5 fi # split portproto local user=${userportprotoaddr//@*} if [ "$user" = "$userportprotoaddr" ]; then # No "user@" given local user="" fi local portprotoaddr=${userportprotoaddr/$user@} local portproto="${portprotoaddr//\%*}" local addr="${portprotoaddr/$portproto}" local addr="${addr/\%}" # Use address depending on direction case "$direction" in 'incoming') # Default "any" local addr="${addr:-any}" local src="$addr" local dst="any" ;; 'outgoing') # Default "any" local addr="${addr:-any}" local src="any" local dst="$addr" ;; 'forwarding') # Default "any-any" local addr="${addr:-any-any}" local src="${addr/-*}" local dst="${addr/*-}" ;; *) echo_error "ERROR: unsupported direction: $direction" echo "Called: $fn $direction $chain $userportprotoaddr $action $options" return 3 ;; esac #echo "DEBUG: $fn $direction $chain $userportprotoaddr $action $options" #echo "DEBUG: portproto=$portproto src=$src dst=$dst" # Add user match option if [ -n "$user" ]; then if [ "$direction" = "outgoing" ]; then local options="--match owner --uid-owner $user $options" else echo_warn "WARN: unsupported direction for owner match: $direction (skip additional option)" echo "Called: $fn $direction $chain $userportprotoaddr $action $options" # return 3 fi fi # Call more generic function firewall_insert_rule $direction $chain $portproto $src $dst $action $options return $? } ## Cleanup ruleset # Options # $1: [IPv4|IPv6] (optional) # Return code # 0: ok (or IPv6 skipped) # 3: IP protocol version not supported firewall_append_cleanup_ruleset() { local ip="$1" local state_support=0 if [ -z "$ip" ]; then # Run through all available protocols firewall_append_cleanup_ruleset IPv4 firewall_append_cleanup_ruleset IPv6 return fi case "$ip" in '4'|'IPv4'|'ipv4') local iptables_call="firewall_iptables" local prefix="FW4" if [ $state_support_ipv4 -eq 1 ]; then local state_support=1 fi ;; '6'|'IPv6'|'ipv6') if ! firewall_check_ipv6; then return fi local iptables_call="firewall_ip6tables" local prefix="FW6" if [ $state_support_ipv6 -eq 1 ]; then local state_support=1 fi ## Required ICMPv6 rules if [ $state_support -ne 1 ]; then echo -n "$prefix: insert some important rules to avoid problems:" # type=1: destination-unreachable # type=2: packet-too-big # type=3: time-exceeded # type=4: parameter-problem for type in destination-unreachable packet-too-big time-exceeded parameter-problem; do echo -n " $type" $iptables_call -I INPUT -p ipv6-icmp --icmpv6-type $type -j ACCEPT $iptables_call -I OUTPUT -p ipv6-icmp --icmpv6-type $type -j ACCEPT $iptables_call -I FORWARD -p ipv6-icmp --icmpv6-type $type -j ACCEPT done echo fi local ipv6_hop_limit_match_1="--match hl --hl-eq 1" local ipv6_hop_limit_match_255="--match hl --hl-eq 255" if [ -f /openwrt_version ]; then if ! grep -q "^hl$" /proc/net/ip6_tables_matches; then # Hop Limit match is not supported local ipv6_hop_limit_match_1="" local ipv6_hop_limit_match_255="" fi fi # <= 2.6.9 does not recognice icmpv6-types, if option headers are in use if [ ${kversion_part[1]} -ge 2 -a ${kversion_part[2]} -ge 6 -a ${kversion_part[3]} -gt 9 ]; then true else # 130 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::1 -j ACCEPT $ipv6_hop_limit_match_1 # 131 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::1:2 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::1:3 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff05::1:3 -j ACCEPT $ipv6_hop_limit_match_1 # 143 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::16 -j ACCEPT $ipv6_hop_limit_match_1 fi echo "$prefix: insert some important rules for protocol independend multicast discovery" $iptables_call -I INPUT -p pim -s fe80::/10 -d ff02::d -j ACCEPT $ipv6_hop_limit_match_1 echo "$prefix: insert some important rules for multicast discovery" # 130: MLD Multicast Listener Query $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::1 --icmpv6-type 130 -j ACCEPT # 131: MLD Multicast Listener Report $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::/16 --icmpv6-type 131 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff05::/16 --icmpv6-type 131 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff15::/16 --icmpv6-type 131 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff1e::/16 --icmpv6-type 131 -j ACCEPT $ipv6_hop_limit_match_1 # 132: MLD Multicast Listener Done echo "$prefix: insert some important rules for router discovery" # type=133: router-solicitation $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::/16 --icmpv6-type router-solicitation -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I INPUT -p ipv6-icmp -s ::/128 -d ff02::2 --icmpv6-type router-solicitation -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d fe80::/10 --icmpv6-type router-solicitation -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I OUTPUT -p ipv6-icmp -s fe80::/10 -d ff02::2 --icmpv6-type router-solicitation -j ACCEPT $ipv6_hop_limit_match_255 # type=134: router-advertisement # multicast $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::1 --icmpv6-type router-advertisement -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::1:ff00:0/102 --icmpv6-type router-advertisement -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I OUTPUT -p ipv6-icmp -s fe80::/10 -d ff02::1 --icmpv6-type router-advertisement -j ACCEPT $ipv6_hop_limit_match_255 # unicast $iptables_call -I OUTPUT -p ipv6-icmp -s fe80::/10 -d fe80::/10 --icmpv6-type router-advertisement -j ACCEPT $ipv6_hop_limit_match_255 echo "$prefix: insert some important rules for neighbour discovery" # type=135: neighbour-solicitation #$iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::/16 --icmpv6-type neighbour-solicitation -j ACCEPT $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ::/0 --icmpv6-type neighbour-solicitation -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I INPUT -p ipv6-icmp -s ::/128 -d fe80::/10 --icmpv6-type neighbour-solicitation -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I INPUT -p ipv6-icmp -s ::/0 -d ff02::1:ff00:0/102 --icmpv6-type neighbour-solicitation -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I OUTPUT -p ipv6-icmp -s ::/0 -d ff02::1:ff00:0/102 --icmpv6-type neighbour-solicitation -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I OUTPUT -p ipv6-icmp -s fe80::/10 -d ::/0 --icmpv6-type neighbour-solicitation -j ACCEPT $ipv6_hop_limit_match_255 # type=136: neighbour-advertisement $iptables_call -I OUTPUT -p ipv6-icmp -s ::/0 -d ::/0 --icmpv6-type neighbour-advertisement -j ACCEPT $ipv6_hop_limit_match_255 $iptables_call -I INPUT -p ipv6-icmp -s ::/0 -d ::/0 --icmpv6-type neighbour-advertisement -j ACCEPT $ipv6_hop_limit_match_255 echo "$prefix: insert some important rules for DHCPv6" # 143: DHCPv6 $iptables_call -I INPUT -p ipv6-icmp -s ::/128 -d ff02::16 --icmpv6-type 143 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I INPUT -p ipv6-icmp -s fe80::/10 -d ff02::16 --icmpv6-type 143 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I OUTPUT -p ipv6-icmp -s ::/128 -d ff02::16 --icmpv6-type 143 -j ACCEPT $ipv6_hop_limit_match_1 $iptables_call -I OUTPUT -p ipv6-icmp -s fe80::/10 -d ff02::16 --icmpv6-type 143 -j ACCEPT $ipv6_hop_limit_match_1 ;; *) echo_error "ERROR: unsupported IP protocol version: $ip" return 3 ;; esac # Drop invalid packets extra, if possible if [ $state_support -eq 1 ]; then echo "$prefix: append log+drop for invalid packages" ## Drop invalid packets # Silent drop of out-of-state RST packages $iptables_call -A INPUT --match state --state INVALID -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j DROP # INPUT $iptables_call -A INPUT --match state --state INVALID -j LOG --log-prefix "INPUT/invalid: " --log-level 6 --match limit --limit 5/minute $iptables_call -A INPUT --match state --state INVALID -j DROP # OUTPUT # Let FIN/ACK out-of-state pass $iptables_call -A OUTPUT -p tcp --match state --state INVALID --tcp-flags SYN,ACK,FIN,RST FIN,ACK -j ACCEPT # Let RST out-of-state pass $iptables_call -A OUTPUT --match state --state INVALID -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j ACCEPT # Log the rest $iptables_call -A OUTPUT --match state --state INVALID -j LOG --log-prefix "OUTPUT/invalid: " --log-level 6 --match limit --limit 5/minute $iptables_call -A OUTPUT --match state --state INVALID -j DROP fi ## Final cleanup echo "$prefix: append final log+drop" # INPUT # Silent drop of out-of-state RST packages $iptables_call -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j DROP $iptables_call -A INPUT -j LOG --log-prefix "INPUT-${prefix}/cleanup: " --log-level 6 --match limit --limit 5/minute $iptables_call -A INPUT -j DROP # OUTPUT # Let RST out-of-state pass $iptables_call -A OUTPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j ACCEPT $iptables_call -A OUTPUT -j LOG --log-prefix "OUTPUT-${prefix}/cleanup: " --log-level 6 --match limit --limit 5/minute case "$ip" in '4'|'IPv4'|'ipv4') $iptables_call -A OUTPUT -p tcp -j REJECT --reject-with tcp-reset $iptables_call -A OUTPUT -p udp -j REJECT --reject-with icmp-port-unreachable ;; '6'|'IPv6'|'ipv6') # still unsupported #$iptables_call -A OUTPUT -p tcp -j REJECT --reject-with tcp-reset #$iptables_call -A OUTPUT -p udp -j REJECT --reject-with icmp6-port-unreachable ;; esac $iptables_call -A OUTPUT -j DROP # FORWARD $iptables_call -A FORWARD -j LOG --log-prefix "FORWARD-${prefix}/cleanup: " --log-level 6 --match limit --limit 5/minute $iptables_call -A FORWARD -j DROP } ## Add accounting rules # Options # $1: step # $2: [IPv4|IPv6] (optional) # Return code # 0: ok (or IPv6 skipped) # 3: IP protocol version not supported firewall_add_accounting_ruleset() { local step="$1" local ip="$2" if [ -z "$step" ]; then echo_error "ERROR: missing step" return 3 fi if [ -z "$ip" ]; then # Run through all available protocols firewall_add_accounting_ruleset "$step" IPv4 firewall_add_accounting_ruleset "$step" IPv6 return fi case "$ip" in '4'|'IPv4'|'ipv4') local iptables_call="firewall_iptables" local prefix="FW4" local tcp="tcp4" local udp="udp4" local icmp="icmp4" local ip="ipv4" ;; '6'|'IPv6'|'ipv6') if ! firewall_check_ipv6; then return fi local iptables_call="firewall_ip6tables" local prefix="FW6" local tcp="tcp6" local udp="udp6" local icmp="icmp6" local ip="ipv6" ;; *) echo_error "ERROR: unsupported IP protocol version: $ip" return 3 ;; esac case "$step" in 'pre') ## Main accouting rules echo "$prefix: add accounting rules (pre)" if [ "$ip" = "ipv4" -o "${FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6}" != "1" ]; then $iptables_call -N accIN $iptables_call -N accOUT $iptables_call -N accBilling # Dedicated protocols $iptables_call -N accBillDNSin $iptables_call -N accBillDNSout $iptables_call -N accBillNTPout $iptables_call -N accBillSSHin $iptables_call -N accBillSSHout $iptables_call -N accBillHTTPin $iptables_call -N accBillHTTPout $iptables_call -N accBillSMTPin $iptables_call -N accBillSMTPout $iptables_call -N accBillIMAPin $iptables_call -N accBillIMAPout $iptables_call -N accBillPOPin $iptables_call -N accBillPOPout $iptables_call -N accBillRSYNCin $iptables_call -N accBillRSYNCout $iptables_call -N accBillFTPin $iptables_call -N accBillFTPout $iptables_call -N accBillICMPin $iptables_call -N accBillICMPout fi ;; 'pre-post') echo "$prefix: add accounting rules (pre-post)" $iptables_call -A accIN -j accBilling $iptables_call -A accOUT -j accBilling case "$ip" in 'ipv4') flag_firewall_ipv4_add_accounting_ruleset_prepost=1 ;; 'ipv6') flag_firewall_ipv6_add_accounting_ruleset_prepost=1 ;; esac ;; 'post') local flag="flag_firewall_${ip}_add_accounting_ruleset_prepost" if [ "${!flag}" != "1" ]; then # For backward compatibility firewall_add_accounting_ruleset pre-post $ip fi echo "$prefix: add accounting rules (post)" ## Dedicated protocols # incoming DNS firewall_insert_rule incoming-no-sport accIN/accOUT domain/$udp any any accBillDNSin firewall_insert_rule incoming-no-sport accIN/accOUT domain/$udp any any RETURN firewall_insert_rule incoming-no-sport accIN/accOUT domain/$tcp any any accBillDNSin firewall_insert_rule incoming-no-sport accIN/accOUT domain/$tcp any any RETURN # outgoing DNS firewall_insert_rule outgoing-no-sport accOUT/accIN domain/$udp any any accBillDNSout firewall_insert_rule outgoing-no-sport accOUT/accIN domain/$udp any any RETURN firewall_insert_rule outgoing-no-sport accOUT/accIN domain/$tcp any any accBillDNSout firewall_insert_rule outgoing-no-sport accOUT/accIN domain/$tcp any any RETURN # outgoing NTP firewall_insert_rule outgoing-no-sport accOUT/accIN ntp/$udp any any accBillNTPout firewall_insert_rule outgoing-no-sport accOUT/accIN ntp/$udp any any RETURN firewall_insert_rule outgoing-no-sport accOUT/accIN ntp/$tcp any any accBillNTPout firewall_insert_rule outgoing-no-sport accOUT/accIN ntp/$tcp any any RETURN # incoming SSH firewall_insert_rule incoming-no-sport accIN/accOUT ssh/$tcp any any accBillSSHin firewall_insert_rule incoming-no-sport accIN/accOUT ssh/$tcp any any RETURN # outgoing SSH firewall_insert_rule outgoing-no-sport accOUT/accIN ssh/$tcp any any accBillSSHout firewall_insert_rule outgoing-no-sport accOUT/accIN ssh/$tcp any any RETURN # incoming HTTP(S) firewall_insert_rule incoming-no-sport accIN/accOUT http/$tcp any any accBillHTTPin firewall_insert_rule incoming-no-sport accIN/accOUT http/$tcp any any RETURN firewall_insert_rule incoming-no-sport accIN/accOUT https/$tcp any any accBillHTTPin firewall_insert_rule incoming-no-sport accIN/accOUT https/$tcp any any RETURN # outgoing HTTP(S) firewall_insert_rule outgoing-no-sport accOUT/accIN http/$tcp any any accBillHTTPout firewall_insert_rule outgoing-no-sport accOUT/accIN http/$tcp any any RETURN firewall_insert_rule outgoing-no-sport accOUT/accIN https/$tcp any any accBillHTTPout firewall_insert_rule outgoing-no-sport accOUT/accIN https/$tcp any any RETURN # incoming SMTP firewall_insert_rule incoming-no-sport accIN/accOUT smtp/$tcp any any accBillSMTPin firewall_insert_rule incoming-no-sport accIN/accOUT smtp/$tcp any any RETURN firewall_insert_rule incoming-no-sport accIN/accOUT smtps/$tcp any any accBillSMTPin firewall_insert_rule incoming-no-sport accIN/accOUT smtps/$tcp any any RETURN firewall_insert_rule incoming-no-sport accIN/accOUT submission/$tcp any any accBillSMTPin firewall_insert_rule incoming-no-sport accIN/accOUT submission/$tcp any any RETURN # outgoing SMTP firewall_insert_rule outgoing-no-sport accOUT/accIN smtp/$tcp any any accBillSMTPout firewall_insert_rule outgoing-no-sport accOUT/accIN smtp/$tcp any any RETURN firewall_insert_rule outgoing-no-sport accOUT/accIN smtps/$tcp any any accBillSMTPout firewall_insert_rule outgoing-no-sport accOUT/accIN smtps/$tcp any any RETURN firewall_insert_rule outgoing-no-sport accOUT/accIN submission/$tcp any any accBillSMTPout firewall_insert_rule outgoing-no-sport accOUT/accIN submission/$tcp any any RETURN # incoming POP firewall_insert_rule incoming-no-sport accIN/accOUT pop3/$tcp any any accBillPOPin firewall_insert_rule incoming-no-sport accIN/accOUT pop3/$tcp any any RETURN firewall_insert_rule incoming-no-sport accIN/accOUT pop3s/$tcp any any accBillPOPin firewall_insert_rule incoming-no-sport accIN/accOUT pop3s/$tcp any any RETURN # outgoing POP firewall_insert_rule outgoing-no-sport accOUT/accIN pop3/$tcp any any accBillPOPout firewall_insert_rule outgoing-no-sport accOUT/accIN pop3/$tcp any any RETURN firewall_insert_rule outgoing-no-sport accOUT/accIN pop3s/$tcp any any accBillPOPout firewall_insert_rule outgoing-no-sport accOUT/accIN pop3s/$tcp any any RETURN # incoming IMAP firewall_insert_rule incoming-no-sport accIN/accOUT imap/$tcp any any accBillIMAPin firewall_insert_rule incoming-no-sport accIN/accOUT imap/$tcp any any RETURN firewall_insert_rule incoming-no-sport accIN/accOUT imaps/$tcp any any accBillIMAPin firewall_insert_rule incoming-no-sport accIN/accOUT imaps/$tcp any any RETURN # outgoing IMAP firewall_insert_rule outgoing-no-sport accOUT/accIN imap/$tcp any any accBillIMAPout firewall_insert_rule outgoing-no-sport accOUT/accIN imap/$tcp any any RETURN firewall_insert_rule outgoing-no-sport accOUT/accIN imaps/$tcp any any accBillIMAPout firewall_insert_rule outgoing-no-sport accOUT/accIN imaps/$tcp any any RETURN # incoming RSYNC firewall_insert_rule incoming-no-sport accIN/accOUT rsync/$tcp any any accBillRSYNCin firewall_insert_rule incoming-no-sport accIN/accOUT rsync/$tcp any any RETURN # outgoing RSYNC firewall_insert_rule outgoing-no-sport accOUT/accIN rsync/$tcp any any accBillRSYNCout firewall_insert_rule outgoing-no-sport accOUT/accIN rsync/$tcp any any RETURN # FTP accounting only works with connection tracking if [ \( "$tcp" = "tcp4" -a $state_support_ipv4 -eq 1 \) -o \( "$tcp" = "tcp6" -a $state_support_ipv6 -eq 1 \) ]; then ## incoming FTP for port in $FIREWALL_LIB_FTP_ACCOUNTING_SERVER_PORTS; do # Command channel firewall_insert_rule incoming-no-sport accIN/accOUT $port/$tcp any any accBillFTPin firewall_insert_rule incoming-no-sport accIN/accOUT $port/$tcp any any RETURN # Active data channel firewall_insert_rule outgoing-no-sport accOUT nonprivportrange/$tcp any any accBillFTPin "--sport $[ $port - 1 ]" firewall_insert_rule outgoing-no-sport accOUT nonprivportrange/$tcp any any RETURN "--sport $[ $port - 1 ]" firewall_insert_rule incoming-no-sport accIN $[ $port - 1 ]/$tcp any any accBillFTPin "! --syn" firewall_insert_rule incoming-no-sport accIN $[ $port - 1 ]/$tcp any any RETURN "! --syn" done ## Passive data channel (ports have to be defined in FTP server) firewall_insert_rule incoming-no-sport accIN/accOUT $FIREWALL_LIB_FTP_ACCOUNTING_PASSIVE_PORTS/$tcp any any accBillFTPin "--match helper --helper ftp" firewall_insert_rule incoming-no-sport accIN/accOUT $FIREWALL_LIB_FTP_ACCOUNTING_PASSIVE_PORTS/$tcp any any RETURN "--match helper --helper ftp" ## outgoing FTP ## Command channel firewall_insert_rule outgoing-no-sport accOUT/accIN ftp/$tcp any any accBillFTPout firewall_insert_rule outgoing-no-sport accOUT/accIN ftp/$tcp any any RETURN # Data channel firewall_insert_rule outgoing-no-sport accOUT/accIN $tcp any any accBillFTPout "--match helper --helper ftp" firewall_insert_rule outgoing-no-sport accOUT/accIN $tcp any any RETURN "--match helper --helper ftp" fi # incoming ICMP firewall_insert_rule incoming accIN any/$icmp any any accBillICMPin firewall_insert_rule incoming accIN any/$icmp any any RETURN # outgoing ICMP firewall_insert_rule outgoing accOUT any/$icmp any any accBillICMPout firewall_insert_rule outgoing accOUT any/$icmp any any RETURN ;; *) echo_error "ERROR: unsupported position: $step" return 3 ;; esac } ## Append ICMP rate limiter # Options # $1: [IPv4|IPv6] (optional) # $2+: chain names (optional, default: INPUT FORWARD OUTPUT) # Return code # 0: ok (or IPv6 skipped) # 3: IP protocol version not supported firewall_append_icmp_ratelimit_ruleset() { local ip="$1" shift if [ -z "$ip" ]; then # Run through all available protocols firewall_append_icmp_ratelimit_ruleset IPv4 $* firewall_append_icmp_ratelimit_ruleset IPv6 $* return fi case "$ip" in '4'|'IPv4'|'ipv4') local iptables_call="firewall_iptables" local prefix="FW4" local chain="ICMPlimit" local proto="icmp" local ip="ipv4" if [ $state_support_ipv4 -eq 1 ]; then local state_support=1 fi ;; '6'|'IPv6'|'ipv6') if ! firewall_check_ipv6; then return fi local iptables_call="firewall_ip6tables" local prefix="FW6" local chain="ICMPlimit" local proto="ipv6-icmp" local ip="ipv6" if [ $state_support_ipv6 -eq 1 ]; then local state_support=1 fi ;; *) echo_error "ERROR: unsupported IP protocol version: $ip" return 3 ;; esac ## ICMP limiter if [ "$ip" = "ipv4" -o "${FIREWALL_LIB_FEATURE_DEFAULT_BOTH_IPV4_AND_IPV6}" != "1" ]; then $iptables_call -N $chain fi echo -n "$prefix: append ICMP rate limiter in chain:" $iptables_call -A $chain -j RETURN --match limit --limit 10/second --limit-burst 100 $iptables_call -A $chain -j LOG --log-prefix "$chain: " --log-level 6 --match limit --limit 5/minute $iptables_call -A $chain -j DROP # Rate limiter if [ -z "$1" ]; then for limitchain in INPUT OUTPUT FORWARD; do echo -n " $limitchain" $iptables_call -A $limitchain -p $proto -j $chain done else while [ ! -z "$1" ]; do echo -n " $1" $iptables_call -A $1 -p $proto -j $chain shift done fi echo } ## Accept all traffic # Options # $1: [IPv4|IPv6] (optional) # Return code # 0: ok (or IPv6 skipped) # 3: IP protocol version not supported firewall_accept_all() { local ip="$1" if [ -z "$ip" ]; then # Run through all available protocols firewall_accept_all IPv4 firewall_accept_all IPv6 return fi case "$ip" in '4'|'IPv4'|'ipv4') local iptables_call="firewall_iptables" local prefix="FW4" ;; '6'|'IPv6'|'ipv6') if ! firewall_check_ipv6; then return fi local iptables_call="firewall_ip6tables" local prefix="FW6" ;; *) echo_error "ERROR: unsupported IP protocol version: $ip" return 3 ;; esac ## Insert accept all rules echo "$prefix: accept all traffic (DANGEROUS)" $iptables_call -I INPUT -j ACCEPT $iptables_call -I OUTPUT -j ACCEPT $iptables_call -I FORWARD -j ACCEPT echo "$prefix: set policy to ACCEPT (DANGEROUS)" firewall_set_policy ACCEPT $ip } ## Set policy # Options # $1: [IPv4|IPv6] (optional) # Return code # 0: ok (or IPv6 skipped) # 3: IP protocol version not supported firewall_set_policy() { local policy="$1" local ip="$2" if [ -z "$policy" ]; then echo_error "ERROR: missing policy (arg1)" exit 3 fi if [ -z "$ip" ]; then # Run through all available protocols firewall_set_policy $policy IPv4 firewall_set_policy $policy IPv6 return fi case "$ip" in '4'|'IPv4'|'ipv4') local iptables_call="firewall_iptables" local prefix="FW4" ;; '6'|'IPv6'|'ipv6') if ! firewall_check_ipv6; then return fi local iptables_call="firewall_ip6tables" local prefix="FW6" ;; *) echo_error "ERROR: unsupported IP protocol version: $ip" return 3 ;; esac ## Set policy echo "$prefix: set default policy to: $policy" $iptables_call -P INPUT $policy $iptables_call -P OUTPUT $policy $iptables_call -P FORWARD $policy } .