Talks, papers and publications
#!/bin/sh
###############################################################
#
# modular packet filter using iptables
# 
# (c) 2004 Markus Schade
#
# License: GPLv2 or later
#
###############################################################


IPT="/sbin/iptables"
IPTR="/sbin/iptables-restore"
IPTS="/sbin/iptables-save"
DESC="IPTables Netfilter"
INNER="eth2"
DEAD="eth1"
OUTER="eth0"
OUTERIP="134.109.96.136"
INNERIP="192.168.1.1"
INNERSUB="192.168.1.0/24"


# define more Variables

test -x $IPT || exit 0

set -e

################### Functions ######################

# define Functions
function setup_inputfw() {
        $IPT -P INPUT DROP

        $IPT -N icmp_packets
        $IPT -N CHECK_FLAGS
        $IPT -N Server

        setup_inputchains

        # Eigentliche INPUT Chain - Von hier aus wird in die Subchains verzweigt

        # ICMP fangen wir gleich mal zu ab
        $IPT -A INPUT -p icmp -j icmp_packets

        # Conntrack
        $IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
        $IPT -A INPUT -m state --state NEW -j Server
        $IPT -A INPUT -m limit --limit 10/m -m state --state INVALID -j LOG --log-prefix "INVALID INPUT DROP: "
        $IPT -A INPUT -m state --state INVALID -j DROP

        # Der Rest wird von der Policy erschlagen (was auch immer da kommen mag)
        $IPT -A INPUT -m limit --limit 10/m -j LOG --log-prefix "INPUT DROP POLICY: "


}

