scripts/firewall.sh
2006-07-27 11:54:45 +02:00

451 lines
13 KiB
Bash

#!/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