Platon Technologies
not logged in Login Registration
EnglishSlovak
open source software development celebrating 10 years of open source development! Monday, November 11, 2024

File: [Platon] / scripts / shell / firewall / fw-universal.sh (download)

Revision 2.72, Wed Jun 9 11:29:14 2010 UTC (14 years, 5 months ago) by nepto

Changes since 2.71: +2 -2 lines

Fixed udp vs tcp typo

#!/bin/sh

#
# This will be universal firewalling script for Linux kernel (iptables) in near future
# Can be started by init or by hand.
#
# Developed by Lubomir Host 'rajo' <rajo AT platon.sk>
# Copyright (c) 2003-2009 Platon Group, http://platon.sk/
# Licensed under terms of GNU General Public License.
# All rights reserved.
#
# $Platon: scripts/shell/firewall/fw-universal.sh,v 2.71 2009-11-06 23:14:36 nepto Exp $
#
# Changelog:
# 2003-10-24 - created
#

umask 077 # security

DESC="firewall"
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

DEFAULT_FIREWALL_CONFIG="${DEFAULT_FIREWALL_CONFIG:=/etc/default/firewall}"
DEFAULT_FIREWALL_CONFIG_DIR="${DEFAULT_FIREWALL_CONFIG_DIR:=/etc/default/firewall.d}"
DEFAULT_CACHE_DIR="${DEFAULT_CACHE_DIR:=/var/cache/firewall}"

# quiet output? {{{
if [ "x$1" = "xblock" ] || [ "x$QUIET" = "xyes" ]; then
    print_info()
    {
        echo -n ""
    }
else
    print_info()
    {
        echo "$@"
    }
fi
# }}}

if [ -f "$DEFAULT_FIREWALL_CONFIG" ]; then
    print_info "Reading config file $DEFAULT_FIREWALL_CONFIG"
    . $DEFAULT_FIREWALL_CONFIG
fi

#
# Default configuration values:
#

DEFAULT_POLICY="${DEFAULT_POLICY:=DROP}"
# which modules to load
MODULES="${MODULES:=}"
MODULES_LOADING="${MODULES_LOADING:=yes}"
MODULES_REMOVING="${MODULES_REMOVING:=no}"

LOG_LIMIT="${LOG_LIMIT:=-m limit --limit 12/h --limit-burst 10 -j LOG --log-level notice --log-prefix}"

# Paths:
#IPTABLES=":" # for testing only - does nothing
IPTABLES="${IPTABLES:=$DEBUG/sbin/iptables}"
IPTABLES_SAVE="${IPTABLES_SAVE:=$DEBUG/sbin/iptables-save}"
IPTABLES_RESTORE="${IPTABLES_RESTORE:=$DEBUG/sbin/iptables-restore}"

if [ "x$LOGGING" = "xoff" ]; then
    IPTABLES_LOG=": log turned off"
else
    IPTABLES_LOG="${IPTABLES_LOG:=$DEBUG/sbin/iptables}"
fi
IFCONFIG="${IFCONFIG:=/sbin/ifconfig}"
DEPMOD="${DEPMOD:=/sbin/depmod}"
MODPROBE="${MODPROBE:=/sbin/modprobe}"
RMMOD="${RMMOD:=/sbin/rmmod}"
AWK="${AWK:=/usr/bin/gawk}"
PERL="${PERL:=/usr/bin/perl}"

# shaping
TC="${TC:=/sbin/tc}"

# loopback interface
LO_IFACE="${LO_IFACE:=lo}"
# Hide NAT clients behind firewall
NAT_SET_TTL="${NAT_SET_TTL:=no}"

# reject config
ALL_REJECT_INPUT_TCP="${ALL_REJECT_INPUT_TCP:=113}" # by default reject connections to AUTH server
REJECT_WITH="${REJECT_WITH:=tcp-reset}"

#
# CONSTANTS - Do not edit
#
ANYWHERE="0.0.0.0/0"                # Match any IP address
BROADCAST_SRC="0.0.0.0"                # Broadcast Source Address
BROADCAST_DEST="255.255.255.255"    # Broadcast Destination Address
CLASS_A="10.0.0.0/8"                # Class-A Private (RFC-1918) Networks
CLASS_B="172.16.0.0/12"                # Class-B Private (RFC-1918) Networks
CLASS_C="192.168.0.0/16"            # Class-C Private (RFC-1918) Networks
CLASS_D_MULTICAST="224.0.0.0/4"        # Class-D Multicast Addresses
CLASS_E_RESERVED_NET="240.0.0.0/5"    # Class-E Reserved Addresses
PRIVPORTS="0:1023"                    # Well-Known, Privileged Port Range
UNPRIVPORTS="1024:65535"            # Unprivileged Port Range
TRACEROUTE_SRC_PORTS="32769:65535"    # Traceroute Source Ports
TRACEROUTE_DEST_PORTS="33434:33523"    # Traceroute Destination Ports


# allow some ICMP packets - needed for ping etc.
ACCEPT_ICMP_PACKETS="${ACCEPT_ICMP_PACKETS:=echo-reply destination-unreachable echo-request time-exceeded}"

# check if all required tools are installed
check_tools()
{ # {{{
    [ -x $AWK ]                    || (echo "AWK not found: please install gawk"                    && exit 1);
    [ -x $PERL ]                || (echo "PERL not found: please install perl"                    && exit 1);
    [ -x $IPTABLES ]            || (echo "IPTABLES not found: please install iptables"            && exit 1);
    [ -x $IPTABLES_SAVE ]        || (echo "IPTABLES_SAVE not found: please install iptables"        && exit 1);
    [ -x $IPTABLES_RESTORE ]    || (echo "IPTABLES_RESTORE not found: please install iptables"    && exit 1);
} # }}}

print_first()
{ # {{{
    echo $1
} # }}}

get_first_ip_addr()
{ # {{{
    varname="$1"
    print_first `echo ${!varname} | sort -g`
} # }}}

read_config_ips()
{ # {{{
    PARSE_CONFIG=$1 $PERL -ne 'if (m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/(\d+)$/g) { print; } elsif ($_ !~ m/^\s*#/ && $_ !~ m/^\s*$/ ) { print STDERR "ERROR: $ENV{PARSE_CONFIG}:$.: ignored string $_\n"; }' $1
} # }}}

# load necessary modules from $MODULES variable
load_modules()
{ # {{{
    if [ "e$MODULES_LOADING" = "eyes" ]; then
        print_info "# Loading modules"
        for mod in $MODULES; do
            print_info "    $MODPROBE $mod"
            $MODPROBE $mod
        done
    fi
} # }}}

load_cache()
{ # {{{
        
    if [ ! -d "$DEFAULT_CACHE_DIR" ]; then
        mkdir -p "$DEFAULT_CACHE_DIR";
    fi

    config=`cat $DEFAULT_FIREWALL_CONFIG $0 $DEFAULT_FIREWALL_CONFIG_DIR/deploy-servers.list $DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf `; # config file and firewalling script
    md5key=`echo "config = '$config' parsed_interfaces ='$parsed_interfaces' parsed_routes='$parsed_routes'" | md5sum | $AWK '{ print $1; }'`;
    CACHE_FILE="$DEFAULT_CACHE_DIR/$md5key"

    #echo "CACHE_FILE=$CACHE_FILE"

    if [ -f "$CACHE_FILE" ]; then
        print_info "Loading rules from cache file $CACHE_FILE"

        # this has nothing to do with IPtables rules, we need to run them explicitly
        forward_on
        shaping_on

        # restore IPtables rules
        $IPTABLES_RESTORE -c < $CACHE_FILE;
        #echo "exit code $IPTABLES_RESTORE: $?"
        [ $? -eq 0 ] && exit 0; # exit if load succesfull
    fi
} # }}}

