#!/bin/bash

IPTABLES=/sbin/iptables

# Setup IFB
modprobe nf_conntrack_ftp

# Enable Internet connection sharing
echo "1" > /proc/sys/net/ipv4/ip_forward
echo "1" > /proc/sys/net/ipv4/ip_dynaddr

# clear out existing setting
$IPTABLES -P INPUT ACCEPT
$IPTABLES -F INPUT 
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -F OUTPUT 
$IPTABLES -P FORWARD DROP
$IPTABLES -F FORWARD 
$IPTABLES -t nat -F
$IPTABLES -t mangle -F
$IPTABLES -t filter -F


# Create and flush internet chain
# This is used to authenitcate users who have already signed up
$IPTABLES -N internet -t nat 2>/dev/null
$IPTABLES -F internet -t nat

# Create ipset for storing ip addresses of p2p users
# Set timeout to 60 seconds meaning their address will
# be cleared after 60 seconds of inactivity of p2p
#
# The current IP addresses in the IP Set can be monitored
# with the 'ipset -L' comand from the bash prompt
#
ipset -X p2p
ipset -N p2p iptree --timeout 60

# Accept all local traffic
iptables -t nat -A PREROUTING -i eth0 --destination 10.0.0.0/16 -j ACCEPT

# Send all traffic via internet chain
# At the prerouting NAT stage this will DNAT them to the local
# webserver for them to signup if they aren't authorised
# Packets for unauthorised users are marked for dropping later
iptables -t nat -A PREROUTING -j internet

# Drop invalid packets
iptables -t mangle -A PREROUTING -p tcp -i eth0 -m conntrack --ctstate INVALID -j DROP  # drop invalid connections

# Accept ping and ssh incoming FROM Internet networks
iptables -t filter -A INPUT -p icmp -i ppp0 --icmp-type 8 -j ACCEPT
iptables -t filter -A INPUT -p ICMP -i ppp0 --icmp-type 11 -j ACCEPT
iptables -t filter -A INPUT -i ppp0 -p tcp --dport 22 -j ACCEPT
iptables -t filter -A INPUT -i ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t filter -A INPUT -i ppp0 -j DROP

# accept NTP time requess
# we allow these for any PC regardless of whether they are logged
# on to the network because the Internet Suite PCs use NTP to set
# their clocks BEFORE they are authorised to use the Internet
iptables -t filter -A FORWARD -p UDP --dport 123 -j ACCEPT

# Stop DoS attacks on DNS-BL
iptables -t filter -A FORWARD -i eth0 --destination 216.168.28.50 -j DROP

# Do not allow outgoing internet SMTP connections
# This is essential to stop the many viruses that sit on
# people's computers and attempt to send spam (using bandwidth up)
# This can be changed on a per user basis if required as per the example
iptables -t filter -A FORWARD -p tcp -i eth0 --dport 25 -m mac --mac-source 00:19:D1:02:1B:02 -j ACCEPT
iptables -t filter -A FORWARD -p tcp -i eth0 --dport 25 -j DROP


