***Script*** General Firewall Rules Debian/Ubuntu Script

#!/bin/bash
# =========================================================================== #
# Description:        General Firewall Script for Debian/Ubuntu.
# Details:            iptables setup.
# Made for:           Linux, Cloudpanel (Debian & Ubuntu).
# Requirements:       ssh-keygen - ssh-copy-id root@127.0.0.1 (replace IP)
# Version:            0.1
# Make executable:    chmod +x firewall.sh
# =========================================================================== #

IPT="/sbin/iptables"

### Interfaces ###
PUB_IF="eth0"   # public interface
PRV_IF="eth1"   # private interface
LO_IF="lo"      # loopback
SERVER_IP=$(ifconfig eth0 | grep 'inet addr:' | awk -F'inet addr:' '{ print $2}' | awk '{ print $1}')

########## Allow/block services #################################################
ALLOW_SSH="true"
ALLOW_HTTP="true"
ALLOW_FTP="false"
ALLOW_STEAM="false"
ALLOW_OUTGOING_DNS="true"
ALLOW_OUTGOING_NTP="true"
ALLOW_OUTGOING_SMTP="true"
ALLOW_OUTGOING_ICMP="true"
ALLOW_INCOMING_ICMP="true"

USE_HARDENING_RULESET="true"

########## SSH #################################################
SSH_PORT=22

# This notes every NEW connection to port ${SSH_PORT} and adds it to the recent "list"
# If your IP is on the recent list, and you have ${SSH_LOGIN_ATTEMPT} or more entries on the list in the
# last ${SSH_LOGIN_ATTEMPT_TIMEFRAME} seconds, we drop your request.
SSH_LOGIN_ATTEMPT_PROTECTION="true"
SSH_LOGIN_ATTEMPT=4
SSH_LOGIN_ATTEMPT_TIMEFRAME_SECONDS=90

SSH_ALLOW_ONLY_IP="false"
SSH_ALLOW_ONLY_IP_LIST="122.xx.yy.zz/29"

#### FILES #####
CUSTOM_RULES=/root/.fw/customRules.sh
BLOCKED_IP_TDB=/root/.fw/blocked.ip.txt
SPOOFIP=""
#SPOOFIP="127.0.0.0/8 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 169.254.0.0/16 0.0.0.0/8 240.0.0.0/4 255.255.255.255/32 168.254.0.0/16 224.0.0.0/4 240.0.0.0/5 248.0.0.0/5 192.0.2.0/24"
#BADIPS=$( [[ -f ${BLOCKED_IP_TDB} ]] && egrep -v "^#|^$" ${BLOCKED_IP_TDB})

###########################################################
###    You shouldn't need to change below this line     ###
###########################################################

function allowPort() {
	if [[ "$1" == "in" ]]; then
		$IPT -A INPUT -i ${PUB_IF} -p $2 --dport $3 -m state --state NEW,ESTABLISHED -j ACCEPT
		$IPT -A OUTPUT -o ${PUB_IF} -p $2 --sport $3 -m state --state ESTABLISHED -j ACCEPT
	else
		$IPT -A OUTPUT -o ${PUB_IF} -p $2 --dport $3 -m state --state NEW,ESTABLISHED -j ACCEPT
		$IPT -A INPUT -i ${PUB_IF} -p $2 --sport $3 -m state --state ESTABLISHED -j ACCEPT
	fi
}

function customRules() {
    if [ -f ${CUSTOM_RULES} ]; then
        source ${CUSTOM_RULES}
    fi
}

function clearAllIpTablesRules() {
    echo "Clear all firewall rules";
    #Default policy is DROP so first change the INPUT FORWARD and OUTPUT policy before the -F or you will be locked.
    iptables -P INPUT ACCEPT
    iptables -P FORWARD ACCEPT
    iptables -P OUTPUT ACCEPT
    iptables -F
    iptables -X
    iptables -t nat -F
    iptables -t nat -X
    iptables -t mangle -F
    iptables -t mangle -X
}