# unload necessary modules from $MODULES variable
unload_modules()
{ # {{{
    # reverse modules
    if [ "e$MODULES_REMOVING" = "eyes" ]; then
        print_info "# Removing modules"
        R_MODULES=`echo "$MODULES" | tr ' ' '\012' | tac | tr '\012' ' '`
        for mod in $R_MODULES; do
            print_info "    $RMMOD $mod"
            $RMMOD $mod
        done
    fi
} # }}}

# print status of detected interfaces
print_iface_status()
{ # {{{
    # Print interfaces:
    print_info "$(pad7 "# iface") | $(pad15 "IP address") | $(pad15 "Gateway") | $(pad15 "Broadcast") | $(pad15 "Netmask") | HW address";
    for iface in $interfaces; do
        IPS="IP_$iface";
        for IP in ${!IPS}; do
            Gateway="Gateway_$iface";
            Bcast="Bcast_$iface";
            Mask="Mask_$iface";
            HWaddr="HWaddr_$iface";
            print_info "$(pad7 $iface) | $(pad15 ${IP}) | $(pad15 ${!Gateway}) | $(pad15 ${!Bcast}) | $(pad15 ${!Mask}) | ${!HWaddr}";
        done
    done
} # }}}

# set default policy (variable $DEFAULT_POLICY)
set_default_policy()
{ # {{{
    # Set default policy
    for chain in INPUT OUTPUT FORWARD; do
        $IPTABLES -P $chain $DEFAULT_POLICY
    done
} # }}}

