#!/bin/bash # chkconfig: - 16 84 # description: Automates a packet filtering firewall with iptables. # File: /etc/init.d/firewall . /etc/init.d/functions . /etc/sysconfig/firewall.conf MASQCONF="/etc/sysconfig/firewall-masquerade.conf" FWDCONF="/etc/sysconfig/firewall-forward.conf" QOSCONF="/etc/sysconfig/firewall-qos.conf" # erlaubt immer SSH zugriff aus internen netzen DEBUG="no" modprobe=`which modprobe` ipt=`which iptables` tc=`which tc` # ulog target ULOG="ULOG --ulog-cprange 128 --ulog-prefix" case "$1" in start) echo "Setting up firewall" touch /var/lock/subsys/firewall # Flush all tables and delete user chains $ipt -F -t filter $ipt -F -t nat $ipt -F -t mangle $ipt -X -t filter $ipt -X -t nat $ipt -X -t mangle # user chains $ipt -N ext-in $ipt -N fwd-out $ipt -N ext-out $ipt -t nat -N ext-in $ipt -t mangle -N ext-in $ipt -t mangle -N ext-out # USER-CHAIN: drop/reject unwanted packets from inet $ipt -N droprej $ipt -A droprej -p tcp -j REJECT --reject-with tcp-reset $ipt -A droprej -p udp -j REJECT $ipt -A droprej -j DROP # USER-CHAIN: log & drop private IPs from/to inet $ipt -t mangle -N logdrop $ipt -t mangle -A logdrop -j $ULOG ext-drop $ipt -t mangle -A logdrop -j DROP # Allow loopback $ipt -A INPUT -i lo -j ACCEPT $ipt -A OUTPUT -o lo -j ACCEPT # debugging if [ "$DEBUG" == "yes" ]; then $ipt -A INPUT -p tcp --dport 22 -j ACCEPT $ipt -A OUTPUT -p tcp --sport 22 -j ACCEPT fi # already accepted traffic $ipt -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT # internal nets for i in $INT_NUMS; do eval dev=\${INT_DEV_${i}} eval nets=\${INT_NET_${i}} eval opts=\${INT_OPT_${i}} realdev=`echo $dev | cut -d":" -f1` # options parsing for opt in $opts; do case "$opt" in # Allow bridging BRIDGE) $ipt -A FORWARD -i $dev -o $dev -j ACCEPT ;; # allow traffic on internal net INTERNAL) for net in $nets; do $ipt -A INPUT -i $realdev -s $net -j ACCEPT $ipt -A OUTPUT -o $realdev -d $net -j ACCEPT done ;; # Allow traffic to external net EXTERNAL) for net in $nets; do $ipt -A FORWARD -i $dev -s $net -j fwd-out done ;; # Allow Routing to other internal nets ROUTE) for i2 in $INT_NUMS; do eval dev2=\${INT_DEV_${i2}} eval nets2=\${INT_NET_${i2}} realdev2=`echo $dev2 | cut -d":" -f1` for net in $nets; do for net2 in $nets2; do if [ "$net" != "$net2" ] || [ "$realdev" != "$realdev2" ]; then $ipt -A FORWARD -i $realdev -o $realdev2 -s $net -d $net2 -j ACCEPT fi done done done ;; # Masquerade all connections through this interface and allow external portforwardings MASQ) for net in $nets; do $ipt -t nat -A PREROUTING -i $dev -j ext-in $ipt -A INPUT -i $dev -s $net -j ext-in $ipt -A OUTPUT -o $dev -d $net -j ext-out $ipt -A FORWARD -i $dev -s $net -m conntrack --ctstate SNAT -j ACCEPT $ipt -t nat -A POSTROUTING -o $dev -j MASQUERADE done ;; # redirect web traffic to squid TSQUID) if [ -z "$squid_table" ]; then squid_table=ok # squid table $ipt -t nat -N squid fi $ipt -t nat -A PREROUTING -i $dev -p tcp --dport 80 -j squid # no squid between nets on this interface for neta in $nets; do for netb in $nets; do $ipt -t nat -A squid -i $dev -s $neta -d $netb -j ACCEPT done done $ipt -t nat -A squid -i $dev -p tcp -j REDIRECT --to-ports 3128 ;; # Allow dhcpd traffic DHCP) $ipt -A INPUT -i $dev -p udp --sport 67:68 --dport 67:68 -j ACCEPT $ipt -A OUTPUT -o $dev -p udp --sport 67:68 --dport 67:68 -j ACCEPT ;; # honeypot target/net HONEYPOT) if [ -z "$hpot_table" ]; then hpot_table=ok # Allow nothing $ipt -N hpot-in $ipt -A hpot-in -j droprej # Allow ftp and dns to external net $ipt -N hpot-fwd $ipt -A hpot-fwd -p udp --dport 53 -j ACCEPT $ipt -A hpot-fwd -p tcp --dport 21 -j ACCEPT $ipt -A hpot-fwd -j droprej # Allow icmp, tcp-rst from localhost (answer to drop-rej in hpot-fwd) $ipt -N hpot-out $ipt -A hpot-out -p tcp --tcp-flags RST RST -j ACCEPT $ipt -A hpot-out -p icmp -j ACCEPT $ipt -A hpot-out -j DROP # ratelimit everything $ipt -t mangle -N hpot-in $ipt -t mangle -A hpot-in -m limit --limit $HONEYPOT_RATE_TO -j ACCEPT $ipt -t mangle -A hpot-in -j DROP $ipt -t mangle -N hpot-out $ipt -t mangle -A hpot-out -m limit --limit $HONEYPOT_RATE_FROM -j ACCEPT $ipt -t mangle -A hpot-out -j DROP fi for net in $nets; do $ipt -t mangle -A PREROUTING -i $dev -s $net -j hpot-in $ipt -A INPUT -i $dev -s $net -j hpot-in $ipt -A FORWARD -i $dev -s $net -j hpot-fwd $ipt -A OUTPUT -o $dev -d $net -j hpot-out $ipt -t mangle -A POSTROUTING -o $dev -d $net -j hpot-out done ;; esac done done # external nets for dev in $EXT_DEVS; do $ipt -A INPUT -i $dev -j ext-in $ipt -A FORWARD -i $dev -m conntrack --ctstate DNAT -j ACCEPT $ipt -A OUTPUT -o $dev -j ext-out # external in/out (dropping internal nets) $ipt -t mangle -A PREROUTING -i $dev -j ext-in $ipt -t mangle -A POSTROUTING -o $dev -j ext-out # external in/out (portforwarding) $ipt -t nat -A PREROUTING -i $dev -j ext-in # used to overcome criminally brain-dead ISPs or servers which block ICMP Fragmentation Needed packets $ipt -t mangle -A FORWARD -o $dev -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu # masquerade everything passing ext device $ipt -t nat -A POSTROUTING -o $dev -j MASQUERADE done # reject the rest $ipt -A INPUT -j $ULOG input $ipt -A INPUT -j droprej $ipt -A FORWARD -j $ULOG forward $ipt -A FORWARD -j droprej $ipt -A OUTPUT -j $ULOG output $ipt -A OUTPUT -j droprej # drop restriced nets for net in $EXT_DENIED; do $ipt -t mangle -A ext-in -s $net -j logdrop $ipt -t mangle -A ext-out -d $net -j logdrop done # allow own traffic $ipt -A ext-in -m state --state ESTABLISHED,RELATED -j ACCEPT # block windows traffic if [ "$EXT_BLOCK_WINDOWS" == "yes" ]; then for chain in ext-in fwd-out ext-out; do $ipt -A $chain -p tcp --dport 135:139 -j droprej $ipt -A $chain -p udp --dport 135:139 -j droprej $ipt -A $chain -p tcp --dport 445 -j droprej done fi # masqerading list (masquerade.conf) grep '^[^#]' $MASQCONF | while read ip proto port; do if [ "$proto" == "all" ]; then $ipt -A fwd-out -s $ip -j ACCEPT elif [ "$proto" == "tcp" -o "$proto" == "udp" ]; then $ipt -A fwd-out -s $ip -p $proto --dport $port -j ACCEPT else $ipt -A fwd-out -s $ip -p $proto -j ACCEPT fi done # log & drop/reject unwanted packets from internal to inet $ipt -A fwd-out -j $ULOG fwd-out $ipt -A fwd-out -j droprej # allow ipv6 proto (tunnel) for ip in "$EXT_SIT_TUNNEL_IP"; do $ipt -A ext-in -p 41 -s $ip -j ACCEPT $ipt -A ext-out -p 41 -d $ip -j ACCEPT done # port-forwarding list (forward.conf) grep '^[^#]' $FWDCONF | while read ip proto port dport; do # if ip=127.0.0.1 then do not forwarding if [ "$ip" == "127.0.0.1" ]; then if [ -z "$dport" ]; then dport=$port else $ipt -t nat -A ext-in -p $proto --dport $port -j REDIRECT --to-ports $dport fi $ipt -A ext-in -p $proto --dport $dport -j ACCEPT else # if no dport is given, dport = port if [ -z "$dport" ]; then dport=`echo $port | tr ':' '-'` else dport=`echo $dport | tr ':' '-'` fi $ipt -t nat -A ext-in -p $proto --dport $port -j DNAT --to ${ip}:${dport} fi done # allow some icmp-echo-requests $ipt -A ext-in -p icmp --icmp-type echo-request -m limit --limit 5/s -m length --length 0:128 -j ACCEPT $ipt -A ext-in -p icmp --icmp-type echo-request -j DROP # log low ports and block the rest $ipt -A ext-in -p tcp --dport 1024:65535 -j droprej $ipt -A ext-in -p udp --dport 1024:65535 -j droprej $ipt -A ext-in -j $ULOG ext-in $ipt -A ext-in -j droprej # final catch ext-out $ipt -A ext-out -p tcp -j ACCEPT $ipt -A ext-out -p udp -j ACCEPT $ipt -A ext-out -p icmp -j ACCEPT $ipt -A ext-out -j $ULOG ext-out $ipt -A ext-out -j droprej # qos-stuff $ipt -t mangle -N qosmark $ipt -t mangle -A qosmark -j MARK --set-mark 22 # qos-regeln grep '^[^#]' $QOSCONF | while read mark proto sport dport; do if [ "$proto" == "tcp" -o "$proto" == "udp" ]; then if [ -z "$sport" -o "$sport" == "any" ]; then sport="0:65535" fi if [ -z "$dport" -o "$dport" == "any" ]; then dport="0:65535" fi $ipt -t mangle -A qosmark -p $proto --sport $sport --dport $dport -j MARK --set-mark $mark else $ipt -t mangle -A qosmark -p $proto -j MARK --set-mark $mark fi done # safe mark $ipt -t mangle -A qosmark -j CONNMARK --save-mark $ipt -t mangle -A qosmark -j RETURN # call qosmark from prerouting and postrouting for new connections only $ipt -t mangle -A ext-in -j CONNMARK --restore-mark $ipt -t mangle -A ext-in -m mark --mark 0 -j qosmark $ipt -t mangle -A ext-out -j CONNMARK --restore-mark $ipt -t mangle -A ext-out -m mark --mark 0 -j qosmark # small acks must be fast (per packet, not per flow) $ipt -t mangle -A ext-in -p tcp --tcp-flags ACK ACK -m length --length 0:65 -j MARK --set-mark 20 $ipt -t mangle -A ext-out -p tcp --tcp-flags ACK ACK -m length --length 0:65 -j MARK --set-mark 20 # kernel tweaks echo 1 > /proc/sys/net/ipv4/ip_forward echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_log_invalid > /dev/null 2>&1 # add. modules $modprobe ip_nat_ftp success "Setting up firewall" echo ;; stop) echo -n "Shutting down firewall" rm /var/lock/subsys/firewall # Flush all tables iptables -F -t filter iptables -F -t nat iptables -F -t mangle iptables -X -t filter iptables -X -t nat iptables -X -t mangle success "Shutting down firewall" echo ;; restart) $0 stop $0 start ;; status) { echo "===============================================" echo "FILTER:" $ipt -L -nv -t filter echo echo "===============================================" echo "NAT:" $ipt -L -nv -t nat echo echo "===============================================" echo "MANGLE:" $ipt -L -nv -t mangle echo } | less -S -#4 ;; start-qos) $0 stop-qos echo -n "Setting up QoS" $tc qdisc add dev $QOS_DEV root handle 1: htb default 22 $tc class add dev $QOS_DEV parent 1: classid 1:1 htb rate ${QOS_RATEUP}kbit $tc class add dev $QOS_DEV parent 1:1 classid 1:20 htb rate $[$QOS_RATEUP/10]kbit ceil $[$QOS_RATEUP/10*3]kbit prio 4 $tc class add dev $QOS_DEV parent 1:1 classid 1:21 htb rate $[$QOS_RATEUP/10]kbit ceil $[$QOS_RATEUP/10*5]kbit prio 2 $tc class add dev $QOS_DEV parent 1:1 classid 1:22 htb rate $[$QOS_RATEUP/10]kbit ceil $[$QOS_RATEUP/10*5]kbit prio 1 $tc class add dev $QOS_DEV parent 1:1 classid 1:23 htb rate $[$QOS_RATEUP/10]kbit ceil $[$QOS_RATEUP/10*8]kbit prio 0 $tc qdisc add dev $QOS_DEV parent 1:20 handle 20: sfq perturb 10 $tc qdisc add dev $QOS_DEV parent 1:21 handle 21: sfq perturb 10 $tc qdisc add dev $QOS_DEV parent 1:22 handle 22: sfq perturb 10 $tc qdisc add dev $QOS_DEV parent 1:23 handle 23: sfq perturb 10 $tc filter add dev $QOS_DEV parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20 $tc filter add dev $QOS_DEV parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21 $tc filter add dev $QOS_DEV parent 1:0 prio 0 protocol ip handle 22 fw flowid 1:22 $tc filter add dev $QOS_DEV parent 1:0 prio 0 protocol ip handle 23 fw flowid 1:23 success "Setting up QoS" echo ;; stop-qos) echo -n "Shutting down QoS" $tc qdisc del dev $QOS_DEV root 2> /dev/null success "Shutting down QoS" echo ;; status-qos) { echo "===============================================" echo "QDISC:" $tc -s -d qdisc show dev $QOS_DEV echo echo "===============================================" echo "CLASS:" $tc -s -d class show dev $QOS_DEV echo echo "===============================================" echo "FILTER:" $tc -s -d filter show dev $QOS_DEV echo } | less -S -#4 ;; *) echo "Usage: $0 {start|stop|restart|status|start-qos|stop-qos|status-qos}" exit 1 ;; esac