function setup_inputchains() {

        # Subchains aufbauen:

        ########################################################
        # icmp_packets chain
        ########################################################
        # icmp protection (really? *g*)

        # Chain loeschen
        echo -n "icmp_packets "

        $IPT -F icmp_packets

        # nur icmp echo-request sollte new sein, der rest established
        $IPT -A icmp_packets -p icmp --icmp-type echo-request -m limit \
                --limit 5/s -m state --state NEW -j ACCEPT
        $IPT -A icmp_packets -p icmp --icmp-type echo-request -m limit \
                --limit 5/m -j LOG --log-prefix "PING:"

        # nu ist gut mit rumgepinge
        $IPT -A icmp_packets -p icmp --icmp-type echo-request -j DROP

        $IPT -A icmp_packets -p icmp --icmp-type echo-reply -m state \
                --state ESTABLISHED -j ACCEPT

        $IPT -A icmp_packets -p icmp --icmp-type destination-unreachable -j ACCEPT

        $IPT -A icmp_packets -p icmp --icmp-type time-exceeded -j ACCEPT

        $IPT -A icmp_packets -p icmp --icmp-type parameter-problem -j ACCEPT

        $IPT -A icmp_packets -p icmp -m limit --limit 5/m -j LOG --log-prefix "ICMP DROP: "
        $IPT -A icmp_packets -p icmp -j DROP


        ########################################################
        # CHECK_FLAGS Chain
        ########################################################
        # typische Portscans

        echo -n "CHECK_FLAGS "        
        $IPT -F CHECK_FLAGS

        $IPT -A CHECK_FLAGS -p tcp --tcp-flags ALL FIN,URG,PSH -m limit \
                --limit 5/m -j LOG --log-prefix "NMAP-XMAS: "
        $IPT -A CHECK_FLAGS -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP

        $IPT -A CHECK_FLAGS -p tcp --tcp-flags ALL NONE -m limit \
                --limit 5/m -j LOG --log-prefix "NMAP-NULL: "
        $IPT -A CHECK_FLAGS -p tcp --tcp-flags ALL NONE -j DROP

        $IPT -A CHECK_FLAGS -p tcp --tcp-flags ALL FIN -m limit \
                --limit 5/m -j LOG --log-prefix "NMAP-FIN: "
        $IPT -A CHECK_FLAGS -p tcp --tcp-flags ALL FIN -j DROP

        # kaputte Verbindungsaufbauten

        $IPT -A CHECK_FLAGS -p tcp --tcp-flags SYN,RST SYN,RST -m limit \
                --limit 5/m -j LOG --log-prefix "SYN/RST: "
        $IPT -A CHECK_FLAGS -p tcp --tcp-flags SYN,RST SYN,RST -j DROP

        $IPT -A CHECK_FLAGS -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit \
                --limit 5/m -j LOG --log-prefix "SYN/FIN: "
        $IPT -A CHECK_FLAGS -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

        $IPT -A CHECK_FLAGS -p tcp --tcp-flags SYN,ACK SYN,ACK -m limit \
                --limit 5/m -j LOG --log-prefix "SYN/ACK: "
        $IPT -A CHECK_FLAGS -p tcp --tcp-flags SYN,ACK SYN,ACK -j REJECT --reject-with tcp-reset


        # Neue TCP Pakete sollten ein Syn-flag haben. (außer DNS)
        $IPT -A CHECK_FLAGS -p tcp --dport ! 53 ! --syn -m limit \
                --limit 10/m -j LOG --log-prefix "NEW NOT SYN: "
        $IPT -A CHECK_FLAGS -p tcp --dport ! 53 ! --syn -j DROP

        ##########################################################
        # Server Chain
        ##########################################################
        
        echo -n "Server "
        $IPT -F Server

        # accept all from the local interface (in god we trust)
        $IPT -A Server -i lo -j ACCEPT

        # private Adressraeume ungeloggt entsorgen, sonst gibts
        # zuviel muell (die gibts maximal auf nem Tunnel-IF oder am internen IF

        $IPT -A Server  -i eth+ -s 10.0.0.0/8 -j DROP
        $IPT -A Server  -s 169.254.0.0/16 -j DROP
        $IPT -A Server  -s 172.16.0.0/12 -j DROP
        $IPT -A Server  -i ! $INNER -s 192.168.0.0/16 -j DROP

        # Multicast
        $IPT -A Server -d 236.83.227.179 -j ACCEPT
        $IPT -A Server -d 224.0.0.0/8 -j DROP

        # Am inneren nur privates Subnetz
        $IPT -A Server -i $INNER -s ! $INNERSUB -j DROP

        # Nein, ich beantworte keine DHCP Requests, außer von intern
        $IPT -A Server  -i ! $INNER -d 255.255.255.255 -j DROP

        # Das ungenutze Interface wird tot geschaltet
        $IPT -A Server -i $DEAD -j DROP

        # Nach dem wir das geklaert haben, koennten wir uns mal den Verbindungen widmen

        # Wenn nicht von Loopback, schauen wir beim tcp genauer hin

        $IPT -A Server -p tcp -j CHECK_FLAGS

        # Dienste, wunderschoene Dienste, frei fuer alle...
	# FTP
        $IPT -A Server -p tcp --dport 21 -j ACCEPT

        # SSH 
        $IPT -A Server -p tcp --dport 22 -j ACCEPT

        # DNS
        $IPT -A Server -p udp --dport 53 -j ACCEPT
        # DNS tcp 
        $IPT -A Server -p tcp --dport 53 ! --syn -j ACCEPT

        # Finger
        $IPT -A Server -p tcp --dport 79 -j ACCEPT

        # HTTP(S)
        $IPT -A Server -p tcp --dport 80 -j ACCEPT
        $IPT -A Server -p tcp --dport 443 -j ACCEPT

        # Auth
        $IPT -A Server -p tcp --dport 113 -j ACCEPT

        # NTP
        $IPT -A Server -p udp --dport 123 -j ACCEPT

        # Samba (im offenen Internet will man das nicht)
        $IPT -A Server -p udp --dport 137:138 -j ACCEPT
        $IPT -A Server -p tcp --dport 139 -j ACCEPT
        $IPT -A Server -p tcp --dport 445 -j ACCEPT

        # Talk        
        $IPT -A Server -p udp --dport 517:518 -j ACCEPT

        # AFS-Callback Service
        $IPT -A Server -p udp --dport 7001 -j ACCEPT

        # Zum Schluss erlaube ich mal die internen IPs auf alle Ports
        $IPT -A Server -i $INNER -s $INNERSUB -j ACCEPT

        # Der Rest waeren Verbindungen auf nicht absichtlich angebotene Dienste
        $IPT -A Server -m limit --limit 10/m -j LOG --log-prefix "UNWANTED_IN: "
        $IPT -A Server -p tcp -j REJECT --reject-with tcp-reset
        $IPT -A Server -j DROP
}