antispoof_on()
{ # {{{
    for interface in /proc/sys/net/ipv4/conf/*/rp_filter; do
        echo "1" > ${interface}
    done
} # }}}

# Turn on IP packets forwarding
forward_on()
{ # {{{
    # NAT requires turn on IP forwarding
    if [ ! -z "$NAT_LAN_IFACE" ]; then
        print_info -en "NAT: Enabling packet forwarding..."
        echo 1 > /proc/sys/net/ipv4/ip_forward
        print_info " done."
    fi
} # }}}

forward_off()
{ # {{{
    print_info -en "NAT: Disabling packet forwarding..."
    echo 0 > /proc/sys/net/ipv4/ip_forward
    print_info " done."
} # }}}

# clear status of iptable chains
remove_chains()
{ # {{{

    for table in filter nat mangle; do
        $IPTABLES -t $table -F # clear all chains
        $IPTABLES -t $table -X # remove all chains
        $IPTABLES -t $table -Z # zero counts
    done

} # }}}

# DROP packages from nmap(1)
nmap_scan_filter()
{ # {{{

    print_info -en "Turning on nmap scan filter "

    for chain in INPUT FORWARD; do
        #  Nie je nastaveny ziaden bit
        $IPTABLES_LOG    -A $chain   -p TCP --tcp-flags ALL NONE  $LOG_LIMIT "nmap scan $chain ALL NONE: "
        print_info -en "."
        $IPTABLES        -A $chain   -p TCP --tcp-flags ALL NONE -j DROP 
        print_info -en "."

        # dva odporujuuce si flagy su nastavene:
        for flags in   SYN,FIN   SYN,RST   FIN,RST   ; do
            $IPTABLES_LOG    -A $chain   -p TCP --tcp-flags $flags $flags $LOG_LIMIT "nmap scan $chain $flags: "
            print_info -en "."
            $IPTABLES        -A $chain   -p TCP --tcp-flags $flags $flags -j DROP 
            print_info -en "."
        done

        # je nastavene len $flags bez predpokladaneho ACK
        for flags in   FIN   PSH   URG   ; do
            $IPTABLES_LOG    -A $chain   -p TCP --tcp-flags ACK,$flags $flags $LOG_LIMIT "nmap scan $chain ACK,$flags: "
            print_info -en "."
            $IPTABLES        -A $chain   -p TCP --tcp-flags ACK,$flags $flags -j DROP 
            print_info -en "."
        done
    done
    
    print_info " done."

} # }}}

# drop packets in state INVALID
invalid_packet_filter()
{ # {{{
    
    print_info -en "Turning on INVALID packet filter "
    for chain in INPUT OUTPUT FORWARD; do
        $IPTABLES_LOG    -A $chain -m state --state INVALID $LOG_LIMIT "INVALID $chain: "
        print_info -en "."
        $IPTABLES        -A $chain -m state --state INVALID -j DROP 
        print_info -en "."
    done

    print_info " done."

} # }}}

syn_flood()
{ # {{{
    $IPTABLES -N syn-flood
    $IPTABLES -A syn-flood -m limit --limit 1/s --limit-burst 4 -j RETURN
    $IPTABLES -A syn-flood -j DROP

    for riface in $REAL_INTERFACES; do
        $IPTABLES -A INPUT -i $riface -p TCP --syn -j syn-flood

        # packet is marked az NEW, but doesn't have SYN flag - drop it
        $IPTABLES -A INPUT -i $riface -p TCP ! --syn -m state --state NEW -j DROP
    done


} # }}}

anti_spoof_filter()
{ # {{{
    
    #   http://www.iana.com/assignments/ipv4-address-space

    if [ ! -z "$ANTISPOOF_IFACE" ]; then

        print_info -en "Turning on antispoof filter for interfaces: "
        $IPTABLES -N spoof

        # Ochrana proti Spoogingu zo spatnej slucky
        $IPTABLES_LOG    -A spoof -s 127.0.0.0/8 $LOG_LIMIT "RESERVED:127.0.0.0/8 src" 
        $IPTABLES        -A spoof -s 127.0.0.0/8 -j DROP 
        $IPTABLES_LOG    -A spoof -d 127.0.0.0/8 $LOG_LIMIT "RESERVED:127.0.0.0/8 dest"
        $IPTABLES        -A spoof -d 127.0.0.0/8 -j DROP
        # Ochrana proti Spoofingu Internetu z adries urcenych pre lokalne siete 
        $IPTABLES_LOG    -A spoof -s 192.168.0.0/16 $LOG_LIMIT "RESERVED:192.168.0.0/16 src"
        $IPTABLES        -A spoof -s 192.168.0.0/16 -j DROP         # RFC1918
        $IPTABLES_LOG    -A spoof -s 172.16.0.0/12 $LOG_LIMIT "RESERVED:172.16.0.0/12 src"
        $IPTABLES        -A spoof -s 172.16.0.0/12 -j DROP         # RFC1918
        $IPTABLES_LOG    -A spoof -s 10.0.0.0/8  $LOG_LIMIT "RESERVED:10.0.0.0/8 src"
        $IPTABLES        -A spoof -s 10.0.0.0/8 -j DROP  # RFC1918 len pre sietovy interface do Internetu, kedze 10.0.0.0 je adresa LAN

        # 2009-02-11 - Not reserver anymore: http://www.iana.org/assignments/ipv4-address-space/
        #              - it is a Comcast network now
        #$IPTABLES_LOG    -A spoof -s 96.0.0.0/4 $LOG_LIMIT "RESERVED:96.0.0.0/4 src"
        #$IPTABLES        -A spoof -s 96.0.0.0/4 -j DROP              # IANA

        for iface in $ANTISPOOF_IFACE; do
            print_info -en " $iface"
            $IPTABLES -A FORWARD -i $iface -j spoof
            $IPTABLES -A INPUT   -i $iface -j spoof
        done
        print_info " done."
    fi
} # }}}

mangle_prerouting()
{ # {{{

    print_info -en "Optimizing PREROUTING TOS: "
    # TOS flagy slouzi k optimalizaci datovych cest. Pro ssh, ftp a telnet
    # pozadujeme minimalni zpozdeni. Pro ftp-data zase maximalni propostnost
    $IPTABLES -t mangle -A PREROUTING -p TCP --sport ssh -j TOS --set-tos Minimize-Delay
    print_info -en "."
    $IPTABLES -t mangle -A PREROUTING -p TCP --dport ssh -j TOS --set-tos Minimize-Delay
    print_info -en "."
    $IPTABLES -t mangle -A PREROUTING -p TCP --sport ftp -j TOS --set-tos Minimize-Delay
    print_info -en "."
    $IPTABLES -t mangle -A PREROUTING -p TCP --dport ftp -j TOS --set-tos Minimize-Delay
    print_info -en "."
    $IPTABLES -t mangle -A PREROUTING -p TCP --dport telnet -j TOS --set-tos Minimize-Delay
    print_info -en "."
    $IPTABLES -t mangle -A PREROUTING -p TCP --sport ftp-data -j TOS --set-tos Maximize-Throughput
    print_info -en "."
    print_info " done."

} # }}}

mangle_output()
{ # {{{

    print_info -en "Optimizing OUTPUT TOS:"
    # TOS flagy slouzi k optimalizaci datovych cest. Pro ssh, ftp a telnet
    # pozadujeme minimalni zpozdeni. Pro ftp-data zase maximalni propostnost
    for riface in $REAL_INTERFACES; do
        print_info -en " $riface";
        $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --sport ssh -j TOS --set-tos Minimize-Delay
        $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --dport ssh -j TOS --set-tos Minimize-Delay
        $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --sport ftp -j TOS --set-tos Minimize-Delay
        $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --dport ftp -j TOS --set-tos Minimize-Delay
        $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --dport telnet -j TOS --set-tos Minimize-Delay
        $IPTABLES -t mangle -A OUTPUT -o $riface -p TCP --sport ftp-data -j TOS --set-tos Maximize-Throughput
    done
    print_info " done."

} # }}}

# Masquerade local subnet
masquerade()
{ # {{{
    if [ ! -z "$NAT_LAN_IFACE" ]; then
        print_info -en "NAT: Enabling packet forwarding..."
        echo 1 > /proc/sys/net/ipv4/ip_forward
        print_info " done."
        print_info -en "NAT: Masquerading local subnet: $NAT_SUBNET_IFACE --> $NAT_LAN_IFACE"

        ip="`get_first_ip_addr IP_$NAT_SUBNET_IFACE`"
        netmask="Mask_$NAT_SUBNET_IFACE"
        localnet="$ip/${!netmask}"

        lan_ip="`get_first_ip_addr IP_$NAT_LAN_IFACE`"

        # alow packets from private subnet
        $IPTABLES -A FORWARD -s ! $localnet -i $NAT_SUBNET_IFACE -j DROP
        for client_ip in $NAT_CLIENT_DROP; do
            print_info -en " !$client_ip";
            $IPTABLES -A FORWARD -s $client_ip -i $NAT_SUBNET_IFACE -j DROP
        done

        for redirect in $NAT_TCP_PORT_REDIRECT; do
            #eval `echo $redirect | $AWK -v FS=: '{ printf "remote_port=%s; local_port=%s;", $1, $2; }'`
            eval `echo $redirect | \
                $AWK -v FS=: '    (NF == 2) { remote_ip = "$lan_ip"; remote_port = $1; local_port = $2; } \
                                (NF == 3) { remote_ip = $2;        remote_port = $1; local_port = $3; } \
                                END { printf "remote_ip=%s; remote_port=%s; local_port=%s;", remote_ip, remote_port, local_port; }'`
            print_info -en " $remote_port>>$remote_ip:$local_port(tcp)"
            $IPTABLES -t nat -A PREROUTING -p TCP \
                -i ! $NAT_LAN_IFACE -d ! $lan_ip \
                --dport $remote_port -j REDIRECT --to-port $local_port
        done
        for redirect in $NAT_UDP_PORT_REDIRECT; do
            #eval `echo $redirect | $AWK -v FS=: '{ printf "remote_port=%s; local_port=%s;", $1, $2; }'`
            eval `echo $redirect | \
                $AWK -v FS=: '    (NF == 2) { dnat = "no"  ; remote_ip = "X"; remote_port = $1; local_port = $2; } \
                                (NF == 3) { dnat = "yes" ; remote_ip = $2;  remote_port = $1; local_port = $3; } \
                                END { printf "dnat=%s; remote_ip=%s; remote_port=%s; local_port=%s;", dnat, remote_ip, remote_port, local_port; }'`
            print_info -en " $remote_port>>$remote_ip:$local_port(udp)"
            if [ "x$dnat" = "xyes" ]; then
                $IPTABLES -t nat -A PREROUTING -p UDP -i $NAT_SUBNET_IFACE -d ! $ip \
                --dport $local_port -j DNAT --to $remote_ip:$remote_port
                $IPTABLES -A FORWARD -p UDP -i $NAT_SUBNET_IFACE -d ! $ip --dport $local_port -j ACCEPT
            else
                $IPTABLES -t nat -A PREROUTING -p UDP \
                    -i ! $NAT_LAN_IFACE -d ! $lan_ip \
                    --dport $remote_port -j REDIRECT --to-port $local_port
            fi
        done

        #$IPTABLES -t nat -A POSTROUTING -s $localnet -o $NAT_LAN_IFACE -j MASQUERADE
        $IPTABLES -t nat -A POSTROUTING -o $NAT_LAN_IFACE -j MASQUERADE

        print_info " done."

        # don't forward Miscrosoft protocols - NOT RFC compliant packets
        if [ ! -z "$NAT_FORWARD_MICROSOFT" ]; then
            if [ "x$NAT_FORWARD_MICROSOFT" = "xno" ]; then
                $IPTABLES -A FORWARD -p TCP ! --syn -m state --state NEW -j DROP

                for port in 69 135 445 1434 6667; do
                    $IPTABLES -A FORWARD -p TCP --dport $port -j DROP
                    $IPTABLES -A FORWARD -p UDP --dport $port -j DROP
                done
            fi
        fi

        if [ ! -z "$NAT_FORWARD_TCP_PORTS" ]; then
            print_info -en "\tAccepting FORWARD TCP ports:"
            for port in $NAT_FORWARD_TCP_PORTS; do
                print_info -en " $port"
                $IPTABLES -A FORWARD -p TCP --dport $port -m state --state NEW -j ACCEPT
            done
            print_info " done."
        fi

        if [ ! -z "$NAT_FORWARD_UDP_PORTS" ]; then
            print_info -en "\tAccepting FORWARD UDP ports:"
            for port in $NAT_FORWARD_UDP_PORTS; do
                print_info -en " $port"
                $IPTABLES -A FORWARD -p UDP --dport $port -m state --state NEW -j ACCEPT
            done
            print_info " done."
        fi

        print_info -en "\tAccepting ICMP packets:"
        for type in $ACCEPT_ICMP_PACKETS; do
            print_info -en " $type"
            $IPTABLES -A FORWARD -p ICMP --icmp-type $type -j ACCEPT
        done
        #$IPTABLES_LOG -A FORWARD -p ICMP -j LOG --log-prefix "FWD ICMP: "
        print_info " done."

        # Port forwarding to local machines
        if [ ! -z "$NAT_TCP_PORT_FORWARD" ]; then
            print_info -en "\tForwarding TCP ports to local machines:"
            for redirect in $NAT_TCP_PORT_FORWARD; do
                #eval `echo $redirect | $AWK -v FS=: '{ printf "src_port=%s; local_machine=%s; dest_port=%s;", $1, $2, $3; }'`
                eval `echo $redirect | \
                    $AWK -v FS=: '    (NF == 3) { src_ip = "$lan_ip" ; src_port = $1; local_machine = $2; dest_port = $3; } \
                                    (NF == 4) { src_ip = $1 ; src_port = $2; local_machine = $3; dest_port = $4; } \
                                    END { printf "src_ip=%s; src_port=%s; local_machine=%s; dest_port=%s;", src_ip, src_port, local_machine, dest_port; }'`
                print_info -en " $src_ip:$src_port -> $local_machine:$dest_port"
                $IPTABLES -t nat -A PREROUTING -p TCP -i $NAT_LAN_IFACE -d $src_ip \
                --dport $src_port -j DNAT --to $local_machine:$dest_port
                $IPTABLES -A FORWARD -p TCP -i $NAT_LAN_IFACE -d $local_machine --dport $dest_port -j ACCEPT
            done
            print_info " done."
        fi
        if [ ! -z "$NAT_UDP_PORT_FORWARD" ]; then
            print_info -en "\tForwarding UDP ports to local machines:"
            for redirect in $NAT_UDP_PORT_FORWARD; do
                #eval `echo $redirect | $AWK -v FS=: '{ printf "src_port=%s; local_machine=%s; dest_port=%s;", $1, $2, $3; }'`
                eval `echo $redirect | \
                    $AWK -v FS=: '    (NF == 3) { src_ip = "$lan_ip" ; src_port = $1; local_machine = $2; dest_port = $3; } \
                                    (NF == 4) { src_ip = $1 ; src_port = $2; local_machine = $3; dest_port = $4; } \
                                    END { printf "src_ip=%s; src_port=%s; local_machine=%s; dest_port=%s;", src_ip, src_port, local_machine, dest_port; }'`
                print_info -en " $src_port -> $local_machine:$dest_port"
                $IPTABLES -t nat -A PREROUTING -p UDP -i $NAT_LAN_IFACE -d $lan_ip \
                --dport $src_port -j DNAT --to $local_machine:$dest_port
                $IPTABLES -A FORWARD -p UDP -i $NAT_LAN_IFACE -d $local_machine --dport $dest_port -j ACCEPT
            done
            print_info " done."
        fi

        # Keep state of connections from private subnets
        $IPTABLES -A OUTPUT  -m state --state NEW -o $NAT_LAN_IFACE -j ACCEPT
        #$IPTABLES -A FORWARD -m state --state NEW -o $NAT_LAN_IFACE -j ACCEPT
        $IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

        # hide NAT clients behind firewall: - set TTL
        # XXX: warning: this breaks traceroute !!!
        if [ ! "a$NAT_SET_TTL" = "ano" ]; then
            print_info "NAT: clients hidden behind firewall - setting TTL to $NAT_SET_TTL"
            $IPTABLES -t mangle -A POSTROUTING -o $NAT_LAN_IFACE -j TTL --ttl-set $NAT_SET_TTL
        fi


    fi
} # }}}

log_new_connections()
{ # {{{
    if [ ! -z "$NAT_LOG_NEW_CONNECTIONS" ]; then
        if [ "x$NAT_LOG_NEW_CONNECTIONS" = "xyes" ]; then
            if [ "x$NAT_LOG_NEW_CONNECTIONS" = "xyes" ]; then
                NAT_LOG_NEW_CONNECTIONS="TCP UDP"
            fi
            print_info -en "Logging new connections $NAT_LOG_NEW_CONNECTIONS:"
            for proto in $NAT_LOG_NEW_CONNECTIONS; do
                $IPTABLES_LOG -A INPUT   -m state --state NEW -p $proto -j LOG --log-prefix "IN  connection: "
                $IPTABLES_LOG -A OUTPUT  -m state --state NEW -p $proto -j LOG --log-prefix "OUT connection: "
                $IPTABLES_LOG -A FORWARD -m state --state NEW -p $proto -j LOG --log-prefix "FWD connection: "
            done
            print_info " done."
        fi
    fi
} # }}}

drop_output()
{ # {{{

    for riface in $REAL_INTERFACES; do
        drop_output_tcp="${riface}_DROP_OUTPUT_TCP"
        DROP_OUTPUT_TCP="${!drop_output_tcp}"
        drop_output_udp="${riface}_DROP_OUTPUT_UDP"
        DROP_OUTPUT_UDP="${!drop_output_udp}"

        if [ ! -z "$DROP_OUTPUT_TCP" ]; then
            print_info -en "$riface: Dropping outgoing packets from ports:"
            for port in $DROP_OUTPUT_TCP; do
                print_info -en " $port"
                $IPTABLES -A FORWARD -p TCP --sport $port -o $riface -j DROP
                $IPTABLES -A OUTPUT  -p TCP --sport $port -o $riface -j DROP
            done
            print_info " done."
        fi

        if [ ! -z "$DROP_OUTPUT_UDP" ]; then
            print_info -en "$riface: Dropping outgoing packets from ports:"
            for port in $DROP_OUTPUT_UDP; do
                print_info -en " $port"
                $IPTABLES -A FORWARD -p UDP --sport $port -o $riface -j DROP
                $IPTABLES -A OUTPUT  -p UDP --sport $port -o $riface -j DROP
            done
            print_info " done."
        fi
    done

} # }}}

bann_ip_adresses()
{ # {{{
    #
    # This feature has been developed for following reason:
    # UbiCrawler spam our website with many requests (they are duplicit requests of the same page!)
    # And this web robot doesn't accept HTTP META tags (http://www.robotstxt.org/wc/faq.html#extension)
    #
    # Bann them too!
    #
    #IP address is: 146.48.97.11 146.48.97.13
    # User Agent: "UbiCrawler/v0.4beta (http://ubi.iit.cnr.it/projects/ubicrawler/)"
    #
    cf="$DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf"
    if [ -f $cf ]; then
        BANNED_IP="$BANNED_IP `read_config_ips $cf`"
    fi
    if [ ! -z "$BANNED_IP" ]; then
        print_info -en "Dropping ALL packets from IP:"
        for banned_ip in $BANNED_IP; do
            print_info -en " $banned_ip"
            $IPTABLES -A INPUT        -s $banned_ip -j DROP
            $IPTABLES -A FORWARD    -s $banned_ip -j DROP
        done
        print_info " done."
    fi
} # }}}

allow_accept_all()
{ # {{{
    if [ ! -z "$IFACE_ACCEPT_ALL" ]; then
        print_info -en "Accepting ALL packets on interfaces:"
        for iface in $IFACE_ACCEPT_ALL; do
            print_info -en " $iface"
            $IPTABLES -A INPUT   -i $iface -j ACCEPT
            $IPTABLES -A FORWARD -i $iface -j ACCEPT
            $IPTABLES -A OUTPUT  -o $iface -j ACCEPT
        done
        print_info " done."
    fi
} # }}}

drop_input()
{ # {{{
    if [ ! -z "$NAT_LAN_IFACE" ]; then
        for client_ip in $NAT_CLIENT_DROP; do
            print_info -en " !$client_ip";
            $IPTABLES -A INPUT -s $client_ip -i $NAT_SUBNET_IFACE -j DROP
        done
    fi
    if [ ! -z "$ALL_DROP_INPUT_TCP" ]; then
        print_info -en "Drop ALL INPUT TCP connections on ports:"
        for port in $ALL_DROP_INPUT_TCP; do
            for riface in $REAL_INTERFACES; do
                print_info -en " $port($riface)"
                $IPTABLES -A INPUT -i $riface -p TCP --dport $port -j DROP
            done
        done
        print_info " done."
    fi
    if [ ! -z "$ALL_DROP_INPUT_UDP" ]; then
        print_info -en "Drop ALL INPUT UDP connections on ports:"
        for port in $ALL_DROP_INPUT_UDP; do
            for riface in $REAL_INTERFACES; do
                print_info -en " $port($riface)"
                $IPTABLES -A INPUT -i $riface -p UDP --dport $port -j DROP
            done
        done
        print_info " done."
    fi
    if [ ! -z "$REAL_DROP_INPUT_TCP" ]; then
        print_info -en "Drop REAL all INPUT TCP connections for ALL interfaces on ports:"
        for port in $REAL_DROP_INPUT_TCP; do
            print_info -en " $port(ALL)"
            $IPTABLES -A INPUT -p TCP --dport $port -j DROP
        done
        print_info " done."
    fi
    if [ ! -z "$REAL_DROP_INPUT_UDP" ]; then
        print_info -en "Drop REAL all INPUT UDP connections for ALL interfaces on ports:"
        for port in $REAL_DROP_INPUT_UDP; do
            print_info -en " $port(ALL)"
            $IPTABLES -A INPUT -p UDP --dport $port -j DROP
        done
        print_info " done."
    fi
} # }}}

reject_input()
{ # {{{
    if [ ! -z "$ALL_REJECT_INPUT_TCP" ]; then
        print_info -en "Reject ALL INPUT TCP connections on ports:"
        for port in $ALL_REJECT_INPUT_TCP; do
            for riface in $REAL_INTERFACES; do
                print_info -en " $port($riface)"
                $IPTABLES -A INPUT -i $riface -p TCP --dport $port -j REJECT --reject-with $REJECT_WITH
            done
        done
        print_info " done."
    fi
    if [ ! -z "$ALL_REJECT_INPUT_UDP" ]; then
        print_info -en "Reject ALL INPUT UDP connections on ports:"
        for port in $ALL_REJECT_INPUT_UDP; do
            for riface in $REAL_INTERFACES; do
                print_info -en " $port($riface)"
                $IPTABLES -A INPUT -i $riface -p UDP --dport $port -j REJECT --reject-with $REJECT_WITH
            done
        done
        print_info " done."
    fi
    if [ ! -z "$REAL_REJECT_INPUT_TCP" ]; then
        print_info -en "Reject REAL all INPUT TCP connections for ALL interfaces on ports:"
        for port in $REAL_REJECT_INPUT_TCP; do
            print_info -en " $port(ALL)"
            $IPTABLES -A INPUT -p TCP --dport $port -j REJECT --reject-with $REJECT_WITH
        done
        print_info " done."
    fi
    if [ ! -z "$REAL_REJECT_INPUT_UDP" ]; then
        print_info -en "Reject REAL all INPUT UDP connections for ALL interfaces on ports:"
        for port in $REAL_REJECT_INPUT_UDP; do
            for riface in $REAL_INTERFACES; do
                print_info -en " $port(ALL)"
                $IPTABLES -A INPUT -p UDP --dport $port -j REJECT --reject-with $REJECT_WITH
            done
        done
        print_info " done."
    fi
} # }}}

allow_input()
{ # {{{
    if [ ! -z "$ALL_ACCEPT_INPUT_TCP" ]; then
        print_info -en "Accepting ALL INPUT TCP connections on ports:"
        for port in $ALL_ACCEPT_INPUT_TCP; do
            src_ip=""
            eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
            for iface in $INTERFACES; do
                riface="IFname_$iface";
                print_info -en " $port($iface)"`[ ! -z $src_ip ] && echo "[$src_ip]"`
                IPS="IP_$iface";
                for ip in ${!IPS}; do
                    if [ -z "$src_ip" ]; then
                        $IPTABLES -A INPUT -i ${!riface} -d $ip -p TCP --dport $port -j ACCEPT
                    else
                        $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP --dport $port -j ACCEPT
                    fi
                done
            done
        done
        print_info " done."
    fi
    if [ ! -z "$ALL_ACCEPT_INPUT_UDP" ]; then
        print_info -en "Accepting ALL INPUT UDP connections on ports:"
        for port in $ALL_ACCEPT_INPUT_UDP; do
            src_ip=""
            eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
            for iface in $INTERFACES; do
                riface="IFname_$iface";
                print_info -en " $port($iface)"`[ ! -z $src_ip ] && echo "[$src_ip]"`
                IPS="IP_$iface";
                for ip in ${!IPS}; do
                    if [ -z "$src_ip" ]; then
                        $IPTABLES -A INPUT -i ${!riface} -d $ip -p UDP --dport $port -j ACCEPT
                    else
                        $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP --dport $port -j ACCEPT
                    fi
                done
            done
        done
        print_info " done."
    fi

    if [ ! -z "$REAL_ACCEPT_INPUT_TCP" ]; then
        print_info -en "Accepting REAL all INPUT TCP connections for ALL interfaces on ports:"
        for port in $REAL_ACCEPT_INPUT_TCP; do
            src_ip=""
            eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
            print_info -en " $port(ALL)"`[ ! -z $src_ip ] && echo "[$src_ip]"`
            if [ -z "$src_ip" ]; then
                $IPTABLES -A INPUT -p TCP --dport $port -j ACCEPT
            else
                $IPTABLES -A INPUT -s $src_ip -p TCP --dport $port -j ACCEPT
            fi
        done
        print_info " done."
    fi
    if [ ! -z "$REAL_ACCEPT_INPUT_UDP" ]; then
        print_info -en "Accepting REAL all INPUT UDP connections for ALL interfaces on ports:"
        for port in $REAL_ACCEPT_INPUT_UDP; do
            src_ip=""
            eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
            print_info -en " $port(ALL)"`[ ! -z $src_ip ] && echo "[$src_ip]"`
            if [ -z "$src_ip" ]; then
                $IPTABLES -A INPUT -p UDP --dport $port -j ACCEPT
            else
                $IPTABLES -A INPUT -s $src_ip -p UDP --dport $port -j ACCEPT
            fi
        done
        print_info " done."
    fi

    for iface in $INTERFACES; do
        riface="IFname_$iface";
        IPS="IP_$iface";

        redirect_tcp="${iface}_REDIRECT_TCP"
        REDIRECT_TCP="${!redirect_tcp}"
        redirect_udp="${iface}_REDIRECT_UDP"
        REDIRECT_UDP="${!redirect_udp}"

        reject_input_tcp="${iface}_REJECT_INPUT_TCP"
        REJECT_INPUT_TCP="${!reject_input_tcp}"
        reject_input_udp="${iface}_REJECT_INPUT_UDP"
        REJECT_INPUT_UDP="${!reject_input_udp}"

        accept_input_tcp="${iface}_ACCEPT_INPUT_TCP"
        ACCEPT_INPUT_TCP="${!accept_input_tcp}"
        accept_input_udp="${iface}_ACCEPT_INPUT_UDP"
        ACCEPT_INPUT_UDP="${!accept_input_udp}"

        if [ ! -z "$REDIRECT_TCP" ]; then
            print_info -en "$iface: redirecting TCP connections:"
            ip="`get_first_ip_addr IP_$iface`";
            for redirect in $REDIRECT_TCP; do
                eval `echo $redirect | \
                    $AWK -v FS=: '    (NF == 2) { remote_ip = "0.0.0.0/0"; from_port = $1; to_port = $2; } \
                                    (NF == 3) { remote_ip = $1;          from_port = $2; to_port = $3; } \
                                    END { printf "remote_ip=%s; from_port=%s; to_port=%s;", remote_ip, from_port, to_port; }'`
                print_info -en " $remote_ip:$from_port->$to_port"
                $IPTABLES -t nat -A PREROUTING -p TCP -i ${!riface} -s $remote_ip -d $ip --dport $from_port -j REDIRECT --to-port $to_port
            done
            print_info " done."
        fi

        if [ ! -z "$REDIRECT_UDP" ]; then
            print_info -en "$iface: redirecting UDP connections:"
            ip="`get_first_ip_addr IP_$iface`";
            for redirect in $REDIRECT_UDP; do
                eval `echo $redirect | \
                    $AWK -v FS=: '    (NF == 2) { remote_ip = "0.0.0.0/0"; from_port = $1; to_port = $2; } \
                                    (NF == 3) { remote_ip = $1;          from_port = $2; to_port = $3; } \
                                    END { printf "remote_ip=%s; from_port=%s; to_port=%s;", remote_ip, from_port, to_port; }'`
                print_info -en " $remote_ip:$from_port->$to_port"
                $IPTABLES -t nat -A PREROUTING -p UDP -i ${!riface} -s $remote_ip -d $ip --dport $from_port -j REDIRECT --to-port $to_port
            done
            print_info " done."
        fi

        # REJECT {{{
        if [ ! -z "$REJECT_INPUT_TCP" ]; then
            print_info -en "$iface: Rejecting INPUT TCP connections on ports:"
            for port in $REJECT_INPUT_TCP; do
                src_ip=""
                eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
                print_info -en " $port"`[ ! -z $src_ip ] && echo "[$src_ip]"`
                for ip in ${!IPS}; do
                    if [ -z $src_ip ]; then
                        $IPTABLES -A INPUT -i ${!riface} -d $ip -p TCP --dport $port -j REJECT --reject-with $REJECT_WITH
                    else
                        $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP --dport $port -j REJECT --reject-with $REJECT_WITH
                    fi
                done
            done
            print_info " done."
        fi

        if [ ! -z "$REJECT_INPUT_UDP" ]; then
            print_info -en "$iface: Rejecting INPUT UDP connections on ports:"
            for port in $REJECT_INPUT_UDP; do
                src_ip=""
                eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
                print_info -en " $port"`[ ! -z $src_ip ] && echo "[$src_ip]"`
                for ip in ${!IPS}; do
                    if [ -z $src_ip ]; then
                        $IPTABLES -A INPUT -i ${!riface} -d $ip -p UDP --dport $port -j REJECT --reject-with $REJECT_WITH
                    else
                        $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP --dport $port -j REJECT --reject-with $REJECT_WITH
                    fi
                done
            done
            print_info " done."
        fi
        # }}}

        # ACCEPT {{{
        if [ ! -z "$ACCEPT_INPUT_TCP" ]; then
            print_info -en "$iface: Accepting INPUT TCP connections on ports:"
            for port in $ACCEPT_INPUT_TCP; do
                src_ip=""
                eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
                if [ -n "$src_ip" -a "$port" = "0" ]; then
                    port="ALL";
                fi
                print_info -en " $port"`[ ! -z $src_ip ] && echo "[$src_ip]"`
                for ip in ${!IPS}; do
                    if [ -z $src_ip ]; then
                        $IPTABLES -A INPUT -i ${!riface} -d $ip -p TCP --dport $port -j ACCEPT
                    else
                        if [ "$port" = "ALL" ]; then
                            $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP -j ACCEPT
                        else
                            $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p TCP --dport $port -j ACCEPT
                        fi
                    fi
                done
            done
            print_info " done."
        fi

        if [ ! -z "$ACCEPT_INPUT_UDP" ]; then
            print_info -en "$iface: Accepting INPUT UDP connections on ports:"
            for port in $ACCEPT_INPUT_UDP; do
                src_ip=""
                eval `echo $port | awk -v FS=: '/:/ { printf "src_ip=\"%s\"; port=\"%s\";", $1, $2; }'`
                if [ -n "$src_ip" -a "$port" = "0" ]; then
                    port="ALL";
                fi
                print_info -en " $port"`[ ! -z $src_ip ] && echo "[$src_ip]"`
                #$IPTABLES -A INPUT -i $iface -d ${!INET_IP} -p UDP --dport $port -j ACCEPT
                #$IPTABLES -A INPUT -i $iface --source 192.168.1.0/16 -p UDP --dport $port -j ACCEPT
                for ip in ${!IPS}; do
                    if [ -z $src_ip ]; then
                        $IPTABLES -A INPUT -i ${!riface} -d $ip -p UDP --dport $port -j ACCEPT
                    else
                        if [ "$port" = "ALL" ]; then
                            $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP -j ACCEPT
                        else
                            $IPTABLES -A INPUT -i ${!riface} -s $src_ip -d $ip -p UDP --dport $port -j ACCEPT
                        fi
                    fi
                done
            done
            print_info " done."
        fi
        # }}}
    done

    # Enable outgoing TRACEROUTE requests (required e.g. by Skype, http://www.skype.com)
    if [ ! -z "$TRACEROUTE_IFACE" ]; then
        ip="`get_first_ip_addr IP_$ANTISPOOF_IFACE`";
        print_info -en "Accepting traceroute:"

        $IPTABLES -A OUTPUT -o $ANTISPOOF_IFACE -p UDP \
            --sport $TRACEROUTE_SRC_PORTS --dport $TRACEROUTE_DEST_PORTS \
            -s $ip -d $ANYWHERE -j ACCEPT

        for iface in $TRACEROUTE_IFACE; do
            $IPTABLES -A FORWARD -p UDP -i $iface --sport $TRACEROUTE_SRC_PORTS \
                --dport $TRACEROUTE_DEST_PORTS -j ACCEPT
        done
        print_info " done."
    fi

} # }}}

# ACCEPT all packets from our IP address
allow_output()
{ # {{{

    # Povolíme odchozí pakety, které mají naše IP adresy
    print_info -en "Accepting OUTPUT packets from"
    for iface in $INTERFACES; do
        riface="IFname_$iface";
        IPS="IP_$iface";
        for ip in ${!IPS}; do
            print_info -en " $ip($iface)"
            $IPTABLES -A OUTPUT -o ${!riface} -s $ip -j ACCEPT
        done
    done;
    print_info " done.";

} # }}}

allow_icmp()
{ # {{{

    print_info -en "Accepting ICMP packets:"

    # accept only allowed ICMP packets
    for type in $ACCEPT_ICMP_PACKETS; do
        print_info -en " $type"
        for iface in $INTERFACES; do
            riface="IFname_$iface";
            IPS="IP_$iface";
            for ip in ${!IPS}; do
                $IPTABLES -A INPUT -i ${!riface} -d $ip -p ICMP --icmp-type $type -j ACCEPT
            done
        done
    done
    #$IPTABLES_LOG -A INPUT  -p ICMP -j LOG --log-prefix "IN  ICMP: "
    #$IPTABLES_LOG -A OUTPUT -p ICMP -j LOG --log-prefix "OUT ICMP: "
    print_info " done."

} # }}}

log_input_drop()
{ # {{{

    if [ ! "x$LOGGING" = "xoff" ]; then
        prefix="input drop: "
        print_info "Input drop is logged with prefix '$prefix'"
        $IPTABLES_LOG -A INPUT $LOG_LIMIT "$prefix"
    fi

} # }}}

log_output_drop()
{ # {{{

    if [ ! "x$LOGGING" = "xoff" ]; then
        prefix="output drop: "
        print_info "Output drop is logged with prefix '$prefix'"
        $IPTABLES_LOG -A OUTPUT $LOG_LIMIT "$prefix"
    fi

} # }}}

log_forward_drop()
{ # {{{

    if [ ! "x$LOGGING" = "xoff" ]; then
        prefix="forward drop: "
        print_info "Forward drop is logged with prefix '$prefix'"
        $IPTABLES_LOG -A FORWARD $LOG_LIMIT "$prefix"
    fi

} # }}}

configure_special_rules()
{ # {{{

    print_info -en "Loading special rules: "
    ##
    ## for DSL from Slovanet (Slovak DSL provider) and DSL modem DLINK DSL-360T you must add following rule for proper ssh connect to your machine
    ##
    # print_info -en "slovanet "
    # $IPTABLES -t mangle -A OUTPUT -s 0/0 -j DSCP --set-dscp 0

    print_info " done.";

} # }}}

do_ip_accounting()
{ # {{{

    if [ ! "x$DO_LOCAL_IP_ACCOUNTING" = "xno" ]; then
        if [ ! -z "$NAT_LAN_IFACE" ]; then
            IPACCT_NAME="ZORBCOUNT"
            IPACCT_IN_NAME="ZORBCOUNTIN"
            IPACCT_OUT_NAME="ZORBCOUNTOUT"
            $IPTABLES -N $IPACCT_NAME        # whole network
            $IPTABLES -N $IPACCT_IN_NAME    # download: from server to client
            $IPTABLES -A $IPACCT_IN_NAME
            $IPTABLES -N $IPACCT_OUT_NAME    # upload: from client to server
            $IPTABLES -A $IPACCT_OUT_NAME

            ip="`get_first_ip_addr IP_$NAT_SUBNET_IFACE`";
            netmask="Mask_$NAT_SUBNET_IFACE"
            localnet="$ip/${!netmask}"

            $IPTABLES -I INPUT  -i $NAT_LAN_IFACE -j $IPACCT_IN_NAME
            $IPTABLES -I OUTPUT -o $NAT_LAN_IFACE -j $IPACCT_OUT_NAME

            $IPTABLES -I FORWARD -s $localnet -o $NAT_LAN_IFACE -j $IPACCT_NAME
            $IPTABLES -I FORWARD -d $localnet -i $NAT_LAN_IFACE -j $IPACCT_NAME

            for client_ip in $IP_ACCT_CLIENTS; do
                $IPTABLES -A $IPACCT_NAME -s $client_ip
                $IPTABLES -A $IPACCT_NAME -d $client_ip
            done

            if [ ! "x$DO_LOCAL_IP_ACCOUNTING" = "xno" ]; then
                accountig_ports=`echo "$NAT_TCP_PORT_REDIRECT " | $AWK -v RS=' ' -v FS=:  '{ print $2; }' | sort -u -r -g `
                for port in $accountig_ports; do
                    $IPTABLES -I INPUT -i $NAT_SUBNET_IFACE -p TCP --dport $port -j $IPACCT_NAME
                    $IPTABLES -I INPUT -i $NAT_SUBNET_IFACE -p UDP --dport $port -j $IPACCT_NAME
                    $IPTABLES -I OUTPUT -o $NAT_SUBNET_IFACE -p TCP --sport $port -j $IPACCT_NAME
                    $IPTABLES -I OUTPUT -o $NAT_SUBNET_IFACE -p UDP --sport $port -j $IPACCT_NAME
                done
            fi

            $IPTABLES -A $IPACCT_NAME -s $localnet
            $IPTABLES -A $IPACCT_NAME -d $localnet
            
        fi
    fi

} # }}}

accept_related()
{ # {{{

    print_info -en "Accepting ESTABLISHED, RELATED packets ..."
    $IPTABLES -A INPUT    -m state --state ESTABLISHED,RELATED -j ACCEPT
    $IPTABLES -A OUTPUT    -m state --state ESTABLISHED,RELATED -j ACCEPT
    print_info " done."

} # }}}

accept_loopback()
{ # {{{
    
    # Loopback není radno omezovat
    print_info -en "Accepting loopback:"
    $IPTABLES -A INPUT  -i $LO_IFACE -j ACCEPT
    $IPTABLES -A OUTPUT -o $LO_IFACE -j ACCEPT
    print_info " done."

} # }}}

#
# Shaping support {{{
#
# http://koti.welho.com/ntoivol2/shaping/
#

shaping_on()
{ # {{{

    mark_idx=1
    if [ ! -z $SHAPING_IFACE ]; then
        for iface in $SHAPING_IFACE; do
            echo "Shaping for interface $iface"
            shaping_classes="${iface}_SHAPING_CLASSES"

            # root qdisc: 2-band prio with everything defaulting to band 0
            $TC qdisc add dev $iface root handle 1: prio bands 2 priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

            for class in ${!shaping_classes}; do
                rate="${iface}_SHAPING_RATE_${class}"
                latency="${iface}_SHAPING_LATENCY_${class}"
                burst="${iface}_SHAPING_BURST_${class}"
                netmask="${iface}_SHAPING_NETMASK_${class}"
                echo -e "\tshaping \"$class\" traffic: rate=${!rate} burst=${!burst} netmask=${!netmask}"
                if [ -z ${!netmask} ]; then
                    $IPTABLES -t mangle -A OUTPUT -j MARK --set-mark 0x$mark_idx
                else
                    $IPTABLES -t mangle -A OUTPUT -d ${!netmask} -j MARK --set-mark 0x$mark_idx
                fi

                if [ -z ${!rate} ]; then
                    # SFQ for local traffic
                    $TC qdisc add dev $iface parent 1:$mark_idx handle $((10 + $mark_idx)): sfq perturb 10
                else
                    # TBF shaping and SFQ for internet traffic
                    $TC qdisc add dev $iface parent 1:$mark_idx handle $((10 + $mark_idx)): tbf rate ${!rate} burst ${!burst} latency ${!latency}
                    $TC qdisc add dev $iface parent $((10 + $mark_idx)): handle $((10 * $mark_idx)): sfq perturb 10
                fi

                mark_idx=$(($mark_idx + 1))
            done
        done
    fi

} # }}}

shaping_off()
{ # {{{
    if [ ! -z $SHAPING_IFACE ]; then
        echo -en "Shaping turned off for interface"
        for iface in $SHAPING_IFACE; do
            echo -en " $iface"
            $TC qdisc del dev $iface root 2>/dev/null
        done
        echo ". done"
    fi
} # }}}

shaping_status()
{ # {{{
    if [ ! -z $SHAPING_IFACE ]; then
        echo "# Shaping status: "
        $TC qdisc list
    else
        echo "# Shaping turned off"
    fi
} # }}}

# }}}

add_banned_ip()
{ # {{{
    echo "# `date '+%Y-%m-%d %X' ` - ${SSH_CLIENT:=local}" >> $DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf
    TMPFILE=`mktemp -t fw-universal.sh-XXXXXX` || exit 1
    trap 'rm -f $TMPFILE' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    if [ -z "$*" ]; then
        print_info "Reading banned IP's from STDIN:"
        cat >> $TMPFILE
    else
        for IP in $*; do
            echo $IP >> $TMPFILE;
        done
    fi
    read_config_ips $TMPFILE >> $DEFAULT_FIREWALL_CONFIG_DIR/BANNED_IP.conf
    rm -f $TMPFILE
} # }}}

deploy_block()
{ # {{{
    if [ -z "$*" ]; then
        echo "Usage: $0 deploy-block IP1/netmask1 IP2/netmask2 ..."
        exit 1;
    fi
    print_info "Deploying to local rules ..."
    add_banned_ip $*
    # start the some script twice to refresh rules (new blocked IP's)
    QUIET=yes $0 start
    TMPFILE=`mktemp -t fw-universal.sh-XXXXXX` || exit 1
    trap 'rm -f $TMPFILE' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    for i in $*; do
        echo $i >> $TMPFILE;
    done
    while read conn keyfile
    do
       case "$conn" in
           ""|\#*)
               continue
               ;;
       esac
       print_info "Deploying to $conn ...";
       cat $TMPFILE | ssh -i $keyfile $conn $0 block
    done < $DEFAULT_FIREWALL_CONFIG_DIR/deploy-servers.list
    rm -f $TMPFILE
} # }}}

# Parse output from ifconfig: - tested on Linux and FreeBSD
# http://platon.sk/cvs/cvs.php/scripts/shell/firewall/ifconfig-parse.sh
parse_ifconfig()
{ # {{{
    # Parse output from ifconfig:
    parsed_interfaces=`$IFCONFIG | \
        $PERL -e '
my $iface_count = 0;
my $iface;
my (%ip, %ifname, %ip6, %scope6, %bcast, %mask, %hwaddr, %ipcount);

while (my $line = <STDIN>) {
    chomp $line;
    if ($line =~ m/^([a-z0-9:]+)\s+.*?([a-z0-9:]+)\s*$/i) { # Linux interface
        $iface    = $1;
        my $iface_hwaddr = $2;
        my $x_iface    = $iface;
        $iface    =~ s/:/_/; # convert "eth0:0" --> "eth0_0"
        $x_iface        = [ $x_iface =~ m/^([a-z0-9]+)/i ]->[0]; # convert "eth0:0" --> "eth0"
        $ifname{$iface} = $x_iface;
        $ipcount{$iface}++;
        $hwaddr{$iface} = $iface_hwaddr;
        $iface_count++;
    }
    elsif ($line =~ m/^[ \t]+inet addr:/) { # Linux IP address
        die unless defined $iface;
        my @fields = split(/[\s:]+/, $line);
        push @{$ip{$iface}}, $fields[3];
        $bcast{$iface} = $fields[5]    || ""; # invalid for loopback interface lo, but we don t need this
        $mask{$iface} = $fields[7]    || $fields[5]; # for loopback interface lo
    }
    elsif($line =~ m/^[ \t]+inet6 addr:/) { # Linux IPv6 address
        die unless defined $iface;
        my @fields = split(/\s+/, $line);
        push @{$ip6{$iface}}, $fields[3];
        $scope6{$iface} = [ $fields[4] =~ m/Scope:(.*)$/i ]->[0];
    }

}

map { printf "IP_%s=\"%s\";            export IP_%s;\n",        $_, join(" ", @{$ip{$_}}),    $_; } keys %ip;
map { printf "IFACE_6_%s=\"%s\";    export IFACE_6_%s;\n",    $_, join(" ", @{$ip6{$_}}),    $_; } keys %ip6;
map { printf "SCOPE_6_%s=\"%s\";    export SCOPE_6_%s;\n",    $_, $scope6{$_},    $_; } keys %scope6;
map { printf "Bcast_%s=\"%s\";        export Bcast_%s;\n",    $_, $bcast{$_},    $_; } keys %bcast;
map { printf "Mask_%s=\"%s\";        export Mask_%s;\n",        $_, $mask{$_},    $_; } keys %mask;
map { printf "HWaddr_%s=\"%s\";        export HWaddr_%s;\n",    $_, $hwaddr{$_},    $_; } keys %hwaddr;
map { printf "IPcount_%s=\"%s\";    export IPcount_%s;\n",    $_, $ipcount{$_},    $_; } keys %ipcount;
map { printf "IFname_%s=\"%s\";        export IFname_%s;\n",    $_, $ifname{$_},    $_; } keys %ifname;
printf "interfaces=\"%s\";     export interfaces;\n", join(" ", sort keys %ip);
    '`
    eval "$parsed_interfaces";
    #echo "$parsed_interfaces";

    parsed_routes=`$PERL -e '
    $\ = "\n";
    open(FILE, "/proc/net/route") or die "Can not open /proc/net/route: $!";
    my @columns = split(/\s+/, <FILE>);
    while (my $line = <FILE>) {
        my $iface;
        my @vals = split(/\s+/, $line);
        foreach my $key (@columns) {
            $iface->{$key} = shift @vals;
        }
        
        foreach my $key (qw( Gateway Destination )) {
            print "${key}_$iface->{Iface}=",
                qw("), hex2ip($iface->{$key}), qw("),
                "; export ${key}_$iface->{Iface};";
        }
        foreach my $key (qw( Flags MTU Metric Window IRTT )) {
            print "${key}_$iface->{Iface}=",
                qw("), $iface->{$key}, qw("),
                "; export ${key}_$iface->{Iface};";
        }
    }
    close(FILE);


    sub hex2ip
    { # {{{
        my ($str) = @_;
        my @block;

        my $hex = uc($str);

        while (length($hex)) {
            my $x = ord(substr($hex, 0, 1));
            my $y = ord(substr($hex, 1, 1));

            $x = $x > 64 ? $x - 55 : $x - 48;
            $y = $y > 64 ? $y - 55 : $y - 48;

            push @block, 16 * $x + $y;
            $hex = substr($hex, 2);
        }

        return join(".", reverse @block);

    } # }}}
    '`
    eval "$parsed_routes";

    # Now we have defined variables like this:
    # IFACE_eth0 HWaddr_eth0 IP_eth0 Bcast_eth0 Mask_eth0
    # IFACE_lo   HWaddr_lo   IP_lo   Bcast_lo   Mask_lo
    # interfaces

} # }}}

# helper function for string padding
str_pad_right()
{ # {{{
    num="$1";
    string="$2";
    count=$(echo -n "$string" | wc -c);
    count=$((count + 0))
    while [ $count -lt $num ]; do
        string="$string ";
        count=$((count + 1));
    done
    echo -n "$string"
    return;
} # }}}

pad7()  { str_pad_right  7 "$1"; }
pad15() { str_pad_right 15 "$1"; }


check_tools
parse_ifconfig
print_iface_status

#
# Split interfaces into 2 groups:
#
# $INTERFACES_ACCEPT_ALL - interfaces withouth restrictions
#
# $INTERFACES - all interfaces withouth loopback
#               and devices without restrictions (e.g. tun0 tun1 tap0 eth0_0 eth0_1 ...)
#
# $REAL_INTERFACES - aliases like eth0:0, eth1:0 are transformed to eth0, eth1, ...
#
# list of all interfaces is in $interfaces variable
#
INTERFACES=""
INTERFACES_ACCEPT_ALL=""
x_REAL_INTERFACES=""
regexp='^\('`echo $IFACE_ACCEPT_ALL | sed 's/ /\\\|/g; s/+/.*/g;'`'\)$'
for iface in $interfaces; do
    riface="IFname_$iface";
    x_REAL_INTERFACES="$x_REAL_INTERFACES ${!riface}"
    #if [ "o$iface" = "olo" ]; then continue; fi
    echo $iface | grep -q -e "$regexp"
    if [ $? = 0 ] || [ "o$iface" = "olo" ]; then # lo interface is always here
        INTERFACES_ACCEPT_ALL="$INTERFACES_ACCEPT_ALL $iface";
    else
        INTERFACES="$INTERFACES $iface";
    fi
