#!/bin/bash 
# DATE: 2022-12-08
# This is the FirewallD. To enable it, su to root and run the script.

#set -x

hostIps="60.249.151.181/32 192.168.128.11/32 192.168.0.11/32"
officeMtIps="59.125.131.1/32 59.125.131.2/32 59.125.131.3/32 59.125.131.151/32 59.125.131.152/32 59.125.131.153/32"
idcMtIps="60.249.151.181/32 60.249.151.182/32 60.249.151.183/32 60.249.151.184/32 60.249.151.185/32 60.249.151.186/32"
mtIps="${officeMtIps} ${idcMtIps}"
localhostIps="127.0.0.1/8"
privateIps="10.0.0.0/8 172.16.0.0/12 192.168.0.0/16"

forwardPortList="80:8080 443:8443"
acceptedServiceList="http https"

anyAcceptedIps="${localhostIps} ${hostIps}"
activeMQAdminAcceptedIps="${privateIps} ${mtIps}"
cockpitAcceptedIps="${privateIps} ${mtIps}"
#mariaDbAcceptedIps="${localhostIps}"
mariaDbAcceptedIps=""
#nfsAcceptedIps="192.168.0.0/24 192.168.128.0/24 ${idcMtIps}"
nfsAcceptedIps=""
pgAcceptedIps="${localhostIps} ${privateIps} ${mtIps}"
pingAcceptedIps="${privateIps} ${mtIps}"
sshAcceptedIps="${privateIps} ${mtIps}"
rdpAcceptedIps="${privateIps} ${mtIps}"

fwCmd="/usr/bin/firewall-cmd"
fwZone="mt-cloud"
fwZoneDefaultTarget="DROP"
fwZoneShortDesc="For mt-cloud environment."
fwZoneDesc="For mt-cloud environment. Only selected incoming connections are accepted."

function init-fw-zone() {
	${fwCmd} --permanent --zone="${fwZone}" --list-all 2>/dev/null

	# If zone ${fwZone} is created, delete it first.
	if [ "${?}" == "0" ]; then
		${fwCmd} --permanent --delete-zone="${fwZone}"
	else
		echo "Zone ${fwZone} not found. Will be created."
	fi

	# Create zone ${fwZone}
	${fwCmd} --permanent --new-zone="${fwZone}"

	# Reset target, short, and description.
	${fwCmd} --permanent --zone="${fwZone}" --set-target="${fwZoneDefaultTarget}"
	${fwCmd} --permanent --zone="${fwZone}" --set-short="${fwZoneShortDesc}"
	${fwCmd} --permanent --zone="${fwZone}" --set-description="${fwZoneDesc}"
}

function pre-extra-rules() {
	return 0
}

function add-forward-port() {
	local fromPortToPortList=${1} # For example: "80:8080 443:8443"

	local fromPortToPort
	for fromPortToPort in ${fromPortToPortList}; do
		# ${fromPortToPort} such as "80:8080"
		local fromPort=$(echo "${fromPortToPort}" | cut -d ":" -f 1)
		local toPort=$(echo "${fromPortToPort}" | cut -d ":" -f 2)
		${fwCmd} --permanent --zone="${fwZone}" --add-forward-port="port=${fromPort}:proto=tcp:toport=${toPort}"
	done
}

function add-service() {
	local serviceList=${1} # For example: "http https"

	local service
	for service in ${serviceList}; do
		${fwCmd} --permanent --zone="${fwZone}" --add-service="${service}"
	done
}