function setup_forwardfw() {
        $IPT -P FORWARD DROP

        $IPT -F FORWARD
        $IPT -N Forward_NEW

        setup_forwardchains

        # Conntrack
        $IPT -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
        $IPT -A FORWARD -m state --state NEW -j Forward_NEW

        $IPT -A FORWARD -m limit --limit 10/m -m state \
                --state INVALID -j LOG --log-prefix "--invalid forward drop-- "
        $IPT -A FORWARD -m state --state INVALID -j DROP

        # Der Rest wird von der Policy erschlagen (was auch immer da kommen mag)
        $IPT -A FORWARD -m limit --limit 10/m -j LOG --log-prefix "FORWARD DROP POLICY: "

}

function setup_forwardchains() {

        echo -n "Forward_NEW "
        $IPT -F Forward_NEW
        $IPT -A Forward_NEW -p tcp -j CHECK_FLAGS

        $IPT -A Forward_NEW -i $INNER -o $OUTER -s $INNERSUB -j ACCEPT
        $IPT -A Forward_NEW -i $OUTER -o $INNER -d $INNERSUB -j ACCEPT
        
}

function setup_outputfw() {
        $IPT -P OUTPUT ACCEPT
        
        $IPT -A OUTPUT -o $DEAD -j DROP
}
################### Procedures #####################

case "$1" in
  start)
	echo -n "Starting $DESC: $NAME"

        /sbin/modprobe ip_tables
        /sbin/modprobe ip_conntrack
        /sbin/modprobe ip_conntrack_ftp
        /sbin/modprobe ip_conntrack_irc
        /sbin/modprobe ip_conntrack_talk

        echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
        echo 1 > /proc/sys/net/ipv4/tcp_syncookies
        echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
        echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects

        # Alle Regeln loeschen

        $IPT -F
        $IPT -X
        $IPT -t nat -F
        $IPT -t nat -X
        $IPT -t mangle -F
        $IPT -t mangle -X

        # Regeln aufbauen

        setup_inputfw
        setup_forwardfw
        setup_outputfw


        # NAT und Forwarding aktivieren
        $IPT -t nat -A POSTROUTING -o eth0 -j SNAT --to $OUTERIP
        echo 1 > /proc/sys/net/ipv4/ip_forward

	echo "done."
	;;
  stop)
	echo -n "Stopping $DESC: $NAME "
        echo 0 > /proc/sys/net/ipv4/ip_forward
        $IPT -F
        $IPT -X
        $IPT -t mangle -F
        $IPT -t mangle -X
        $IPT -P INPUT ACCEPT
        $IPT -P OUTPUT ACCEPT
        $IPT -P FORWARD DROP
	echo "done."
	;;
  reload-server)
	echo -n "Reloading $DESC INPUT Subchains configuration..."

        setup_inputchains

	echo "done."
  ;;
  reload-forward)
	echo -n "Reloading $DESC FORWARD Subchains configuration..."

        setup_forwardchains

	echo "done."
  ;;
  restart|force-reload)
        $0 stop && $0 start
	;;
  dump)
        echo -n "Writing Firewall Dumpfile: "
        $IPT -L -nvx > /var/log/firewall-dump-`date+%d.%m.%Y"-"%H:%M:%S`.log
        $IPT -Z
        echo -e "done."
        ;;
  *)
	N=/etc/init.d/$NAME
	# echo "Usage: $N {start|stop|reload-server|reload-forward|restart|force-reload}" >&2
	echo "Usage: $N {start|stop|reload-server|reload-forward|restart|force-reload}" >&2
	exit 1
	;;
esac

exit 0


syntax highlighted by Code2HTML, v. 0.9.1