done
REAL_INTERFACES="`echo $x_REAL_INTERFACES | awk -v RS=' ' '{ print; }' | sort -u`"
INTERFACES_ACCEPT_ALL="$IFACE_ACCEPT_ALL"


case "$1" in
    start)
        print_info -n "Starting $DESC: "
        # Inicialize modules
        #$DEPMOD -a
        load_modules
        load_cache
        set_default_policy
        remove_chains
        #
        # (un)commnet next lines as needed
        #
        bann_ip_adresses
        allow_accept_all
        nmap_scan_filter
        invalid_packet_filter
        anti_spoof_filter
        #syn_flood
        mangle_prerouting
        mangle_output
        accept_related
        log_new_connections
        drop_output
        drop_input
        reject_input
        allow_input
        allow_output
        allow_icmp
        accept_loopback
        masquerade
        log_input_drop
        log_output_drop
        log_forward_drop
        forward_on
        do_ip_accounting
        shaping_off
        shaping_on
        configure_special_rules
        $IPTABLES_SAVE -c > $CACHE_FILE
        ;;
        
    stop)
        print_info -n "Stopping $DESC: "
        shaping_off
        set_default_policy
        remove_chains
        unload_modules
        forward_off
        accept_related
        ;;

    really-off)
        print_info -n "Stopping $DESC: removing ALL rules, all packets are dropped !!"
        set_default_policy
        remove_chains
        unload_modules
        forward_off
        ;;

    status)
        print_iface_status; echo
        $IPTABLES -L -nv
        shaping_status
        ;;

    purge)
        find $DEFAULT_CACHE_DIR -type f -ls -exec rm -f {} \;
        ;;
    block)
        shift;
        add_banned_ip $*;
        # start the some script twice to refresh rules (new blocked IP's)
        QUIET=yes $0 start;
        ;;
    deploy-block)
        shift;
        deploy_block $*;
        ;;
    *)
        echo "Usage: $0 {start|stop|really-off|status|purge|block|deploy-block}" >&2
        exit 1
        ;;
esac

exit 0

# vim600: fdm=marker fdl=0 fdc=3


Platon Group <platon@platon.org> http://platon.org/
Copyright © 2002-2006 Platon Group
Site powered by Metafox CMS
Go to Top