#!/bin/bash

### BEGIN INIT INFO
# Provides:		  firewall-3g
# Required-Start:	$network $local_fs
# Required-Stop:	 $network $local_fs
# Default-Start:	 2 3 4 5
# Default-Stop:
# Short-Description: The iptables init (firewall)
# Description:	   3gteam firewall initialization
### END INIT INFO

INETIF=eth0
HVIF=eth1
#LANIF=eth2
#VPN_LAN=tun0

# ----------------------------- run iptables and in6tables together -------------------------------

ipt64() {
	/sbin/ip6tables $@
	/sbin/iptables $@
}
ipt6() {
	/sbin/ip6tables $@
}
ipt4() {
	/sbin/iptables $@
}


# ----------------------------- init -------------------------------

fw_init() {

	echo -n " init"

	#modprobe ipt_LOG
	#modprobe ipt_limit

	#Turn on IP forwarding
	echo 1 >/proc/sys/net/ipv4/ip_forward

	# Reset tables
	ipt64 -F
	ipt64 -X
	ipt64 -t nat -F
	ipt64 -t mangle -F

	# Defaults (DROP ALL)
	ipt64 -P INPUT  DROP
	ipt64 -P FORWARD  DROP
	ipt64 -P OUTPUT  DROP

	# loopback (lo) traffic
	ipt64 -A INPUT -i lo -p all -j ACCEPT		# allow ALL input from loopback
	ipt64 -A FORWARD -i lo -p all -j ACCEPT		# allow ALL forward from loopback

	# fail2ban
	ipt64 -N filter_in_fail2ban
	ipt64 -N filter_in_fail2ban_jails

	ipt64 -A INPUT -j filter_in_fail2ban
	ipt64 -A filter_in_fail2ban -j filter_in_fail2ban_jails
	ipt64 -A filter_in_fail2ban -j RETURN
	ipt64 -A filter_in_fail2ban_jails -j RETURN

	# Munin-needed
	ipt4 -A INPUT -d 193.178.119.198
	ipt4 -A OUTPUT -s 193.178.119.198

	# ---------- FILTERS -----------

	# Create the drop filter
	ipt64 -N dropfilter
	ipt64 -A INPUT -j dropfilter
	ipt64 -A FORWARD -j dropfilter
	ipt64 -A OUTPUT -j dropfilter

	# Create the input and forward filtering chain
	ipt64 -N infwfilter
	ipt64 -A INPUT -j infwfilter
	ipt64 -A FORWARD -j infwfilter

	# Create the input filtering chain
	ipt64 -N infilter
	ipt64 -A INPUT -j infilter

	# Create the forwarding chain
	ipt64 -N fwfilter
	ipt64 -A FORWARD -j fwfilter

	# Create the output filtering chain
	ipt64 -N outfilter
	ipt64 -A OUTPUT -j outfilter

	# loopback (lo) traffic
	ipt64 -A OUTPUT -o lo -p all -j ACCEPT		# allow FILTERED output to loopback

}

# ----------------------------- input+forward+output drop filter chain -------------------------------

dropfilter() {

	echo -n " dropfilter"

	DROPLIST=/var/lib/droplist/drop.txt

	if [ -f $DROPLIST ]; then
		ipt4 -F dropfilter
		cat "$DROPLIST" \
		| sed -e 's/;.*//' \
		| grep -v '^ *$' \
		| while read NB ; do
			ipt4 -A dropfilter -s "$NB" -j DROP
			ipt4 -A dropfilter -d "$NB" -j DROP
		done
	fi

	DROPLIST6=/var/lib/droplist/drop6.txt

	if [ -f $DROPLIST6 ]; then
		ipt6 -F dropfilter
		cat "$DROPLIST6" \
		| sed -e 's/;.*//' \
		| grep -v '^ *$' \
		| while read NB ; do
			ipt6 -A dropfilter -s "$NB" -j DROP
			ipt6 -A dropfilter -d "$NB" -j DROP
		done
	fi

}

# ----------------------------- output filter chain -------------------------------

outfilter() {

	echo -n " outfilter"
	ipt64 -F outfilter

	ipt64 -A outfilter -p icmp -j ACCEPT

	ipt64 -A outfilter -p tcp -m tcp --dport 25 -m owner --uid-owner 33 -j DROP

	ipt4 -A outfilter -s 127.0.0.0/8 -d 127.0.0.0/8 -p tcp -m tcp --dport 10024:10027 -m owner --uid-owner 33 -j DROP
	ipt6 -A outfilter -s "::1/128" -d "::1/128" -p tcp -m tcp --dport 10024:10027 -m owner --uid-owner 33 -j DROP

	ipt64 -A outfilter -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT

	# allow OUTPUT
				ipt64 -A OUTPUT -o $INETIF -p all -j ACCEPT		# allow ALL output to INET
	[ -n "$HVIF" ] &&	ipt64 -A OUTPUT -o $HVIF -p all -j ACCEPT		# allow ALL output to HVLAN
	[ -n "$LANIF" ] &&	ipt64 -A OUTPUT -o $LANIF -p all -j ACCEPT		# allow ALL output to LAN

}

