Netfilter/Iptables script, with traffic control (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~~

en/ressources/articles/netfilter_advance.txt · Last modified: 2011/03/16 01:30 (external edit)
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0