function add-rich-rule() {
	local family=${1} #ipv4|ipv6
	local srcAddrList=${2} # For example: "127.0.0.0/8 192.168.0.0/16"
	local action=${3} #accept|reject|drop|mark
	local portsOrServiceList=${4} # For example: "22 http https 2001-2020"

	local srcAddr
	for srcAddr in ${srcAddrList}; do
		if [ "${portsOrServiceList}" == "" ]; then
			#firewall-cmd --permanent --zone="mt-cloud" --add-rich-rule "rule family='ipv4' source address='192.168.0.0/16' accept"
			${fwCmd} --permanent --zone="${fwZone}" --add-rich-rule "rule family='${family}' source address='${srcAddr}' ${action}"
		else
			local portsOrService
			for portsOrService in ${portsOrServiceList}; do
				local ports=""
				local service=""
				[[ ${portsOrService} =~ ^[0-9]+(-[0-9]+)?$ ]] && ports=${portsOrService} || service=${portsOrService}
				if [ "${ports}" != "" ]; then
					#firewall-cmd --permanent --zone="mt-cloud" --add-rich-rule "rule family='ipv4' source address='192.168.0.0/16' port port='18080' accept"
					#firewall-cmd --permanent --zone="mt-cloud" --add-rich-rule "rule family='ipv4' source address='192.168.0.0/16' port port='18080-18443' accept"
					${fwCmd} --permanent --zone="${fwZone}" --add-rich-rule "rule family='${family}' source address='${srcAddr}' port port='${ports}' protocol='tcp' ${action}"
					${fwCmd} --permanent --zone="${fwZone}" --add-rich-rule "rule family='${family}' source address='${srcAddr}' port port='${ports}' protocol='udp' ${action}"
				elif [ "${service}" != "" ]; then
					#firewall-cmd --permanent --zone="mt-cloud" --add-rich-rule "rule family='ipv4' source address='192.168.0.0/16' service name='ssh' accept"
					${fwCmd} --permanent --zone="${fwZone}" --add-rich-rule "rule family='${family}' source address='${srcAddr}' service name='${service}' ${action}"
				fi
			done
		fi
	done
}

function allow-icmp-for-ping() {
	local family=${1} #ipv4|ipv6
	local srcAddrList=${2} # For example: "127.0.0.0/8 192.168.0.0/16"
	${fwCmd} --permanent --zone="${fwZone}" --add-icmp-block-inversion

	local srcAddr
	for srcAddr in ${srcAddrList}; do
		${fwCmd} --permanent --zone="${fwZone}" --add-rich-rule "rule family='${family}' source address='${srcAddr}' icmp-type name='echo-request' accept"
	done
}

function post-extra-rules() {
	return 0
}

function let-fw-be-active() {
	${fwCmd} --reload
	if [ "$(${fwCmd} --get-default-zone)" != "${fwZone}" ]; then
		${fwCmd} --set-default-zone="${fwZone}"
	fi
	#${fwCmd} --permanent --zone="${fwZone}" --list-all
	${fwCmd} --zone="${fwZone}" --list-all
}

init-fw-zone

# Customize additional firewall rules beforehand
pre-extra-rules

# Forward ports
add-forward-port "${forwardPortList}"

# Allow servies for any ip addr
add-service "${acceptedServiceList}"

# Allow any for specified ip addr
add-rich-rule "ipv4" "${anyAcceptedIps}" "accept"

# Allow Apache ActiveMQ for specified ip addr
add-rich-rule "ipv4" "${activeMQAdminAcceptedIps}" "accept" "8161 61616"

# Allow Cockpit for specified ip addr
add-rich-rule "ipv4" "${cockpitAcceptedIps}" "accept" "cockpit"

# Allow MariaDB / MySQL for specified ip addr
add-rich-rule "ipv4" "${mariaDbAcceptedIps}" "accept" "mysql"

# Allow NFS for specified ip addr
add-rich-rule "ipv4" "${nfsAcceptedIps}" "accept" "nfs rpc-bind mountd"

# Allow PostgreSQL for specified ip addr
add-rich-rule "ipv4" "${pgAcceptedIps}" "accept" "postgresql"

# Allow PING(response echo-reply for echo-request) for specified ip addr
allow-icmp-for-ping "ipv4" "${pingAcceptedIps}"

# Allow SSH for specified ip addr
add-rich-rule "ipv4" "${sshAcceptedIps}" "accept" "ssh"

# Allow RDP for specified ip addr
add-rich-rule "ipv4" "${rdpAcceptedIps}" "accept" "rdp"

# Customize additional firewall rules afterwards
post-extra-rules

let-fw-be-active