# Mark traffic for shaping later
# The lower the MARK the higher the priority
# Default mark is marked at prerouting to catch both
# internal and forwarded traffic destined for other machines
iptables -t mangle -A PREROUTING -i ppp0 -j MARK --set-mark 40
# Accept any packets marked 99 here; they will be dropped later
# If they are re-marked then they will be allowed through
iptables -t mangle -A FORWARD -m mark --mark 99 -j ACCEPT
# http / https
iptables -t mangle -A FORWARD -p tcp --sport 80 -i ppp0 -j MARK --set-mark 30
iptables -t mangle -A FORWARD -p tcp --dport 80 -o ppp0 -j MARK --set-mark 30
iptables -t mangle -A FORWARD -p tcp --sport 443 -i ppp0 -j MARK --set-mark 30
iptables -t mangle -A FORWARD -p tcp --dport 443 -i eth0 -j MARK --set-mark 30
# SSH
iptables -t mangle -A FORWARD -p tcp --sport 22 -i ppp0 -j MARK --set-mark 10
iptables -t mangle -A FORWARD -p tcp --dport 22 -o ppp0 -j MARK --set-mark 10
# local traffic
iptables -t mangle -A POSTROUTING --source 10.0.0.1 -j MARK --set-mark 1
iptables -t mangle -A POSTROUTING --destination 10.0.0.1 -j MARK --set-mark 1
# http via squid
iptables -t mangle -A POSTROUTING -p tcp --sport 3128 --source 10.0.0.1 -j MARK --set-mark 30
# DNS requests
iptables -t mangle -A OUTPUT -m udp -p udp --dport 53 -j MARK --set-mark 10
iptables -t mangle -A OUTPUT -m tcp -p tcp --dport 53 -j MARK --set-mark 10
iptables -t mangle -A INPUT -m udp -p udp --sport 53 -j MARK --set-mark 10
iptables -t mangle -A INPUT -m tcp -p tcp --sport 53 -j MARK --set-mark 10
# mark large downloads from squid
iptables -t mangle -A POSTROUTING -p tcp --sport 3128 --source 10.0.0.1 -m connbytes --connbytes 504857: --connbytes-dir both --connbytes-mode bytes -j MARK --set-mark 40
# IMAP
iptables -t mangle -A FORWARD -p tcp --sport 993 -i ppp0 -j MARK --set-mark 30  # imap
iptables -t mangle -A FORWARD -p tcp --dport 993 -o ppp0 -j MARK --set-mark 30  # imap
# Mark large downloads (> 500kb)
iptables -t mangle -A FORWARD -m connbytes --connbytes 504857: --connbytes-dir both --connbytes-mode bytes -j MARK --set-mark 40
# To speed up downloads while an upload is going on, put short ACK
# packets in the interactive class:
iptables -t mangle -A FORWARD -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK ACK -m length --length :64 -j MARK --set-mark 10

# The next few lines pick out P2P packets
# These are characterised by lots of connections to high port numbers
# First look for the packets and log to IPSET p2p
# Detects traffic from users using >8 ports above 1024
# and adds the source address to the P2P list.
iptables -t mangle -A FORWARD -o ppp0 -p tcp --dport 1024: \
	-m connlimit --connlimit-above 8 -j SET --add-set p2p src 
# Detects traffic from users using >4 UDP ports above 1024
# and adds the source address to the P2P list.
iptables -t mangle -A FORWARD -o ppp0 -p udp --dport 1024: \
	-m connlimit --connlimit-above 4 -j SET --add-set p2p src 
# Detects traffic to users using >8 ports above 1024
# and adds the dst address (ie the user) to the P2P list.
iptables -t mangle -A FORWARD -i ppp0 -p tcp --sport 1024: \
	-m connlimit --connlimit-above 8 -j SET --add-set p2p dst
# Detects traffic to users using >4 UDP ports above 1024
# and adds the dst address (ie the user) to the P2P list.
iptables -t mangle -A FORWARD -i ppp0 -p udp --sport 1024: \
	-m connlimit --connlimit-above 4 -j SET --add-set p2p dst
# Once a user is in the p2p IPSET, these rules mark their packets
# Any packets above 1024 are marked as the lowest priority
iptables -t mangle -A FORWARD -o ppp0 \
	-m set --set p2p src -j MARK --set-mark 60
iptables -t mangle -A FORWARD -i ppp0 \
	-m set --set p2p dst -j MARK --set-mark 60
iptables -t mangle -A POSTROUTING -o eth0 \
	-m set --set p2p dst -j MARK --set-mark 60
iptables -t mangle -A POSTROUTING -o ppp0 \
	-m set --set p2p src -j MARK --set-mark 60

# Now that we've got to the forward filter, drop all packets
# marked 99 - these are unknown users. We can't drop them earlier
# as there's no filter table
iptables -t filter -A FORWARD -m mark --mark 99 -j DROP
# Do the same for the INPUT chain so that they also can't get to squid
# but allow them to the webserver to signup
iptables -t filter -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -t filter -A INPUT -m mark --mark 99 -j DROP

