#!/bin/bash
# vim: cindent:shiftwidth=4:tabstop=4:smarttab:textwidth=100

#$title$ Internet Domain Name System (DNS) Reply Size
#$check$ identifies resolvers that cannot receive large DNS replies
#$ref$ RFC6891, https://www.dns-oarc.net/oarc/services/replysizetest
#$author$ Rafal Rzeczkowski
#$version$ 0.7.0

set -o posix
set -o errexit
set -o pipefail
set -o nounset
#set -o xtrace

level_check long

#CHANGELOG
#0.5.0	initial
#0.5.2	desynchronization during "long" cycle
#0.5.3	dig error is presented on standard output
#0.6.0	use Clearcable nameserver for testing
#0.6.1	unify runtime delay randomization
#0.7.0	select UDP message buffer size advertised using EDNS0 explicitly

declare -r -a PROBLEMS=(NO_NAMESERVERS REPLY_TOO_SMALL)
test -n ${#PROBLEMS[@]}

declare -r TARGET_RECORD='syscheck.EDNS0.clearcable.net.'
declare -r EDNS_MAXIMUM_PAYLOAD_SIZE=4096 # RFC6891 6.2.5. Payload Size Selection
declare -r EDNS_EXPECTED_MINIMUM_RESPONSE_SIZE=3920 # without any ADDITIONAL SECTION records
declare -r RANDOMIZATION_MAX=24

unattended_random_delay $RANDOMIZATION_MAX

parent_domain=${TARGET_RECORD#*.}
parent_domain=${parent_domain#*.}
nameservers=($(dig +short -t ns $parent_domain))
if [[ ${#nameservers[@]} -eq 0 ]]; then
	fail caution "no nameservers found for $TARGET_RECORD"
	problem NO_NAMESERVERS $TARGET_RECORD
	exit
fi
nameserver=${nameservers[0]}

echodebug "UDP message buffer size advertised using EDNS0: $EDNS_MAXIMUM_PAYLOAD_SIZE"
echodebug "nameservers for $parent_domain: ${nameservers[@]}"
echodebug "checking $TARGET_RECORD against $nameserver"

declare -i ok_count=0
for AF in 4 6; do
	# verify that the selected address family is functional
	route=$(ip -$AF route show default)
	if [[ -n "$route" ]]; then
		echodebug "AF$AF routing available"
	else
		continue
	fi

	# verify that test server's DNS service is responding
	if dig_output=$(dig @$nameserver 'version.bind' TXT CH -$AF +short +norecurse); then
		echodebug "AF$AF $nameserver software version $dig_output"
	else
		echodebug "$dig_output"
		continue
	fi

	dig_output=$(dig @$nameserver $TARGET_RECORD TXT -$AF +edns=0 +bufsize=$EDNS_MAXIMUM_PAYLOAD_SIZE +norecurse +notcp +ignore)
	msg_size=$(awk '{if ($1==";;" && $2=="MSG" && $3=="SIZE" && $4=="rcvd:"){print $5}}' <<< "$dig_output")
	if [[ $msg_size -gt $EDNS_EXPECTED_MINIMUM_RESPONSE_SIZE ]]; then
		echodebug "AF$AF received EDNS(0) test record of $msg_size bytes from $nameserver via UDP"
		ok_count=$((ok_count+1))
	else
		fail warning "observed UDP message size limit $msg_size is less than the minimum of $EDNS_EXPECTED_MINIMUM_RESPONSE_SIZE expected for $TARGET_RECORD"
		helpmsg "IP path to $nameserver is not clean"
		problem REPLY_TOO_SMALL $msg_size
		exit
	fi
done

if [[ $ok_count -gt 0 ]]; then
	ok
else
	unknown "no connectivity to nameservers of $TARGET_RECORD"
fi
