#!/bin/sh


to_subnet() {
	pref=$1
	case "$pref" in
	*.*.*.*) echo $pref/32;;
	*.*.*) echo $pref.0/24;;
	*.*) echo $pref.0.0/16;;
	*) echo $pref.0.0.0/8;;
	esac
}

gen_config() {
	echo "# Config generated by $0, $(date)"
	echo "server:"
	echo -e "\troot-hints: /etc/unbound/root.hints\n"

	[ -n "$IP" ] && echo -e "\tinterface: $IP\n"
	[ -n "$IPSEND" ] && echo -e "\toutgoing-interface: $IPSEND\n"

	for i in $access_control; do
		echo -e "\taccess-control: $i allow"
	done
	echo ""

	# stub zones
	local zonefile ip
	local fwdtype="stub"
	if [ -n "$FORWARDONLY" ]; then
		fwdtype="forward"
	fi
	for zonefile in "$root"/etc/dnscache/servers/*; do
		local zone=${zonefile##*/}
		case "$zone" in
			'@'|'*'|*.apk-new) continue;;
		esac
		echo "${fwdtype}-zone:"
		echo -e "\tname: ${zone}"
		for ip in $(cat $zonefile); do
			echo -e "\t${fwdtype}-addr: $ip"
		done
		echo ""
	done
}

usage() {
	cat >&2 <<EOF
usage: $0 [-h] [-r ROOT]
Migrate dnscache configuration to unbound

This tool will install unbound, migrate the configuration, stop dnscache
and start unbound and remove traces of dnscache.

Options:
 -c  Only dump the config to stdout and exit
 -h  Show this help
 -k  Keep unbound.conf.backup and keep dnscache config
 -r  Look for dnscache config in ROOT/etc/dnscache

EOF
}

root=${ROOT:-/}
dump_config=false
quiet=false
keep_backup=false
while getopts "chr:" opt; do
	case "$opt" in
	'c') dump_config=true;;
	'h') usage; exit;;
	'k') keep_backup=true;;
	'r') root="$OPTARG";;
	'q') quiet=true; quiet_opt=--quiet;;
	esac
done
unbound_conf=${UNBOUND_CONF:-${root%/}/etc/unbound/unbound.conf}

# read dnscache config
if ! [ -f "$root"/etc/conf.d/dnscache ] && ! [ -d "$root"/etc/dnscache ]; then
	echo "No dnscache config found"
	exit 1
fi

confd="$root"/etc/conf.d/dnscache
if [ -r "$confd" ]; then
	. "$confd"
fi

interface="$IP"
outgoing_interface="$IPSEND"

for i in "$root"/etc/dnscache/ip/*; do
	[ -f "$i" ] || continue
	access_control="$access_control $(to_subnet ${i##*/})"
done

if $dump_config; then
	gen_config
	exit 0
fi

# install unbound if needed
if ! apk info -e unbound; then
	apk add $quiet_opt unbound
fi

# generate config
if [ -f "$unbound_conf" ]; then
	$quiet || echo "Backing up $unbound_conf" >&2
	mv "$unbound_conf" "${unbound_conf}".backup
fi

$quiet || echo "Generating $unbound_conf" >&2
gen_config > "$unbound_conf"

# stop dnscache and start unbound
if /etc/init.d/dnscache --quiet status 2>/dev/null; then
	/etc/init.d/dnscache $quiet_opt stop
	if ! /etc/init.d/unbound $quiet_opt start; then
		echo "Failed to start unbound. Starting up dnscache again"
		/etc/init.d/dnscache $quiet_opt start
		exit 1
	fi
fi

# update runlevels
errors=0
if rc-update | grep -q -w dnscache; then
	runlevels=$(rc-update | awk '$1 == "dnscache" { FS="|"; $0 = $0; print $2 }')
	for level in $runlevels; do
		rc-update $quiet_opt add unbound $level \
			|| errors=$(($errors + 1))
		rc-update $quiet_opt del dnscache $level \
			|| errors=$(($errors + 1))
	done
fi

# cleanup if requested
if [ $errors -eq 0 ] && ! $keep_backup ; then
	$quiet || echo "Purging dnscache and dnscache config" >&2
	apk del --purge $quiet_opt dnscache
	rm -rf $root/etc/dnscache $root/etc/conf.d/dnscache
	$quiet || echo "Purging ${unbound_conf}.backup" >&2
	rm -rf ${unbound_conf}.backup
fi

exit $errors