###### INTERNET CHAIN ##########
# Allow authorised hosts in, redirect all others to login webserver
# Add known users to the NAT table to stop their dest being rewritten
# Ignore MAC address with a * - these users are blocked
awk 'BEGIN { FS="\t"; } { if ($5 !~ /\*/) { system("iptables -t nat -A internet -m mac --mac-source "$5" -j RETURN"); } }' /var/lib/users
# MAC address not found. Mark the packet 99
iptables -t nat -A internet -j MARK --set-mark 99
# Redirects web requests from Unauthorised users to logon Web Page
iptables -t nat -A internet -m mark --mark 99 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.1
################################

# Force all traffic via web proxy to speed up some traffic
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128

# Bocks outgoing traffic from local host on unused ports.
# Allow known ports out
iptables -t mangle -A OUTPUT -p tcp --dport 80 -o ppp0 -j ACCEPT  # Accept web proxy traffic
iptables -t mangle -A OUTPUT -p tcp --dport 25 -o ppp0 -j ACCEPT # Accept outgoing mail 
iptables -t mangle -A OUTPUT -p tcp --dport 21 -o ppp0 -j ACCEPT # Accept outgoing ftp
iptables -t mangle -A OUTPUT -p tcp --dport 22 -o ppp0 -j ACCEPT # Accept outgoing ssh
iptables -t mangle -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t mangle -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t mangle -A OUTPUT -p icmp -o ppp0 --icmp-type 8 -j ACCEPT #Accept ping commamnds
iptables -t mangle -A OUTPUT -p ICMP -o ppp0 --icmp-type 11 -j ACCEPT #Accept ping commands
iptables -t mangle -A OUTPUT -m udp -p udp --dport 53 -j ACCEPT   # DNS
iptables -t mangle -A OUTPUT -o ppp0 -j DROP # Drops all other outputs from the local machine


# Enable Internet connection sharing
$IPTABLES -A FORWARD -i ppp0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A FORWARD -i eth0 -o ppp0 -j ACCEPT
$IPTABLES -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

##############################################################################
# Now set up traffic shaping based on the marks given to each packet

# Delete all old stuff first
tc qdisc del dev ppp0 root    2> /dev/null > /dev/null
tc qdisc del dev ifb0 root   2> /dev/null > /dev/null
tc qdisc del dev ifb0 ingress   2> /dev/null > /dev/null
tc qdisc del dev ppp0 root 2> /dev/null > /dev/null
tc qdisc del dev ifb0 root 2> /dev/null > /dev/null
tc qdisc del dev ppp0 ingress 2> /dev/null > /dev/null
tc qdisc del dev eth0 root 2> /dev/null > /dev/null
tc qdisc del dev eth0 ingress 2> /dev/null > /dev/null

# Set variables
# The downlink should be slightly less than the ADSL line
# All the classes below should add up to this
DOWNLINK=2200
# Same for the uplink
UPLINK=330

##############################################################################
## downlink via eth0 ##

# A qdisc is a whole set of shaping rules that we apply
# Here we add a HTB qdisc to the interface eth0
# This is known as the root for the interface
# We don't set a default class to stop us shaping local eth0 traffic
# We have to shape at eth0 and not ppp0 as we can only do egress shaping
tc qdisc add dev eth0 root handle 1: htb

# Then we add to the root some overall rate limits
tc class add dev eth0 parent 1: classid 1:1 htb rate ${DOWNLINK}kbit

# Then we go through and add a number of classes to the
# root qdisc. With some qdiscs the classes are automatically
# created. With HTB they are not so we add 4 in total
# with different rate limits each

# [[[ example to divide between $[8*$DOWNLINK/10]kbit ]]]

# interactive traffic
tc class add dev eth0 parent 1:1  classid 1:10 htb \
	rate 100kbit ceil 100kbit prio 0

