#!/bin/bash

# Install FIB rules for DNS servers

# priority of FIB rules. Needs to be before (lower prio)
# VRF rules
PRIO=99

PROG=${0##*/}
VERBOSE=0

################################################################################
# logging

function log_cmd
{
	if [ $VERBOSE -eq 1 ]; then
		echo "${PROG}: $*"
	fi
}

################################################################################
# TO-DO: distinguish IPv4 and IPv6 DNS

function configure_dns_server
{
	local dns=$1
	local table=$2

	# does rule already exist?
	# TO-DO: table arg is a number, 'ip ru' always converts
	#        to text if an id to name exists
	ip ru ls | grep -q "from all to ${dns} lookup "
	[ $? -eq 0 ] && return 0

	log_cmd "ip rule add to ${dns} prio ${PRIO}"
	ip rule add to ${dns} lookup ${table} prio ${PRIO}
}

function remove_dns_server
{
	local dns=$1
	local table=$2

	# simpler to just do remove command and not worry about ENOENT error
	log_cmd "ip rule del to ${dns} lookup ${table} prio ${PRIO}"
	ip rule del to ${dns} lookup ${table} prio ${PRIO} 2>/dev/null

	return 0
}

function verify_dns_server
{
	local dns=$1
	local table=$2

	echo

	grep -q "from all to ${dns} lookup ${table}" ${IPRUFILE}
	if [ $? -eq 0 ]; then
		echo "Rule for dns server ${dns} exists with table ${table}"
		sed -ie "/from all to ${dns} lookup ${table}/d" ${IPRUFILE}
		return 0
	fi

	grep -q "from all to ${dns} lookup " ${IPRUFILE}
	if [ $? -eq 0 ]; then
		echo "Rule for dns server ${dns} exists but table match failed"
		sed -ie "/from all to ${dns} lookup /d" ${IPRUFILE}
		return 0
	fi

	echo "No FIB rule for dns server ${dns}"
	return 0
}

################################################################################
#

function vrf_delete
{
	local vrf=$1
	local mgmt

	# For now only going to install DNS rules for management VRF
	mgmt=$(mgmt-vrf name)
	[ "$vrf" != "$mgmt" ] && return 0

	# since we are only handling mgmt VRF could delete all rules with
	# our priority which handles DNS changes between VRF create & delete
	while read ns ip tmp
	do
		[ "$ns" != "nameserver" ] && continue
		# simpler to just do remove command and not worry about
		# ENOENT error
		log_cmd "ip rule del to ${dns} prio ${PRIO}"
		ip rule del to ${dns} prio ${PRIO} 2>/dev/null
	done < /etc/resolv.conf
}

function vrf_create
{
	local vrf=$1
	local tbid=$2
	local mgmt

	if [ -z "$tbid" ]; then
		return 1
	fi

	# For now only going to install DNS rules for management VRF
	mgmt=$(mgmt-vrf name)
	[ "$vrf" != "$mgmt" ] && return 0

	while read ns ip tmp
	do
		[ "$ns" != "nameserver" ] && continue
		configure_dns_server $ip $tbid
	done < /etc/resolv.conf
}

function vrf_verify_one
{
	local vrf=$1
	local tbid=$2

	while read ns ip tmp
	do
		[ "$ns" != "nameserver" ] && continue
		verify_dns_server ${ip} ${tbid} ${IPRUFILE}
	done < /etc/resolv.conf
}

function vrf_verify_all
{
	local mgmt_name=$(mgmt-vrf name)

	vrf_verify_one "$mgmt_name" "$mgmt_name"

	if [ -s ${IPRUFILE} ]; then
		echo
		echo "Extra FIB rules exist at DNS priority:"
		cat ${IPRUFILE}
	fi
}

function vrf_verify
{
	local vrf=$1
	local tbid=$2
	local rc=0

	# For now only dealing with Management VRF
	mgmt-vrf status
	[ $? -ne 0 ] && return 0

	# get a cache of DNS entries
	IPRUFILE=$(mktemp /tmp/vrf.XXXXXXXX)
	ip ru ls | egrep "^${PRIO}:" >> ${IPRUFILE}

	if [ -z "$vrf" ]; then
		vrf_verify_all
		rc=$?
	else
		# ip rules have converted id to name
		# TO-DO: add option to ip to not do that
		vrf_verify_one ${vrf} "$(mgmt-vrf name)"
		rc=$?
	fi

	rm -f ${IPRUFILE}
}

################################################################################
# main

# enable verbose logging?
if [ "$1" = "-v" ]; then
	VERBOSE=1
	shift
fi

ACTION=$1
shift
case "$ACTION" in
	dns_add) configure_dns_server $*;;
	dns_del) remove_dns_server $*;;
	create)  vrf_create $*;;
	delete)  vrf_delete $*;;
	verify)  vrf_verify $*;;
	*) exit 1;;
esac
