initial router config
authorJustin Wind <justin.wind+git@gmail.com>
Sun, 1 Oct 2017 18:24:54 +0000 (11:24 -0700)
committerJustin Wind <justin.wind+git@gmail.com>
Sun, 1 Oct 2017 18:24:54 +0000 (11:24 -0700)
router.sh [new file with mode: 0755]

diff --git a/router.sh b/router.sh
new file mode 100755 (executable)
index 0000000..2ff05af
--- /dev/null
+++ b/router.sh
@@ -0,0 +1,294 @@
+#!/bin/bash
+
+set -e
+
+# some system-specific config...
+
+EXT=173.164.216.234
+EXT_IF=eth2
+
+INT='192.168.0.0/24'
+INT_IF=eth5
+
+EXT6_IF=he6
+INT6_IF=eth5
+SUBNET6='2001:470:1f05:cb8::/64'
+
+UPLINK=11232 #kbit
+BURST=15 #k
+
+# note that behavior between v4 and v6 is slightly different
+
+###
+##
+#
+IPTABLES=$(which iptables)
+IP6TABLES=$(which ip6tables)
+IPSET=$(which ipset)
+TC=$(which tc)
+SYSCTL=/usr/sbin/sysctl
+F2B_CTL="/etc/init.d/fail2ban"
+
+if [ "commit" != "$1" ]; then
+       IPTABLES="echo ${IPTABLES}"
+       IP6TABLES="echo ${IP6TABLES}"
+       IPSET="echo ${IPSET}"
+       TC="echo ${TC}"
+       SYSCTL="echo ${SYSCTL}"
+       F2B_CTL="echo ${F2B_CTL}"
+fi
+
+# fail2ban writes its own chains, don't flush tables before shutting it down
+f2b_needs_attention=0
+if f2b_pid=$(cat /var/run/fail2ban/fail2ban.pid)
+then
+       f2b_comm=`ps -o comm= -p ${f2b_pid}`
+       if [ $? -eq 0 ]; then
+               if [ "fail2ban-server" = "${f2b_comm}" ]; then
+                       f2b_needs_attention=1
+               fi
+       fi
+fi
+
+function sysctl_set(){
+       if [ "$2" != $($SYSCTL -ne "$1") ]
+       then
+               echo "setting $1 to $2"
+               $SYSCTL -w "$1"="$2"
+       fi
+}
+
+# system config
+# enable forwarding
+sysctl_set net.ipv4.ip_forward 1
+sysctl_set net.ipv6.conf.all.forwarding 1
+# disable routing triangulation; queries go out same interface
+sysctl_set net.ipv4.conf.all.rp_filter 1
+# log malformed packets
+#${SYSCTL} -w net.ipv4.conf.all.log_martians=1
+sysctl_set net.ipv4.conf.all.log_martians 0
+# disable redirects
+sysctl_set net.ipv4.conf.all.send_redirects 0
+sysctl_set net.ipv4.conf.all.accept_redirects 0
+# disable source routed packets
+sysctl_set net.ipv4.conf.all.accept_source_route 0
+# do syncookies
+sysctl_set net.ipv4.tcp_syncookies 1
+
+if [ ${f2b_needs_attention} -eq 1 ]; then
+       ${F2B_CTL} stop
+fi
+
+# flush tables
+${IPTABLES} -F
+${IPTABLES} -F INPUT
+${IPTABLES} -F OUTPUT
+${IPTABLES} -F FORWARD
+${IPTABLES} -F -t mangle
+${IPTABLES} -F -t nat
+${IPTABLES} -X 
+
+$IP6TABLES -F
+$IP6TABLES -F INPUT
+$IP6TABLES -F OUTPUT
+$IP6TABLES -F FORWARD
+$IP6TABLES -F -t mangle
+$IP6TABLES -X
+
+# default policies
+$IPTABLES -P INPUT DROP
+$IPTABLES -P OUTPUT ACCEPT
+$IPTABLES -P FORWARD ACCEPT
+
+$IP6TABLES -P INPUT DROP
+$IP6TABLES -P OUTPUT DROP
+$IP6TABLES -P FORWARD DROP
+
+# clear and reset traffic control
+(
+set +e
+if $TC qdisc del dev ${EXT_IF}
+then
+       echo "removed existing qdisc"
+else
+       echo "new qdisc"
+fi
+if $TC qdisc add dev ${EXT_IF} root handle 1: htb default 30
+then
+       echo "qdisc root exists"
+else
+       echo "new qdisc root"
+fi
+$TC class add dev ${EXT_IF} parent 1: classid 1:1 htb rate ${UPLINK}kbit burst ${BURST}k
+$TC class add dev ${EXT_IF} parent 1:1 class 1:10 htb rate ${UPLINK}kbit burst ${BURST}k prio 1
+$TC class add dev ${EXT_IF} parent 1:1 class 1:20 htb rate ${UPLINK}kbit burst ${BURST}k prio 2
+$TC class add dev ${EXT_IF} parent 1:1 class 1:30 htb rate $(expr 9 \* ${UPLINK} / 10)kbit burst ${BURST}k prio 3
+$TC class add dev ${EXT_IF} parent 1:1 class 1:40 htb rate $(expr 5 \* ${UPLINK} / 10)kbit burst ${BURST}k prio 4
+$TC class add dev ${EXT_IF} parent 1:1 class 1:50 htb rate $(expr 5 \* ${UPLINK} / 10)kbit burst $(expr 2 \* ${BURST} / 3)k prio 5
+
+for x in $(seq 5)
+do
+       $TC qdisc add dev ${EXT_IF} parent 1:${x}0 handle ${x}0: sfq perturb 10
+       $TC filter add dev ${EXT_IF} parent 1: prio 0 protocol ip handle ${x} fw flowid 1:${x}0
+done
+)
+
+SHAPE_CHAIN='SHAPER-OUT'
+# shaper marking
+$IPTABLES -t mangle -X ${SHAPE_CHAIN}
+$IPTABLES -t mangle -N ${SHAPE_CHAIN}
+$IP6TABLES -t mangle -X ${SHAPE_CHAIN}
+$IP6TABLES -t mangle -N ${SHAPE_CHAIN}
+
+function shape() {
+       local PRIO=$1
+       shift
+       if ! $IPTABLES -t mangle -C ${SHAPE_CHAIN} "$@" -j MARK --set-mark ${PRIO} >/dev/null 2>&1
+       then
+               $IPTABLES -t mangle -A ${SHAPE_CHAIN} "$@" -j MARK --set-mark ${PRIO}
+       fi
+       if ! $IP6TABLES -t mangle -C ${SHAPE_CHAIN} "$@" -j MARK --set-mark ${PRIO} >/dev/null 2>&1
+       then
+               $IP6TABLES -t mangle -A ${SHAPE_CHAIN} "$@" -j MARK --set-mark ${PRIO}
+       fi
+}
+
+# prioritize small and responsive things
+shape 1 -p icmp
+shape 1 -p ipv6-icmp
+shape 1 -p udp
+#shape 1 -p tcp -m length :64
+#shape 1 -p tcp --syn -m length 40:68
+#shape 1 -p tcp --tcp-flags ALL ACK -m length --length 40:100
+shape 1 -p tcp --tcp-flags ALL RST
+shape 1 -p tcp --tcp-flags ALL ACK,RST
+shape 1 -p tcp --tcp-flags ALL ACK,FIN
+
+# favor ssh
+shape 2 -p tcp --dport 22
+
+# defavor ftp
+shape 4 -p tcp --dport 20
+shape 4 -p tcp --dport 115
+
+# bulk bittorrent
+shape 5 -p tcp --dport 8881:8899
+shape 5 -p tcp --sport 8881:8899
+  
+# default everything else to middle
+shape 3 -m mark --mark 0
+
+# tag traffic
+$IPTABLES -t mangle -I POSTROUTING -o ${EXT_IF} -j ${SHAPE_CHAIN}
+
+
+# reserve a special place in hell for some people
+$IPTABLES -N xenophobe
+$IPTABLES -A xenophobe -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
+$IPTABLES -A xenophobe -j REJECT --reject-with icmp-port-unreachable
+
+$IP6TABLES -N xenophobe
+$IP6TABLES -A xenophobe -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
+$IP6TABLES -A xenophobe -j REJECT --reject-with icmp6-port-unreachable
+
+# create ipsets for v4 and v6
+for s in xenophobe sinokorea
+do
+       $IPSET create "$s" -exist hash:net counters
+       $IPSET create "$s"6 -exist hash:net family inet6 counters
+done
+for s in trusted
+do
+       $IPSET create "$s" -exist hash:net
+       $IPSET create "$s"6 -exist hash:net family inet6
+done
+
+# create ipsets shared by v4 and v6 
+for s in allowed_udp allowed_tcp
+do
+       $IPSET create "$s" -exist bitmap:port range 0-65535
+done
+
+
+###
+##
+#
+
+# allow local traffics
+$IPTABLES -A INPUT -i lo -j ACCEPT
+$IP6TABLES -A INPUT -i lo -j ACCEPT
+$IP6TABLES -A OUTPUT -o lo -j ACCEPT
+
+# allow anything out to v6
+$IP6TABLES -A OUTPUT -o ${EXT6_IF} -j ACCEPT
+
+# allow all internal traffic in
+$IP6TABLES -I INPUT -i ${INT6_IF} -j ACCEPT
+
+# allow icmp
+$IPTABLES -A INPUT -p icmp -j ACCEPT
+$IP6TABLES -A INPUT -p ipv6-icmp -j ACCEPT
+$IP6TABLES -A OUTPUT -p ipv6-icmp -j ACCEPT
+$IP6TABLES -A FORWARD -p ipv6-icmp -j ACCEPT
+
+# drop source-route headered v6
+$IP6TABLES -A INPUT -m rt --rt-type 0 -j DROP || echo "MISSING RT MATCH" 1>&2
+
+# drop bad packets; these are all illegal combinations
+for flags in 'ALL FIN,URG,PSH' 'ALL ALL' 'ALL SYN,RST,ACK,FIN,URG' 'ALL NONE' 'SYN,RST SYN,RST' 'SYN,FIN SYN,FIN'
+do
+       $IPTABLES -A INPUT -p tcp --tcp-flags ${flags} -j DROP
+done
+
+# allow trusted things
+$IPTABLES -A INPUT -m set --match-set trusted src -j ACCEPT
+$IP6TABLES -A INPUT -m set --match-set trusted6 src -j ACCEPT
+
+# drop sketchy things
+$IPTABLES -A INPUT -m set --match-set xenophobe src -j xenophobe
+$IP6TABLES -A INPUT -m set --match-set xenophobe6 src -j xenophobe
+
+# drop asia from ssh and smtp
+$IPTABLES -A INPUT -m set --match-set sinokorea src -m multiport -p tcp --dports ssh,smtp -j xenophobe
+$IP6TABLES -A INPUT -m set --match-set sinokorea6 src -m multiport -p tcp --dports ssh,smtp -j xenophobe
+
+# don't forward packets in
+$IPTABLES -A FORWARD -i ${EXT_IF} -m conntrack --ctstate NEW,INVALID -j DROP
+
+# forward from internal site subnet
+$IP6TABLES -A FORWARD -i ${INT6_IF} -o ${EXT6_IF} -s ${SUBNET6} -m conntrack --ctstate NEW -j ACCEPT
+
+# allow things we've dealt with
+$IPTABLES -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+$IP6TABLES -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+$IP6TABLES -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
+
+# accept ipv6 link-local
+$IP6TABLES -A INPUT -s fe80::/10 -j ACCEPT
+$IP6TABLES -A OUTPUT -s fe80::/10 -j ACCEPT
+
+# accept ipv6 multicast
+$IP6TABLES -A INPUT -s ff00::/8 -j ACCEPT
+$IP6TABLES -A OUTPUT -s ff00::/8 -j ACCEPT
+
+# many:1 NAT
+$IPTABLES -t nat -A POSTROUTING -o ${EXT_IF} -j SNAT --to ${EXT}
+
+# accept internal network traffic
+$IPTABLES -A INPUT -i ${INT_IF} -j ACCEPT
+
+# accept list of external ports
+$IPTABLES -A INPUT -i ${EXT_IF} -p tcp -m set --match-set allowed_tcp dst -j ACCEPT
+$IPTABLES -A INPUT -i ${EXT_IF} -p udp -m set --match-set allowed_udp dst -j ACCEPT
+$IP6TABLES -A INPUT -i ${EXT6_IF} -p tcp -m set --match-set allowed_tcp dst -j ACCEPT
+$IP6TABLES -A INPUT -i ${EXT6_IF} -p udp -m set --match-set allowed_udp dst -j ACCEPT
+
+# load rules
+# inserts, so stack order matters
+./sinokorea.sh
+./xenophobe.sh
+./trusted.sh
+
+if [ ${f2b_needs_attention} -eq 1 ]; then
+       ${F2B_CTL} start
+fi