# web browsing
tc class add dev eth0 parent 1:1  classid 1:30 htb \
	rate 1000kbit ceil 1000kbit prio 1

# default traffic
tc class add dev eth0 parent 1:1  classid 1:40 htb \
	rate 1000kbit ceil 1000kbit prio 2

# bad boys
tc class add dev eth0 parent 1:1  classid 1:60 htb \
	rate 100kbit ceil 100kbit prio 3

# Next we add some more qdiscs. These are different priority
# qdiscs but they each sit on top of the classes already created.
# So the root qdisc dumps traffic in each class, and the qdisc
# here prioritises within that class
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10 #flow hash keys dst divisor 1024 #hash ctorigsrc
tc qdisc add dev eth0 parent 1:40 handle 40: sfq perturb 10 #hash ctorigsrc
tc qdisc add dev eth0 parent 1:60 handle 60: sfq perturb 10 #hash ctorigsrc

# Finally we attach some filters to each class
# A filter is what sends a particular packet to a particular class
# This filter uses the iptables marks to allocate them
tc filter add dev eth0 parent 1:0 protocol ip handle 10 fw flowid 1:10
tc filter add dev eth0 parent 1:0 protocol ip handle 30 fw flowid 1:30
tc filter add dev eth0 parent 1:0 protocol ip handle 40 fw flowid 1:40
tc filter add dev eth0 parent 1:0 protocol ip handle 60 fw flowid 1:60

# experimental hash filters - couldn't get to work!
tc filter add dev eth0 parent 10: protocol ip handle 10 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 30: protocol ip handle 30 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 40: protocol ip handle 40 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 60: protocol ip handle 60 flow hash keys nfct-dst divisor 1024

########################################## End of downlink configuration ##########################################



###################################################################################################################
## uplink via ppp0 ##

# A qdisc is a whole set of shaping rules that we apply
# Here we add a HTB qdisc to the interface ppp0
# This is known as the root for the interface
# Default class is 40
tc qdisc add dev ppp0 root handle 1: htb default 40

# Then we add to the root some overall rate limits
tc class add dev ppp0 parent 1: classid 1:1 htb rate ${UPLINK}kbit

# Then we go through and add a number of classes to the
# root qdisc. With some qdiscs the classes are automatically
# created. With HTB they are not so we add 4 in total
# with different rate limits each


# [[[ example to divide between $[8*$DOWNLINK/10]kbit ]]]

# interactive traffic
tc class add dev ppp0 parent 1:1  classid 1:10 htb \
	rate 50kbit ceil 50kbit prio 0

# web browsing
tc class add dev ppp0 parent 1:1  classid 1:30 htb \
	rate 120kbit ceil 200kbit prio 1

# default traffic
tc class add dev ppp0 parent 1:1  classid 1:40 htb \
	rate 120kbit ceil 200kbit prio 2

# bad boys
tc class add dev ppp0 parent 1:1  classid 1:60 htb \
	rate 40kbit ceil 40kbit prio 3

# Next we add some more qdiscs. These are different priority
# qdiscs but they each sit on top of the classes already created.
# So the root qdisc dumps traffic in each class, and the qdisc
# here prioritises within that class
tc qdisc add dev ppp0 parent 1:10 handle 10: pfifo
tc qdisc add dev ppp0 parent 1:30 handle 30: pfifo #sfq perturb 10 hash ctorigsrc
tc qdisc add dev ppp0 parent 1:40 handle 40: pfifo #sfq perturb 10 hash ctorigsrc
tc qdisc add dev ppp0 parent 1:60 handle 60: pfifo #sfq perturb 10 hash ctorigsrc

# Finally we attach some filters to each class
# A filter is what sends a particular packet to a particular class
# This filter uses the iptables marks to allocate them
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 30 fw flowid 1:30
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 40 fw flowid 1:40
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 60 fw flowid 1:60

################################# End of uplink configuration #####################################################


