#!/bin/bash
# called by _USER_ to perform the necessary updation
# perform the process of updating the files in the safesquid folder
# ACTION(s) performed : softlink, mkdir, copy with overwite, copy without overwrite
# OWNERSHIP and PERMISSIONS will also be set

THIS_PROCESS=$BASHPID

shopt -s expand_aliases
trap _CLEANUP `seq 0 15`

if [[ -t 1 ]]; then
	exec 1> >( exec logger --id=${THIS_PROCESS} -s -t "safesquid.setup" ) 2>&1
	CHILD=$!
else
	exec 1> >( exec logger --id=${THIS_PROCESS} -t "safesquid.setup" ) 2>&1
	CHILD=$!
fi

set -o pipefail

CWD=`dirname $0`
IAM=`basename $0`
DIST=""
_USER_="ssquid"
_GROUP_="root"
OWNER="${_USER_}:${_GROUP_}"
let _MONIT_STATUS=1
_MONIT=$(which monit) ; _e=$? ; [ "x${_e}" == "x0"  ] || _MONIT=""  
[ "x${_MONIT}" != "x" ] && ${_MONIT} status && let _MONIT_STATUS=0


[ "x${CWD}" == "x." ] && CWD=`pwd`

PARENT_DIR=`dirname ${CWD}`

LIST=${CWD}"/list.conf";
OLD_FILES=${CWD}"/old.conf";

DATE=`date`;
L=0;



_CLEANUP()
{
	echo "cleaning up"
	[ "x${INIT_PID}" != "x" ] && rm -v "${INIT_PID}"
	DIE
	set -e
	trap 'echo "exiting.. $$";' `seq 0 15`
	kill -15 ${CHILD}  ${THIS_PROCESS}  2>&1 > /dev/null
	exit 0
}

_CLEANUP_()
{
	echo "cleaning up setup"
	set -e
	trap 'echo "exiting.. $$";' `seq 0 15`
	kill ${CHILD} ${THIS_PROCESS}  2>&1 > /dev/null
	exit 0
}

MONIT_CHECK()
{
	let _MONIT_STATUS=1;
	
	_MONIT=$(which monit) || _MONIT="";
	[ "x${_MONIT}" == "x"  ] && return;
	
	${_MONIT} status && let _MONIT_STATUS=0;
	[ "x${_MONIT_STATUS}" != "x0" ] && return;

	echo "Suspending Monit: ${_MONIT_STATUS}"

	${_MONIT} unmonitor all
	return;
}


STOP_SAFESQUID ()
{
	[ ! -f "${CWD}/../etc/init.d/safesquid" ] && return;
	echo "stopping SafeSquid"
	${CWD}/../etc/init.d/safesquid stop;
}

START_SAFESQUID ()
{
	systemctl start safesquid.service && return;
	[ ! -f "${CWD}/../etc/init.d/safesquid" ] && return;
	echo "starting SafeSquid"
	${CWD}/../etc/init.d/safesquid start;
}

MONIT_RESUME()
{
	START_SAFESQUID
	
	echo "monit status: ${_MONIT_STATUS}"
	[ "x${_MONIT_STATUS}" != "x0" ] && return;
	echo "Resuming Monit"
	${_MONIT} reload
	${_MONIT} monitor all
	${_MONIT} validate
	${_MONIT} start all
}


DIE()
{
	MONIT_RESUME
}


WHICH_PLATFORM ()
{
	which aptitude && DIST="DB" && echo "platform: Debian" && return;
	which apt-get && DIST="DB" && echo "platform: Debian" && return;
	which yum && DIST="RH" && echo "platform: Red-Hat" && return;
	DIE "platform: unknown"
}

