netfilter networking iptables tc qos
The script below is used on production systems to enable Firewalling with Netfilter/Iptables and QOS with Traffic Control. More detailled information about Netfilter and TC can be found in other articles on this wiki.
#! /bin/bash
#
### BEGIN INIT INFO
# Provides: netfilter_qos.sh
# Required-Start: $syslog
# Required-Stop: $syslog
# Should-Start: $local_fs
# Should-Stop: $local_fs
# Default-Start: 2
# Default-Stop: 0 1 6
# Short-Description: starts/stops netfilter_qos.sh
# Description: starts and stops netfilter and qos rules
### END INIT INFO
NETCARD=eth0 # network card to apply the QoS to
IP=1.2.3.4 # local ip address
LAN=1.2.3.0/24 # lan address
UPLINK=1024 # upload in kbits/s
#within http class, list hosts and allow them [ 1/(total nb of host) ] bandwidth
HTTPPRIORITIES="www.example.net website.example.com static.myexample.eu"
LISTENTCP="ssh http https imap"
LISTENUDP="domain"
TC=/sbin/tc
IPT=/sbin/iptables
case "$1" in
start)
echo "~~~~ LOADING $NETCARD NETFILTER/QOS RULES FOR `uname -n` ~~~~"
echo
echo "#-cleanup"
$TC qdisc del dev $NETCARD root
$IPT -t mangle -F
echo
echo "##################### FIREWALL ###############################"
echo
echo "create LOGACCEPT: LOG to syslog and ACCEPT packet"
$IPT -N LOGACCEPT
$IPT -t filter -A LOGACCEPT -j LOG --log-prefix "NETFILTER ACCEPT => " --log-level debug
$IPT -t filter -A LOGACCEPT -j ACCEPT
echo "ACCEPT localhost packets"
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
echo "accept packets from ESTABLISHED connections without LOGGING"
$IPT -A INPUT -i $NETCARD -p tcp -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o $NETCARD -p tcp -m state --state ESTABLISHED -j ACCEPT
$IPT -A INPUT -i $NETCARD -p udp -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -o $NETCARD -p udp -m state --state ESTABLISHED -j ACCEPT
for service in $LISTENTCP
do
echo "LOGACCEPT incoming TCP/$service"
$IPT -A INPUT -t filter -i $NETCARD -p tcp --dport $service -m state --state NEW -j LOGACCEPT
done
for service in $LISTENUDP
do
echo "LOGACCEPT incoming UDP/$service"
$IPT -A INPUT -t filter -i $NETCARD -p udp --dport $service -m state --state NEW -j LOGACCEPT
done
echo "LOGACCEPT incoming TCP/10035 (dspam)"
$IPT -A INPUT -t filter -i $NETCARD -p tcp --dport 10035 -s dspam.example.net -m state --state NEW -j LOGACCEPT
$IPT -A OUTPUT -t filter -o $NETCARD -p tcp --dport 10034 -d dspam.example.net -m state --state NEW -j LOGACCEPT
echo "LOGACCEPT incoming TCP/LDAPS (OpenLDAP sync)"
$IPT -A INPUT -t filter -i $NETCARD -p tcp --dport ldaps -s ldapmaster.example.net -m state --state NEW -j LOGACCEPT
echo "LOGACCEPT incoming TCP/LDAPS from nagios"
$IPT -A INPUT -t filter -i $NETCARD -p tcp --dport ldaps -s nagios.example.net -m state --state NEW -j LOGACCEPT
echo "LOGACCEPT incoming ping from iruel (nagios check)"
$IPT -A INPUT -t filter -i $NETCARD -p icmp --icmp-type 8 -s nagios.example.net -j LOGACCEPT
$IPT -A OUTPUT -t filter -o $NETCARD -p icmp --icmp-type 0 -d nagios.example.net -j LOGACCEPT
echo "LOGACCEPT outgoing DNS requests"
$IPT -A OUTPUT -t filter -o $NETCARD -p udp --dport domain -j LOGACCEPT
$IPT -A OUTPUT -t filter -o $NETCARD -p tcp --dport domain -m state --state NEW -j LOGACCEPT
$IPT -A INPUT -t filter -i $NETCARD -p udp --sport domain -m state --state ESTABLISHED -j LOGACCEPT
echo "LOGACCEPT outgoing NTP requests"
$IPT -A OUTPUT -t filter -o $NETCARD -p udp --dport ntp -m state --state NEW -j LOGACCEPT
$IPT -A INPUT -t filter -i $NETCARD -p udp --sport ntp -m state --state ESTABLISHED -j LOGACCEPT
echo "LOGACCEPT outgoing SMTP requests"
$IPT -A OUTPUT -t filter -o $NETCARD -p tcp --dport smtp -m state --state NEW -j LOGACCEPT
echo "LOGACCEPT root outgoing connexions"
$IPT -A OUTPUT -t filter -o $NETCARD -m owner --uid-owner 0 -j LOGACCEPT
echo "LOGACCEPT user=julien outgoing connexions"
$IPT -A OUTPUT -t filter -o $NETCARD -m owner --uid-owner 1000 -j LOGACCEPT
echo
echo "##################### QOS ####################################"
echo
echo "#-root"
$TC qdisc add dev $NETCARD root handle 1: htb default 999 r2q 5000
echo "#--uplink - rate $UPLINK kbit ceil $UPLINK kbit"
$TC class add dev $NETCARD parent 1:0 classid 1:1 htb rate $(($UPLINK))kbit ceil $(($UPLINK))kbit
echo "#---interactive - id 100 -rate $(( $UPLINK / 48 )) kbit ceil $(( $UPLINK / 3 )) kbit"
$TC class add dev $NETCARD parent 1:1 classid 1:100 htb rate $(( $UPLINK / 48 ))kbit ceil $(( $UPLINK / 3 ))kbit burst 5k prio 1 linklayer atm
echo "#--- ~ sub interactive: pfifo"
$TC qdisc add dev $NETCARD parent 1:100 handle 1100: pfifo limit 10000
echo "#--- ~ interactive filter"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 1 handle 100 fw flowid 1:100
echo "#--- ~ netfilter rule - DNS, NTP, SNMP at 100"
$IPT -t mangle -A OUTPUT -o $NETCARD -p udp -m multiport --sports 53,123,161:162 -j CONNMARK --set-mark 100
$IPT -t mangle -A OUTPUT -o $NETCARD -p udp --dport 53 -j CONNMARK --set-mark 100
echo "#---tcp acks - id 200 - rate $(( $UPLINK / 12 )) kbit ceil $(( $UPLINK / 8 )) kbit"
$TC class add dev $NETCARD parent 1:1 classid 1:200 htb rate $(( $UPLINK / 12 ))kbit ceil $(( $UPLINK / 8 ))kbit burst 8k prio 2
echo "#--- ~ sub tcp acks: pfifo"
$TC qdisc add dev $NETCARD parent 1:200 handle 1200: pfifo limit 10000
echo "#--- ~ filtre tcp acks"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 2 handle 200 fw flowid 1:200
echo "#--- ~ netfilter rule will be loaded at the end"
echo "#---ssh - id 300 - rate $(( $UPLINK / 100 )) kbit ceil $(( $UPLINK / 8 )) kbit"
$TC class add dev $NETCARD parent 1:1 classid 1:300 htb rate $(( $UPLINK / 100 ))kbit ceil $(( $UPLINK / 8 ))kbit burst 8k prio 3
echo "#--- ~ sub ssh: sfq"
$TC qdisc add dev $NETCARD parent 1:300 handle 1300: sfq perturb 10
echo "#--- ~ ssh filter"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 3 handle 300 fw flowid 1:300
echo "#--- ~ netfilter rule - SSH at 300"
$IPT -t mangle -A OUTPUT -o $NETCARD -p tcp --tcp-flags SYN,ACK SYN,ACK --sport 22 -j CONNMARK --set-mark 300
echo "#---http branch - id 400 - rate $(( $UPLINK / 3 )) kbit ceil $UPLINK kbit"
$TC class add dev $NETCARD parent 1:1 classid 1:400 htb rate $(( $UPLINK / 3 ))kbit ceil $(( $UPLINK ))kbit burst 20k prio 4
echo "#--- ~ sub http branch: sfq"
$TC qdisc add dev $NETCARD parent 1:400 handle 1400: sfq perturb 10
echo "#--- ~ http branch filter"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 4 handle 400 fw flowid 1:400
# first count the number of website
webcount=1 #start at 1 to include the default fallback
for i in $HTTPPRIORITIES
do
webcount=$(( webcount + 1 ))
done
# then create the rules
counter=0
for i in $HTTPPRIORITIES
do
counter=$(( counter + 1 ))
echo "#---http leaf $i - id 40$counter - rate $(( $UPLINK / 3 / $webcount )) kbit ceil $UPLINK kbit"
$TC class add dev $NETCARD parent 1:400 classid 1:40$counter htb rate $(( $UPLINK / 3 / $webcount ))kbit ceil $(( $UPLINK ))kbit burst 20k prio 4
echo "#--- ~ sub http $i: sfq"
$TC qdisc add dev $NETCARD parent 1:40$counter handle 140$counter: sfq perturb 10
echo "#--- ~ http filter"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 4 handle 40$counter fw flowid 1:40$counter
echo "#--- ~ netfilter rule - $i"
$IPT -t mangle -A INPUT -i $NETCARD -p tcp --dport 80 -m string --string "Host: $i" --algo bm -j CONNMARK --set-mark 40$counter
done
# finally, create the default HTTP class for non classified traffic
echo "#---http default leaf - id 499 - rate $(( $UPLINK / 3 / $webcount )) kbit ceil $UPLINK kbit"
$TC class add dev $NETCARD parent 1:400 classid 1:499 htb rate $(( $UPLINK / 3 / $webcount ))kbit ceil $(( $UPLINK ))kbit burst 20k prio 4
echo "#--- ~ sub http default leaf: sfq"
$TC qdisc add dev $NETCARD parent 1:499 handle 1499: sfq perturb 10
echo "#--- ~ http filter"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 4 handle 499 fw flowid 1:499
echo "#--- ~ netfilter rule - http default leaf"
$IPT -t mangle -A OUTPUT -o $NETCARD -p tcp --tcp-flags SYN,ACK ACK --sport 80 -m connmark --mark 0 -j CONNMARK --set-mark 499
$IPT -t mangle -A OUTPUT -o $NETCARD -p tcp --tcp-flags SYN,ACK ACK --sport 443 -m connmark --mark 0 -j CONNMARK --set-mark 499
echo "#---files xfer - id 500 - rate $(( $UPLINK / 3 )) kbit ceil $UPLINK kbit"
$TC class add dev $NETCARD parent 1:1 classid 1:500 htb rate $(( $UPLINK / 3 ))kbit ceil $(( $UPLINK ))kbit burst 2k prio 5 linklayer atm
echo "#--- ~ sub files xfer: sfq"
$TC qdisc add dev $NETCARD parent 1:500 handle 1500: sfq perturb 10
echo "#--- ~ files xfer filter"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 7 handle 500 fw flowid 1:500
echo "#--- ~ netfilter rule - FTP and everything bigger than 10MB"
$IPT -t mangle -A INPUT -i $NETCARD -p tcp --dport 20:21 -j CONNMARK --set-mark 500
$IPT -t mangle -A OUTPUT -o $NETCARD -p tcp -m connbytes --connbytes 10000000: --connbytes-mode bytes --connbytes-dir both -j CONNMARK --set-mark 500
echo "#---default - id 999 - rate $(( $UPLINK / 5 ))kbit ceil $(( $UPLINK ))kbit"
$TC class add dev $NETCARD parent 1:1 classid 1:999 htb rate $(( $UPLINK / 5 ))kbit ceil $(( $UPLINK ))kbit burst 2k prio 9 linklayer atm
echo "#--- ~ sub default: sfq"
$TC qdisc add dev $NETCARD parent 1:999 handle 1999: sfq perturb 10
echo "#--- ~ filtre default"
$TC filter add dev $NETCARD parent 1:0 protocol ip prio 99 handle 999 fw flowid 1:999
echo "#--- ~ propagating marks on connections"
$IPT -t mangle -A POSTROUTING -j CONNMARK --restore-mark
echo "#--- ~ TCP ACKS at 200"
$IPT -t mangle -A POSTROUTING -p tcp --tcp-flags URG,ACK,PSH,RST,SYN,FIN ACK -m length --length 40:64 -j MARK --set-mark 200
echo "Default policy: DROP EVERYTHING ELSE"
$IPT -N LOGDROP
$IPT -A LOGDROP -j LOG --log-prefix "NETFILTER DROP => " --log-level debug
$IPT -A LOGDROP -j DROP
$IPT -A INPUT -i $NETCARD -j LOGDROP
$IPT -A FORWARD -i $NETCARD -j LOGDROP
$IPT -A OUTPUT -o $NETCARD -j LOGDROP
echo
echo "Firewall is up and running"
echo
;;
stop)
$IPT -t nat -F
$IPT -t nat -X
$IPT -t filter -F
$IPT -t filter -X
$IPT -t mangle -F
$IPT -t mangle -X
$TC qdisc del dev $NETCARD root handle 1
exit 0
;;
restart)
$0 stop
$0 start
exit 0
;;
*)
echo "usage:$0 {start|stop|restart}"
echo "julien vehent - 2011 - julien@linuxwall.info"
;;
esac
~~DISCUSSION~~