# ------------------------- input+forward filter chain -------------------------------

infwfilter() {
	echo -n " infwfilter"
	ipt64 -F infwfilter

	# Protect against common attacks
	ipt64 -A infwfilter -i $INETIF -p tcp ! --syn -m state --state NEW -j DROP		# NEW packets should be SYN
	ipt4 -A infwfilter -i $INETIF -f -j DROP						# IP fragmentation attack (IPv4 only)

	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ACK,FIN FIN -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ACK,PSH PSH -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ACK,URG URG -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ALL ALL -j DROP			# XMAS packets
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ALL NONE -j DROP			# NULL packets
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
	ipt64 -A infwfilter -i $INETIF -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

	# Protect against fake LAN/loopback connections from INET
	SPOOF_INET_4="0.0.0.0/8 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 224.0.0.0/3"
	for spoofip in $SPOOF_INET_4; do
		ipt4 -A infwfilter -i $INETIF -p all -s "$spoofip" -j DROP
	done

	SPOOF_INET_6="::1/128 fe80::/10 fc00::/7"
	for spoofip in $SPOOF_INET_6; do
		ipt6 -A infwfilter -i $INETIF -p all -s "$spoofip" -j DROP
	done

	# Protect against fake loopback connections from LAN, VPN
	SPOOF_LAN="0.0.0.0/8 127.0.0.0/8"
	for spoofip in $SPOOF_LAN; do
		[ -n "$HVIF" ] &&	ipt4 -A infwfilter -i $HVIF -p all -s "$spoofip" -j DROP
		[ -n "$LANIF" ] &&	ipt4 -A infwfilter -i $LANIF -p all -s "$spoofip" -j DROP
		[ -n "$VPN_LAN" ] &&	ipt4 -A infwfilter -i $VPN_LAN -p all -s "$spoofip" -j DROP
	done

	SPOOF_LAN_6="::1/128 fe80::/10"
	for spoofip in $SPOOF_LAN_6; do
		[ -n "$HVIF" ] &&	ipt6 -A infwfilter -i $HVIF -p all -s "$spoofip" -j DROP
		[ -n "$LANIF" ] &&	ipt6 -A infwfilter -i $LANIF -p all -s "$spoofip" -j DROP
		[ -n "$VPN_LAN" ] &&	ipt6 -A infwfilter -i $VPN_LAN -p all -s "$spoofip" -j DROP
	done

	# -----------------------------------------------------------------------------

	# ICMP PING
	ipt4 -A infwfilter -p icmp --icmp-type echo-request -m limit --limit 10/s -j ACCEPT
	ipt6 -A infwfilter -p icmpv6 --icmpv6-type echo-request -m limit --limit 10/s -j ACCEPT

	# ICMP fragmentation needed (ipv4) / packet too big (ipv6)
	ipt4 -A infwfilter -p icmp --icmp-type fragmentation-needed -m limit --limit 10/s -j ACCEPT
	ipt6 -A infwfilter -p icmpv6 --icmpv6-type packet-too-big -m limit --limit 10/s -j ACCEPT

	# ICMP time exceeded
	ipt4 -A infwfilter -p icmp --icmp-type time-exceeded -m limit --limit 10/s -j ACCEPT
	ipt6 -A infwfilter -p icmpv6 --icmpv6-type time-exceeded -m limit --limit 10/s -j ACCEPT

}

# ------------------------------ input filter chain -------------------------------