MAKE_USER_ ()
{
	ID=""; 
	unset GID;
	typeset -a GID;
	unset G; typeset -i G; G=1
	
#	useradd -r ${_USER_} -g ${_GROUP_} --shell ${SHELL}
#	usermod ${_USER_} -g ${_GROUP_}
	
	ID=`id -un ${_USER_}` || DIE 
	GID=( `id -Gn ${_USER_}` ) || DIE 

	for grps in ${GID[*]}
	do
		[ "x${grps}" != "x${_GROUP_}" ] && continue;			
		echo "_USER_ ${_USER_} is a member of _GROUP_ ${_GROUP_}" && G=0 && break;			
	done
	
	[ "x${G}" == "x0" ] && return;
	usermod -aG ${_GROUP_} ${_USER_}
	return;
}

INSTALL_FIRST()
{
	declare -a PACKS
	declare -a _PACKS
	
	PACKS=();
	_PACKS=();
	
	
	PACKS=( `< ${CWD}/system_dependnecies.lst` )
	[[ ${#PACKS[*]} -eq 0 ]] && return;
	
	
	for (( i=0; i < ${#PACKS[*]} ; i++ ))
	do
		pp=${PACKS[i]} 
		apt-cache show ${pp} | grep "Package" && _PACKS+=(${pp})
	done

	export DEBIAN_FRONTEND=noninteractive
	apt-get -q -y --ignore-missing install ${_PACKS[*]}
	apt-get -y autoremove
	apt-get -y autoclean
	export DEBIAN_FRONTEND=
}

INSTALL_SECOND()
{
	declare -a PACKS
	declare -a _PACKS
	
	PACKS=();
	_PACKS=();
	
	LIBS=( `sort ${CWD}/libraries.1st | uniq` )
	[[ ${#LIBS[*]} -eq 0 ]] && return;

	PACKS=( `dpkg -S ${LIBS[*]} | grep -o -aiE "^[^:]*" | sort -rn  | uniq` )
	[[ ${#PACKS[*]} -eq 0 ]] && return;
		
	for (( i=0; i < ${#PACKS[*]} ; i++ ))
	do
		pp=${PACKS[i]} 
		apt-cache show ${pp} | grep "Package" && _PACKS+=(${pp})
	done
	
	export DEBIAN_FRONTEND=noninteractive
	apt-get -q -y --ignore-missing ${_PACKS[*]}
	apt-get -y autoremove
	apt-get -y autoclean
	export DEBIAN_FRONTEND=
	
	return;
	
}

DEBIAN_INSTALLATION()
{	
	apt-get update
	INSTALL_FIRST
	INSTALL_SECOND
}

REDHAT_INSTALLATION()
{	
	PACKS=`< ${CWD}/rh_dependencies.lst`	
	
	if [ "x${PACKS}" != "x" ]; then
		yum install ${PACKS}
	fi
}

INSTALL_PACKAGES()
{	
	[ "x${DIST}" == "x" ] && DIE "platform: unknown"
	[ "x${DIST}" == "xDB" ] && DEBIAN_INSTALLATION && return;
	[ "x${DIST}" == "xRH" ] && REDHAT_INSTALLATION && return;	
}

INSTALL_APPLIANCE ()
{
	find ${PARENT_DIR}/ -name safesquid -type d -exec chown -R ssquid {} \;
	rsync -m -av --exclude "installation" ${PARENT_DIR}/ /
	ln -fs /var/run/safesquid /run/safesquid
}

READ_OLD()
{
	source ${OLD_FILES}
}

REMOVE_OLD()
{
	local i=0
	for (( i=0; i<${#OLD[*]}; i++))
	do
		[ "x${OLD[$i]}" == "x" ] && continue;
		[ ! -e  "${OLD[$i]}" ] && continue;
		rm -f "${OLD[$i]}"	
	done
}


MAKE_NAMED_CONF_APPLIANCE_OPTIONS_FILE()
{
	[ -f /etc/bind/named.conf.appliance.options ] && return;
	cat << _EOF >> /etc/bind/named.conf.appliance.options
allow-new-zones yes;
max-cache-ttl 300;
max-ncache-ttl 300;

auth-nxdomain no;    # conform to RFC1035
dnssec-validation no;
recursion yes;

max-cache-size unlimited;

/*
    clients-per-query / max-clients-per-query are set by default to 10 and 100, respectively. 
	They limit the total number of outstanding clients (requests) for any single query. 
	In the worst case, there can be 100 outstanding requests.

    recursive-clients is configured by default to 1000. 
	This limits the total number of outstanding requests. 
	After reaching 90% of this limit (i.e. 900 requests by default), 
		the oldest requests are dropped and can no longer contribute 
		to the effectiveness of this attack.

    responses-per-second is a rate limit which can be configured to further mitigate this attack. 
	It limits the number of UDP responses for a particular query per network segment.
*/

	listen-on-v6 { ::1; };
//  listen-on { 127.0.0.1; };
	listen-on { any; };

clients-per-query 50000;
max-clients-per-query 50000;
tcp-clients 50000;
recursive-clients 50000;
fetches-per-server 50000;
rrset-order {
	order cyclic;
};

rate-limit {
	 responses-per-second 0;
};


// forwarders {
//      0.0.0.0;
// };


_EOF

}

MAKE_IPV6_DISABLE_CONF_FILE ()
{
	[ -f /etc/bind/ipv6_disable.conf ] && return;

	cat << _EOF >> /etc/bind/ipv6_disable.conf
	plugin query "filter-aaaa.so" {
		filter-aaaa-on-v4 yes;
		filter-aaaa-on-v6 yes;
		filter-aaaa { any; };
	};
_EOF

}

MAKE_RNDC_ENABLE_CONF_FILE()
{
	[ -f /etc/bind/rndc_enable.conf ] && return;

	cat << _EOF >> /etc/bind/rndc_enable.conf
	include "/etc/bind/rndc.key";
	controls {
		inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; };
	};
_EOF

}

MAKE_RNDC_KEY_FILE()
{
	[ -f /etc/bind/rndc.key ] && return;	
	rndc-confgen -a -c /etc/bind/rndc.key
}


ADD_IPV6_DISABLE()
{
	grep "/etc/bind/ipv6_disable.conf" /etc/bind/named.conf && return;
	cat <<- _EOF >> /etc/bind/named.conf
	include "/etc/bind/ipv6_disable.conf";
	_EOF

}

ADD_RNDC_KEY_ENABLE()
{
	grep "/etc/bind/rndc_enable.conf" /etc/bind/named.conf && return;
	cat <<- _EOF >> /etc/bind/named.conf
	include "/etc/bind/rndc_enable.conf";
	_EOF

}

ADD_DNSBL_CONF()
{
	grep "/etc/bind/dnsbl.conf" /etc/bind/named.conf && return;
	cat <<- _EOF >> /etc/bind/named.conf
	include "/etc/bind/dnsbl.conf";
	_EOF
	
	cat <<- _EOF >> /etc/bind/dnsbl.conf
	zone "in.dnsbl.org" {
		type forward;
		forward only;
		forwarders { 127.0.0.1 port 532; };
	};

	_EOF

}


RBLDNSD_SOCKET_CONF()
{
	[ -f "/etc/systemd/system/rbldnsd.socket.d/override.conf" ] && return;
	
	[ ! -d "/etc/systemd/system/rbldnsd.socket.d/" ] && mkdir -p "/etc/systemd/system/rbldnsd.socket.d/"
	
	cat <<- _EOF >> /etc/systemd/system/rbldnsd.socket.d/override.conf
[Socket]
# An empty ListenDatagram clears out the default port 53 bindings
ListenDatagram=
# Bind strictly to localhost on your proxy-facing port
ListenDatagram=127.0.0.1/532

	_EOF
	
	systemctl restart rbldnsd.socket	
}

SETUP_RBLDNSD()
{
	grep "DNSBL SETUP" /etc/default/rbldnsd && return;
	cat <<- _EOF >> /etc/default/rbldnsd
	# Set the base parameters first
	# DNSBL SETUP

RBLDNSD="- -r /var/lib/rbldns"
RBLDNSD="\$RBLDNSD -b 127.0.0.1/532"
RBLDNSD="\$RBLDNSD in.dnsbl.org:dnset:domains.blacklist"
RBLDNSD="\$RBLDNSD in.dnsbl.org:ip4trie:ips.blacklist"

	_EOF

}


MAKE_DNSBL_DOMAIN_TEMPLATE()
{
	[ -f "/var/lib/rbldns/domains.blacklist" ] && return;
	
	cat <<- _EOF >> /var/lib/rbldns/domains.blacklist
	\$SOA 3000 ns1.in.dnsbl.org admin.in.dnsbl.org 0 600 300 86400 300
	\$NS 3000 ns1.in.dnsbl.org
	
	 #return 1.2.3.4 for unlisted domains
	* :1.2.3.4:Domain is not listed

	# return 127.0.0.2 for blacklisted sites
	:127.0.0.2:Domain is blacklisted
	badsite.com
	evilsite.net 
_EOF
	
}



MAKE_DNSBL_IP_TEMPLATE()
{
	[ -f "/var/lib/rbldns/ips.blacklist" ] && return;
	
	cat <<- _EOF >> /var/lib/rbldns/ips.blacklist
	# return 1.2.3.4 for unlisted IPs
	0.0.0.0/0 :1.2.3.4:IP is not listed

	# Default return payload for listed IPs
	:127.0.0.3:IP is blocked due to abuse

	# 1. Individual IPv4 addresses
	203.0.113.5
	198.51.100.42

	# 2. Entire subnets (CIDR notation) - blocks all 256 IPs at once
	192.0.2.0/24

	# 3. Custom return IP for a specific block
	185.0.0.0/8 :127.0.0.3:Known bulletproof hosting range

	_EOF
	
}


APPEND_NAMED_DEFAULT()
{
	grep "disable ipv6" /etc/default/named && return;
	cat <<- _EOF >> /etc/default/named
	#disable ipv6
	OPTIONS="-4 -u bind" 
	_EOF

}

ADD_NAMED_CONF_APPLIANCE_OPTIONS()
{
	grep "/etc/bind/named.conf.appliance.options" /etc/bind/named.conf.options && return;

	sed -i '/^options {/,/^};/ s|^options {|&\n\tinclude "/etc/bind/named.conf.appliance.options";|' /etc/bind/named.conf.options

}


FIX_BIND9()
{
	MAKE_NAMED_CONF_APPLIANCE_OPTIONS_FILE
	MAKE_IPV6_DISABLE_CONF_FILE
	MAKE_RNDC_KEY_FILE
	MAKE_RNDC_ENABLE_CONF_FILE
	ADD_NAMED_CONF_APPLIANCE_OPTIONS
	ADD_DNSBL_CONF
	ADD_IPV6_DISABLE
	APPEND_NAMED_DEFAULT
	ADD_RNDC_KEY_ENABLE
	systemctl restart named
	systemctl enable --now named-resolvconf.service
	systemctl start named-resolvconf.service

}


MAIN()
{
	MONIT_CHECK
	WHICH_PLATFORM
	MAKE_USER_
	READ_OLD
	REMOVE_OLD
	INSTALL_PACKAGES
	STOP_SAFESQUID
	FIX_BIND9
	INSTALL_APPLIANCE
	SETUP_RBLDNSD
	MAKE_DNSBL_DOMAIN_TEMPLATE
	MAKE_DNSBL_IP_TEMPLATE
	RBLDNSD_SOCKET_CONF	
	
	update-rc.d safesquid enable
	systemctl enable --now safesquid
	systemctl daemon-reload
	
	return;
}

#MAIN | LOGGER
MAIN 
# DIE
echo "All Done!"
exit 0

:<< _EOF
MAIN |& tee -a ${echoF};
chown ${OWNER} ${echoF}
DIE
echo "All Done!"
_EOF