function hardeningRules() {
    if [ "${USE_HARDENING_RULESET}" == "true" ]; then
        echo "Hardening: Drop sync"
        $IPT -A INPUT -i ${PUB_IF} -p tcp ! --syn -m state --state NEW -j DROP

        echo "Hardening: Drop Fragments"
        $IPT -A INPUT -i ${PUB_IF} -f -j DROP

        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL ALL -j DROP

        echo "Hardening: Drop NULL packets"
        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL NONE -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " NULL Packets "
        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL NONE -j DROP

        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,RST SYN,RST -j DROP

        echo "Hardening: Drop XMAS"
        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " XMAS Packets "
        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

        echo "Hardening: Drop FIN packet scans"
        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags FIN,ACK FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " Fin Packets Scan "
        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags FIN,ACK FIN -j DROP

        $IPT  -A INPUT -i ${PUB_IF} -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

        echo "Hardening: Log and get rid of broadcast / multicast and invalid"
        $IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type broadcast -j LOG --log-prefix " Broadcast "
        $IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type broadcast -j DROP

        $IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type multicast -j LOG --log-prefix " Multicast "
        $IPT  -A INPUT -i ${PUB_IF} -m pkttype --pkt-type multicast -j DROP

        $IPT  -A INPUT -i ${PUB_IF} -m state --state INVALID -j LOG --log-prefix " Invalid "
        $IPT  -A INPUT -i ${PUB_IF} -m state --state INVALID -j DROP
    fi
}

function logAndBlockSpoofedIPRules() {
    $IPT -N spooflist
    for ipblock in $SPOOFIP
    do
        $IPT -A spooflist -i ${PUB_IF} -s $ipblock -j LOG --log-prefix " SPOOF List Block "
        $IPT -A spooflist -i ${PUB_IF} -s $ipblock -j DROP
    done
    $IPT -I INPUT -j spooflist
    $IPT -I OUTPUT -j spooflist
    $IPT -I FORWARD -j spooflist
}

function sshRules() {
    if [ "${ALLOW_SSH}" == "true" ]; then
        echo "Allow SSH";

        if [ "${SSH_ALLOW_ONLY_IP}" == "true" ]; then
            # Allow ssh only from selected public ips
            for ip in ${SSH_ALLOW_ONLY_IP_LIST}
            do
                $IPT -A INPUT -i ${PUB_IF} -s ${ip} -p tcp -d ${SERVER_IP} --dport ${SSH_PORT} -j ACCEPT
                $IPT -A OUTPUT -o ${PUB_IF} -d ${ip} -p tcp -s ${SERVER_IP} --sport ${SSH_PORT} -j ACCEPT
            done
        else
            # allow for all
            $IPT -A INPUT -i ${PUB_IF}  -p tcp -d ${SERVER_IP} --dport ${SSH_PORT} -j ACCEPT
            $IPT -A OUTPUT -o ${PUB_IF} -p tcp -s ${SERVER_IP} --sport ${SSH_PORT} -j ACCEPT

            # allow for all (outbound)
            $IPT -A OUTPUT -o ${PUB_IF} -p tcp -s ${SERVER_IP} --dport ${SSH_PORT} -j ACCEPT
            $IPT -A INPUT -i ${PUB_IF}  -p tcp -d ${SERVER_IP} --sport ${SSH_PORT} -j ACCEPT
        fi

        if [ "${SSH_LOGIN_ATTEMPT_PROTECTION}" == "true" ]; then
            $IPT -I INPUT -p tcp --dport ${SSH_PORT} -i eth0 -m state --state NEW -m recent --set
            $IPT -I INPUT -p tcp --dport ${SSH_PORT} -i eth0 -m state --state NEW -m recent --update --seconds ${SSH_LOGIN_ATTEMPT_TIMEFRAME_SECONDS} --hitcount ${SSH_LOGIN_ATTEMPT} -j DROP
        fi
    fi
}

function icmpRules() {
    if [ "${ALLOW_INCOMING_ICMP}" == "true" ]; then
        echo "Allow incoming ICMP";
        $IPT -A INPUT -i ${PUB_IF} -p icmp --icmp-type 8 -s 0/0 -m state --state NEW,ESTABLISHED,RELATED -m limit --limit 30/sec  -j ACCEPT
        $IPT -A OUTPUT -o ${PUB_IF} -p icmp --icmp-type 0 -d 0/0 -m state --state ESTABLISHED,RELATED -j ACCEPT
    fi

    if [ "${ALLOW_OUTGOING_ICMP}" == "true" ]; then
        echo "Allow outgoing ICMP";
        $IPT -A OUTPUT -o ${PUB_IF} -p icmp --icmp-type echo-request -j ACCEPT
        $IPT -A INPUT -i ${PUB_IF} -p icmp --icmp-type echo-reply -j ACCEPT
    fi
}

