#!/bin/bash #################################################################### ## Netfilters Init-Script for Linux SOHO-Routers #################################################################### ## by Sebastian "blackwing" Werner (xwing@gmx.net) #################################################################### ## Readme available at: ## http://blackwing.de/files/netfilters #################################################################### ## This script is released under the terms of the ## GNU General Public License IPT="/sbin/iptables" IP="/sbin/ip" TC="/sbin/tc" # internal netif int="eth0" # wlan if wlan="eth1" # external netif ext="ppp0" # dns updating dns_server="1.2.3.4" dns_ttl="1200" dns_keyfile="/etc/bind/Kblackdyn.+157+59214.key" dns_hostname="one" dns_domainname="host.name" # hosts traffic will be forwarded for (or set entire subnet!) allow_forward="10.10.0.1 10.10.0.2" # specific chains accounting_chains="in-ext in-int out-ext out-int forward-int forward-ext" chains="$accounting_chains finalize" proc_init() { infoline "Setting /proc values... " # Activate IP-Forwarding in kernel echo 1 > /proc/sys/net/ipv4/ip_forward # Activate Syncookie Support echo 1 > /proc/sys/net/ipv4/tcp_syncookies # DynIP Patch echo 1 > /proc/sys/net/ipv4/ip_dynaddr # Ignore Dead Error Messages echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses # Ignore all Broadcasts pings echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts # Enable route verification for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f done # Deny source routed packages echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route # Disable ICMP redirect acceptance echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects # Enable bad error message protection echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses # Don NOT Log impossible packets echo 0 >/proc/sys/net/ipv4/conf/all/log_martians # Set local port range echo "30000 60000" >/proc/sys/net/ipv4/ip_local_port_range # Decrease tcp timeouts to prevent DoS echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout echo 1800 > /proc/sys/net/ipv4/tcp_keepalive_time echo 1 > /proc/sys/net/ipv4/tcp_window_scaling echo 0 > /proc/sys/net/ipv4/tcp_sack infoline } infoline() { if [ "$debug" ] then if [ "$1" ] then case "$1" in f) echo "] done." ;; n) echo ;; *) echo -ne "$1 " esac else echo "done." fi fi } modules_load() { infoline "Loading modules... " modprobe ip_conntrack_ftp ports=21,34256,22222 2>/dev/null modprobe ip_nat_ftp 2>/dev/null modprobe ip_conntrack_irc ports=6667,6668,6669 2>/dev/null modprobe ip_nat_irc ports=6667,6668,6669 2>/dev/null modprobe imq numdevs=1 2>/dev/null infoline } modules_unload() { infoline "UnLoading modules... " modprobe -r ip_conntrack_ftp 2>/dev/null modprobe -r ip_nat_ftp 2>/dev/null modprobe -r ip_conntrack_irc 2>/dev/null modprobe -r ip_nat_irc 2>/dev/null modprobe -r imq 2>/dev/null infoline } firewall_policy() { infoline "Setting default policies... " ## set default drop $IPT -P INPUT DROP $IPT -P FORWARD DROP $IPT -P OUTPUT DROP infoline } firewall_flush() { infoline "Flushing firewall... " ## flush tables $IPT -t filter -F $IPT -t nat -F $IPT -t mangle -F ## call helpers firewall_destroy_helpers infoline } firewall_stop() { infoline "Stopping firewall... " $IPT -P INPUT ACCEPT $IPT -P FORWARD DROP $IPT -P OUTPUT ACCEPT infoline } firewall_init() { infoline "Init firewall... " ## accepting estabilshed stuff $IPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT $IPT -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT $IPT -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT ## router itself $IPT -A OUTPUT -m state --state NEW -j ACCEPT $IPT -A INPUT -i lo -j ACCEPT ## call helpers infoline } firewall_create_helpers() { for chain in $chains; do $IPT -N $chain done } firewall_destroy_helpers() { for chain in $chains; do $IPT -X $chain 2>/dev/null done } firewall_allow_local_services() { infoline "Allowing local services [" infoline "ssh" $IPT -A INPUT -m state --state NEW -p tcp --destination-port ssh -j ACCEPT infoline "smb(i)" $IPT -A INPUT -i $int -m state --state NEW -p tcp --destination-port 135:139 -j ACCEPT infoline "ftp" $IPT -A INPUT -m state --state NEW -p tcp --destination-port 21 -j ACCEPT infoline "http" $IPT -A INPUT -m state --state NEW -p tcp --destination-port http -j ACCEPT infoline "ping" $IPT -A INPUT -m state --state NEW -p icmp --icmp-type echo-request -j ACCEPT infoline "dns" $IPT -A INPUT -m state --state NEW -p tcp --destination-port 53 -j ACCEPT $IPT -A INPUT -m state --state NEW -p udp --destination-port 53 -j ACCEPT infoline "dhcp(w)" $IPT -A INPUT -i $wlan -m state --state NEW -p tcp --destination-port 67:68 -j ACCEPT $IPT -A INPUT -i $wlan -m state --state NEW -p udp --destination-port 67:68 -j ACCEPT infoline f } firewall_forward() { infoline "Constructing forward [" ## block rfc1918 private address forwarding $IPT -A FORWARD --destination 192.168.0.0/16 -j finalize $IPT -A FORWARD --destination 10.0.0.0/8 -j finalize ## allow forwarding for specified hosts for valid_host in $allow_forward; do infoline "$valid_host" $IPT -A FORWARD --in-interface $int --source $valid_host -j ACCEPT done ## allow wlan to internet $IPT -A FORWARD --in-interface $wlan --out-interface $ext -j ACCEPT infoline f } firewall_masquerade() { infoline "Masquerading... " $IPT -t nat -A POSTROUTING -o $ext -j MASQUERADE infoline } firewall_goodies() { infoline "Setting up special stuff [ " ### forward external ftp to an DMZ HOST # infoline " ftp_forward " # $IPT -t nat -A PREROUTING -p tcp -i $ext --destination-port 21 -j DNAT --to 192.168.99.200:21 # $IPT -A FORWARD -p tcp -i $ext --destination-port 20:21 -j ACCEPT ### forward external wc3 to simon infoline " warcraft_forward " $IPT -t nat -A PREROUTING -p tcp -i $ext --destination-port 6112 -j DNAT --to simon:6112 $IPT -A FORWARD -p tcp -i $ext --destination-port 6112 -j ACCEPT ### TRANSPARENT PROXY (force internal surfers to be routed through a proxy) # infoline " trans_proxy " # $IPT -t nat -A PREROUTING -p tcp -i $int --destination-port 80 -j REDIRECT --to-port 3128 # $IPT -A INPUT -p tcp -i $int --destination-port 3128 -j ACCEPT ### LOAD BALANCER (balance EXTERNAL port 80 traffic to three servers in DMZ # infoline " load_balance " # $IPT -t nat -A PREROUTING -p tcp -i $ext --destination-port 80 -j DNAT --to 192.168.99.1-192.168.99.3 # $IPT -A INPUT -p tcp -i $ext --destination-port 80 -j ACCEPT infoline f } firewall_finalize() { $IPT -A finalize -p tcp -j REJECT --reject-with tcp-reset $IPT -A finalize -j REJECT chains="INPUT FORWARD OUTPUT" for chain in $chains; do $IPT -A $chain -j finalize done } firewall_zero() { infoline "Zeroing all chains... " $IPT -t filter -Z $IPT -t mangle -Z $IPT -t nat -Z infoline } qos_flush() { infoline "Flushing QoS... " # upstream root qdisc $TC qdisc del dev $ext root 2>/dev/null $TC class del dev $ext 2>/dev/null # down $TC qdisc del dev imq0 root 2>/dev/null $TC class del dev imq0 2>/dev/null $IP link set imq0 down 2>/dev/null infoline } qos_ingress() { infoline "Setting up downstream QoS... " $IP link set imq0 up ## Create main class $TC qdisc add dev imq0 handle 1: root htb default 50 $TC class add dev imq0 parent 1: classid 1:1 htb rate 1000kbit ## Add leaf classes - TCP traffic in 21, non TCP traffic in 20 $TC class add dev imq0 parent 1:1 classid 1:10 htb rate 200kbit ceil 1000kbit quantum 1500 prio 0 $TC class add dev imq0 parent 1:1 classid 1:20 htb rate 250kbit ceil 1000kbit prio 1 $TC class add dev imq0 parent 1:1 classid 1:50 htb rate 350kbit ceil 1000kbit burst 30k prio 2 $TC class add dev imq0 parent 1:1 classid 1:99 htb rate 200kbit ceil 800kbit burst 30k prio 2 ## Attach qdisc to leaf classes $TC qdisc add dev imq0 parent 1:10 handle 10: esfq hash src limit 16 perturb 10 $TC qdisc add dev imq0 parent 1:20 handle 20: esfq hash src limit 16 perturb 10 $TC qdisc add dev imq0 parent 1:50 handle 50: esfq hash src limit 16 perturb 10 $TC qdisc add dev imq0 parent 1:99 handle 99: esfq hash src limit 16 perturb 10 ## Filter traffic into classes by fwmark $TC filter add dev imq0 parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10 $TC filter add dev imq0 parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20 $TC filter add dev imq0 parent 1:0 prio 0 protocol ip handle 50 fw flowid 1:50 $TC filter add dev imq0 parent 1:0 prio 0 protocol ip handle 99 fw flowid 1:99 infoline } classify_ingress() { infoline "Setting up downstream classifier... " ## restore connection marks $IPT -t mangle -A PREROUTING -i $ext -p tcp -j CONNMARK --restore-mark $IPT -t mangle -A PREROUTING -i $ext -p tcp -m mark ! --mark 0 -j IMQ ### HIGHEST Prio ( 200kbit ) # # Short TCP packets are probably ACKs, so rate up # $IPT -t mangle -A PREROUTING -i $ext -p tcp -m length --length :64 -j MARK --set-mark 10 # # ToS 0x10 # $IPT -t mangle -A PREROUTING -i $ext -m tos --tos Minimize-Delay -j MARK --set-mark 10 # # DNS name resolution (small packets) # $IPT -t mangle -A PREROUTING -i $ext -p tcp --source-port domain -j MARK --set-mark 10 # $IPT -t mangle -A PREROUTING -i $ext -p udp --source-port domain -j MARK --set-mark 10 # icmp $IPT -t mangle -A PREROUTING -i $ext -p icmp -j MARK --set-mark 10 # ### HIGH Prio ( 250 kbit ) # # http(s) $IPT -t mangle -A PREROUTING -i $ext -p tcp --source-port http -j MARK --set-mark 20 $IPT -t mangle -A PREROUTING -i $ext -p tcp --source-port https -j MARK --set-mark 20 # # imaps # $IPT -t mangle -A PREROUTING -i $ext -p tcp --source-port imaps -j MARK --set-mark 20 # ftp $IPT -t mangle -A PREROUTING -i $ext -p tcp --source-port 34256 -j MARK --set-mark 20 # ### LOWEST Prio ( 200kbit ) # # p2p $IPT -t mangle -A PREROUTING -i $ext -p tcp -m ipp2p --ipp2p -j MARK --set-mark 99 $IPT -t mangle -A PREROUTING -i $ext -p tcp -m ipp2p --bit -j MARK --set-mark 99 # ### REGULAR Prio ( 350 kbit ) # # All other traffic # $IPT -t mangle -A PREROUTING -i $ext -m mark --mark 0 -j MARK --set-mark 50 # ### save connection marks $IPT -t mangle -A PREROUTING -i $ext -p tcp -j CONNMARK --save-mark ## finally, instruct these packets to go through the imq0 we set up above $IPT -t mangle -A PREROUTING -i $ext -j IMQ infoline } qos_egress() { infoline "Setting up upstream QoS... " ## set interface qlen $IP link set dev $ext qlen 30 ## create root chain $TC qdisc add dev $ext root handle 1: htb default 50 #$TC class add dev $ext parent 1: classid 1:1 htb rate 250kbit $TC class add dev $ext parent 1: classid 1:1 htb rate 510kbit ## Add leaf classes # uplink to inet has 256k #$TC class add dev $ext parent 1:1 classid 1:10 htb rate 50kbit ceil 230kbit burst 2k quantum 1500 prio 0 #$TC class add dev $ext parent 1:1 classid 1:20 htb rate 100kbit ceil 210kbit burst 2k quantum 1500 prio 0 #$TC class add dev $ext parent 1:1 classid 1:50 htb rate 50kbit ceil 210kbit burst 2k quantum 1500 prio 1 #$TC class add dev $ext parent 1:1 classid 1:99 htb rate 50kbit ceil 150kbit burst 2k quantum 1500 prio 2 # inet uplink has 512k $TC class add dev $ext parent 1:1 classid 1:10 htb rate 100kbit ceil 450kbit burst 2k quantum 1500 prio 0 $TC class add dev $ext parent 1:1 classid 1:20 htb rate 150kbit ceil 450kbit burst 2k quantum 1500 prio 0 $TC class add dev $ext parent 1:1 classid 1:50 htb rate 150kbit ceil 400kbit burst 2k quantum 1500 prio 1 $TC class add dev $ext parent 1:1 classid 1:99 htb rate 150kbit ceil 400kbit burst 2k quantum 1500 prio 2 ## Attach qdisc to leaf classes # uplink $TC qdisc add dev $ext parent 1:10 handle 10: pfifo $TC qdisc add dev $ext parent 1:20 handle 20: esfq hash src limit 16 perturb 5 $TC qdisc add dev $ext parent 1:50 handle 50: esfq hash src limit 16 perturb 5 $TC qdisc add dev $ext parent 1:99 handle 99: esfq hash src limit 16 perturb 10 ## filter traffic into classes by fwmark # uplink $TC filter add dev $ext parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10 $TC filter add dev $ext parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20 $TC filter add dev $ext parent 1:0 prio 0 protocol ip handle 50 fw flowid 1:50 $TC filter add dev $ext parent 1:0 prio 0 protocol ip handle 99 fw flowid 1:99 infoline } classify_egress() { infoline "Setting up upstream classifier... " ## Restore connection marks $IPT -t mangle -A POSTROUTING -o $ext -p tcp -j CONNMARK --restore-mark $IPT -t mangle -A POSTROUTING -o $ext -p tcp -m mark ! --mark 0 -j ACCEPT ## HIGHiEST Prio # ICMP (ping) - high prio, impress friends $IPT -t mangle -A POSTROUTING -o $ext -p icmp -j MARK --set-mark 10 # DNS name resolution (small packets) $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port domain -j MARK --set-mark 10 $IPT -t mangle -A POSTROUTING -o $ext -p udp --destination-port domain -j MARK --set-mark 10 # ToS 0x10 (ssh ohne scp!) $IPT -t mangle -A POSTROUTING -o $ext -m tos --tos Minimize-Delay --j MARK --set-mark 10 # small packets (probably just ACKs) $IPT -t mangle -A POSTROUTING -o $ext -p tcp -m length --length :64 -j MARK --set-mark 10 # ssh $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port ssh -j MARK --set-mark 10 ## HIGH Prio # http $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port http -j MARK --set-mark 20 $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port https -j MARK --set-mark 20 # imaps $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port imaps -j MARK --set-mark 20 # games # stream $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port 8000 -j MARK --set-mark 20 ## REGULAR Prio # Default for low port traffic $IPT -t mangle -A POSTROUTING -o $ext -p tcp --dport 0:1024 -m mark ! --mark 0 -j MARK --set-mark 50 ## LOWEST Prio $IPT -t mangle -A POSTROUTING -o $ext -p tcp -m ipp2p --ipp2p -j MARK --set-mark 99 $IPT -t mangle -A POSTROUTING -o $ext -p tcp -m ipp2p --bit -j MARK --set-mark 99 $IPT -t mangle -A POSTROUTING -o $ext -p tcp --source-port 6880:6889 -j MARK --set-mark 99 $IPT -t mangle -A POSTROUTING -o $ext -p tcp --source-port 4660:4669 -j MARK --set-mark 99 $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port 6880:6889 -j MARK --set-mark 99 $IPT -t mangle -A POSTROUTING -o $ext -p tcp --destination-port 4660:4669 -j MARK --set-mark 99 ## save connection marks $IPT -t mangle -A POSTROUTING -o $ext -p tcp -j CONNMARK --save-mark infoline } accounting_construct() { infoline "Setting up accounting..." $IPT -I INPUT 1 -i $ext -j in-ext $IPT -I INPUT 1 -i $int -j in-int $IPT -I OUTPUT 1 -o $ext -j out-ext $IPT -I OUTPUT 1 -o $int -j out-int $IPT -I FORWARD 1 -i $int -o $ext -j forward-int $IPT -I FORWARD 1 -i $ext -o $int -j forward-ext for chain in $accounting_chains; do $IPT -A $chain -j RETURN done infoline } show_traffic() { echo -e "\033[31mtraffic:\033[m" echo -e "\033[1mexternal link\033[m" echo -n "up: " $IPT -v -L out-ext | awk '/RETURN/{print $2}' echo -n "down: " $IPT -v -L in-ext | awk '/RETURN/{print $2}' echo -e "\033[1minternal link\033[m" echo -n "up: " $IPT -v -L out-int | awk '/RETURN/{print $2}' echo -n "down: " $IPT -v -L in-int | awk '/RETURN/{print $2}' echo -e "\033[1mforwarding\033[m" echo -n "up: " $IPT -v -L forward-int | awk '/RETURN/{print $2}' echo -n "down: " $IPT -v -L forward-ext | awk '/RETURN/{print $2}' } accounting_flush() { infoline "Flushing accounting rules..." $IPT -t filter -Z $IPT -t nat -Z $IPT -t mangle -Z infoline } show_status () { echo -e "\033[31miptables:\033[m" echo -e "\033[1mfilter\033[m" $IPT -v -L INPUT echo $IPT -v -L OUTPUT echo $IPT -v -L FORWARD echo -e "\n\033[1mnat\033[m" $IPT -v -t nat -L PREROUTING echo $IPT -v -t nat -L POSTROUTING echo -e "\n\033[1mmangle\033[m" $IPT -v -t mangle -L PREROUTING echo $IPT -v -t mangle -L POSTROUTING echo -e "\n\033[31mlinks:\033[m" $IP -s -s link ls $ext $IP -s -s link ls $int } show_qos () { echo -e "\033[31mqos:\033[m" echo -e "\033[1mupstream\033[m" $TC -s qdisc show dev $ext $TC -s class show dev $ext echo -e "\033[1mdownstream\033[m" $TC -s qdisc show dev imq0 $TC -s class show dev imq0 } dns_update() { infoline "Updating dns record..." NEW_IP=`/sbin/ifconfig ppp0 | grep 'inet addr' | awk '{print $2}' | sed -e s/.*://` nsupdate -v -k $dns_keyfile >/dev/null << EOF server $dns_server zone $dns_domainname update delete $dns_hostname.$dns_domainname. A update add $dns_hostname.$dns_domainname. $dns_ttl A $NEW_IP send EOF infoline } adsl_start() { infoline "Connecting to QSC... [" adsl-start infoline f } adsl_stop() { infoline "Disconnecting from QSC... [" adsl-stop >/dev/null infoline f } case "$1" in start|restart) if [ "$1" = "start" ]; then echo -ne "\033[1mStarting blackShape... \033[m" infoline n modules_load adsl_start else echo -ne "\033[1mRestarting blackShape... \033[m" infoline n fi proc_init firewall_flush #accounting_flush firewall_policy firewall_create_helpers firewall_init firewall_allow_local_services firewall_forward firewall_masquerade firewall_goodies accounting_construct qos_flush qos_ingress classify_ingress qos_egress classify_egress firewall_finalize dns_update echo -e "\033[32mdone.\033[m" ;; stop) echo -ne "\033[1mStopping blackShape: \033[m" if [ $debug ] then echo fi qos_flush accounting_flush firewall_flush firewall_stop adsl_stop modules_unload echo -e "\033[32mdone.\033[m" ;; reconnect) qos_egress dns_update ;; status) show_status ;; qos) show_qos ;; traffic) show_traffic ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0