infilter() {

	echo -n " infilter"
	ipt64 -F infilter

	# -----------------------------------------------------------------------------

	#SSH
	ipt64 -A infilter -i $INETIF -p tcp --dport 4224 -j ACCEPT

	#FTP & SFTP server
	ipt64 -A infilter -i $INETIF -p tcp --dport 21 -j ACCEPT
	ipt64 -A infilter -i $INETIF -p tcp --dport 121 -j ACCEPT
	ipt64 -A infilter -i $INETIF -p tcp --dport 20 -j ACCEPT

	# FTP passive port range
	ipt64 -A infilter -i $INETIF -p tcp --dport 19200:20200 -j ACCEPT
	ipt64 -A infilter -i $INETIF -p tcp --dport 17200:18200 -j ACCEPT

	#WWW + WWW-SSL
	ipt64 -A infilter -i $INETIF -p tcp --dport 80 -j ACCEPT
	ipt64 -A infilter -i $INETIF -p tcp --dport 443 -j ACCEPT
	# Apache + PHP 7.2
	ipt64 -A infilter -i $INETIF -p tcp --dport 8072 -j ACCEPT

	#MySQL [SSL Tunneled on port 33306]
	ipt64 -A infilter -i $INETIF -p tcp --dport 33306 -j ACCEPT

	# STATUSd
	ipt64 -A infilter -i $INETIF -p tcp --dport 34000 -m limit --limit 1/s -j ACCEPT

	#identd -> REJECT [needed, but DROP if not]
	ipt64 -A infilter -i $INETIF -p tcp --dport 113 -m limit --limit 4/s  -j REJECT

	# -----------------------------------------------------------------------------
	# ACCEPTING from $INETIF
	ipt64 -A infilter -i $INETIF -m state --state RELATED,ESTABLISHED -j ACCEPT

	ipt64 -A infilter -i $INETIF -m state --state NEW,INVALID -j DROP
	ipt64 -A infilter -i $INETIF -j DROP

	# -----------------------------------------------------------------------------
	# Hypervisor local HVLAN interface

	if [ -n "$HVIF" ]; then
		ipt64 -A infilter -i $HVIF -p tcp --dport 4224 -j ACCEPT

		ipt64 -A infilter -i $HVIF -m state --state RELATED,ESTABLISHED -j ACCEPT
		ipt64 -A infilter -i $HVIF -m state --state NEW,INVALID -j DROP
		ipt64 -A infilter -i $HVIF -j DROP
	fi

	# -----------------------------------------------------------------------------
	# LAN interface

	if [ -n "$LANIF" ]; then

		ipt64 -A infilter -i $LANIF -p tcp --dport 4224 -j ACCEPT
		ipt64 -A infilter -i $LANIF -p tcp --dport 80 -j ACCEPT
		ipt64 -A infilter -i $LANIF -p tcp --dport 443 -j ACCEPT

		ipt64 -A infilter -i $LANIF -m state --state RELATED,ESTABLISHED -j ACCEPT
		ipt64 -A infilter -i $LANIF -m state --state NEW,INVALID -j DROP
		ipt64 -A infilter -i $LANIF -j DROP
	fi

	# -----------------------------------------------------------------------------
	# VPN-LAN interface

	if [ -n "$VPN_LAN" ]; then

		ipt64 -A infilter -i $VPN_LAN -p tcp --dport 4224 -j ACCEPT
		ipt64 -A infilter -i $VPN_LAN -p tcp --dport 80 -j ACCEPT
		ipt64 -A infilter -i $VPN_LAN -p tcp --dport 443 -j ACCEPT

		ipt64 -A infilter -i $VPN_LAN -m state --state RELATED,ESTABLISHED -j ACCEPT
		ipt64 -A infilter -i $VPN_LAN -m state --state NEW,INVALID -j DROP
		ipt64 -A infilter -i $VPN_LAN -j DROP
	fi


	# -----------------------------------------------------------------------------
	# drop all remaining

	ipt64 -A infilter -m state --state NEW,INVALID -j DROP
	ipt64 -A infilter -j DROP

}

# ------------------------------ forward filter chain -------------------------------

fwfilter() {

	echo -n " fwfilter"
	ipt64 -F fwfilter

	# -----------------------------------------------------------------------------
	# INET interface

	ipt64 -A fwfilter -i $INETIF -m state --state RELATED,ESTABLISHED -j ACCEPT

	# -----------------------------------------------------------------------------
	# LAN interface

	if [ -n "$LANIF" ]; then

		#ipt64 -A fwfilter -i $LANIF -j ACCEPT						# LAN
		ipt64 -A fwfilter -i $LANIF -o $LANIF -j ACCEPT					# Everything inside LAN
		[ -n "$VPN_LAN" ] && ipt64 -A fwfilter -i $LANIF -o $VPN_LAN -j ACCEPT		# Everything LAN-VPN

		ipt64 -A fwfilter -i $LANIF -m state --state RELATED,ESTABLISHED -j ACCEPT
		ipt64 -A fwfilter -i $LANIF -j DROP
	fi

	if [ -n "$VPN_LAN" ]; then

		#ipt64 -A fwfilter -i $VPN_LAN -j ACCEPT					# VPN_LAN
		ipt64 -A fwfilter -i $VPN_LAN -o $VPN_LAN -j ACCEPT				# Everything inside VPN
		[ -n "$LANIF" ] && ipt64 -A fwfilter -i $VPN_LAN -o $LANIF -j ACCEPT		# Everything VPN-LAN

		ipt64 -A fwfilter -i $VPN_LAN -m state --state RELATED,ESTABLISHED -j ACCEPT
		ipt64 -A fwfilter -i $VPN_LAN -j DROP
	fi


	ipt64 -A fwfilter -m state --state NEW,INVALID -j DROP
	ipt64 -A fwfilter -j DROP

}

# ----------------------------------------------------------------------------------

case "$1" in
	start|restart)

		echo -n "Initializing firewall rules: "

		fw_init
		outfilter
		infwfilter
		infilter
		fwfilter
		dropfilter

		echo " done."

		[ -f /var/run/fail2ban/fail2ban.pid ] && /etc/init.d/fail2ban restart
		exit 0
		;;
	reload)

		echo -n "Reloading firewall filters: "

		outfilter
		infwfilter
		infilter
		fwfilter
#		dropfilter

		echo " done."
		exit 0
		;;
	stop)
		exit 0
		;;
	*)
		echo "Usage: $0 {start|restart|reload}"
		exit 1
	;;
esac