function httpRules() {
    if [ "${ALLOW_HTTP}" == "true" ]; then
        echo "Allow HTTP";
        #allow http(s) inbound connection/response
        $IPT -A INPUT -i ${PUB_IF}  -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
        $IPT -A OUTPUT -o ${PUB_IF} -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT

        #allow http(s) outbound connection/response
        $IPT -A OUTPUT -o ${PUB_IF} -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
        $IPT -A INPUT -i ${PUB_IF}  -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
    fi
}

function dnsRules() {
    if [ "${ALLOW_OUTGOING_DNS}" == "true" ]; then
        echo "Allow outgoing DNS";
        allowPort out udp 53
    fi
}

function ntpRules() {
    if [ "${ALLOW_OUTGOING_NTP}" == "true" ]; then
        echo "Allow outgoing NTP";
        allowPort out udp 123
    fi
}

function smtpRules() {
    if [ "${ALLOW_OUTGOING_SMTP}" == "true" ]; then
        echo "Allow outgoing SMTP";
        allowPort out tcp 25
    fi
}

function ftpRules() {
    if [ "${ALLOW_FTP}" == "true" ]; then
        echo "Allow FTP";
        $IPT -A INPUT -p tcp --dport ftp -i ${PUB_IF} -j ACCEPT
        $IPT -A INPUT -p udp --dport ftp -i ${PUB_IF} -j ACCEPT

        $IPT -A INPUT -p tcp --dport ftp-data -i ${PUB_IF} -j ACCEPT
        $IPT -A INPUT -p udp --dport ftp-data -i ${PUB_IF} -j ACCEPT
    fi
}

function steamRules() {
    if [ "${ALLOW_STEAM}" == "true" ]; then
        echo "Allow Steam";
        allowPort in udp "27000:27030"
        allowPort out udp "27000:27030"

        allowPort in tcp "27014:27050"
        allowPort out tcp "27014:27050"

        allowPort in udp "4379:4380"
        allowPort out udp "4379:4380"
    fi
}

function dropAndCloseEverythingRules() {
    echo "Drop And Close Everything";
    $IPT -P INPUT DROP
    $IPT -P OUTPUT DROP
    $IPT -P FORWARD DROP
}

function dropAndLogEverythingElseRules() {
    $IPT -A INPUT -m limit --limit 5/m --limit-burst 7 -j LOG --log-prefix " DEFAULT DROP "
    $IPT -A INPUT -j DROP
}

function unlimitedLoopbackRules() {
    $IPT -A INPUT -i ${LO_IF} -j ACCEPT
    $IPT -A OUTPUT -o ${LO_IF} -j ACCEPT
}

function unlimitedPrivateRules() {
    $IPT -A INPUT -i ${PRV_IF} -j ACCEPT
    $IPT -A OUTPUT -o ${PRV_IF} -j ACCEPT
}

function createIptablesRules() {
    echo "Setting $(hostname) Firewall...";
    dropAndCloseEverythingRules
    unlimitedLoopbackRules
    unlimitedPrivateRules
    hardeningRules
    logAndBlockSpoofedIPRules
    sshRules
    httpRules
    icmpRules
    dnsRules
    ntpRules
    smtpRules
    ftpRules
    steamRules
    customRules
    dropAndLogEverythingElseRules
}

echo "  Choose one of the following options:"
echo
echo "[N]ew firewall rules"
echo "[C]lear all firewall rules"
echo "[T]est firewall rules"
echo "[S]ave firewall rules to /etc/network/iptables"
echo "[E]xit"
echo

read choice

case "$choice" in
    "N" | "n" )
        clearAllIpTablesRules
        createIptablesRules
    ;;
    "C" | "c" )
        clearAllIpTablesRules
    ;;
    "T" | "t" )
        clearAllIpTablesRules
        createIptablesRules
        iptables-apply
    ;;
    "S" | "s" )
        clearAllIpTablesRules
        createIptablesRules
        iptables-save > /etc/network/iptables
    ;;
    * )
        exit 0
    ;;
esac

Comments and Updates are welcomed