#!/bin/sh
#
# Spawned by /etc/dhcpcd.exit-hook when a connectivity probe fails.
# Waits for the captive portal to be cleared, then sets unbound as
# the resolver again. Runs as its own process, so trap/EXIT is safe here.

set -u

IFACE=${1:-wlan0}
PIDFILE=/run/captive-portal-poll.pid
INTERVAL=10
MAX_TRIES=90

PROBES="http://connectivity-check.ubuntu.com
	http://cp.cloudflare.com/generate_204
	http://www.gstatic.com/generate_204"

log() {
	logger -t captive-portal-poll -p daemon.info -- "$*"
}

unbound_on() {
	printf 'nameserver 127.0.0.1\n' | resolvconf -a lo.unbound
	# Flush unbound caches to clear any cached SERVFAILs ot NXDOMAINs
	unbound-control flush_zone .
	unbound-control flush_infra all
}

probe() {
	for url in $PROBES; do
		[ "$(curl -s -o /dev/null -w '%{http_code}' \
		    --retry 3 --max-time 3 "$url" 2>/dev/null)" = 204 ] && \
		    return 0
	done
	return 1
}

# Single instance: the hook kills the previous poller before spawning us,
# but claim the pidfile regardless so a stray one is visible.
echo $$ > $PIDFILE
trap 'rm -f "$PIDFILE"' EXIT
trap 'exit 143' TERM
trap 'exit 130' INT

log "started on $IFACE, polling for up to $((MAX_TRIES * INTERVAL))s"

i=0
while [ "$i" -lt "$MAX_TRIES" ]; do
	# Bail out if the link disappeared under us. The hook also kills us
	# on NOCARRIER, but that event is not guaranteed for every teardown.
	if [ "$(cat "/sys/class/net/$IFACE/carrier" 2>/dev/null)" != 1 ]; then
		log "$IFACE carrier lost, giving up"
		break
	fi

	if probe; then
		unbound_on
		log "connectivity confirmed, unbound restored"
		exit 0
	fi

	# wait can be interrupted, so use that
	sleep "$INTERVAL" & wait $!
	i=$((i + 1))
done

# End state is unbound, always. We don't want to stay on the portal's
# resolvers for long, not matter what.
unbound_on
log "gave up after $((i * INTERVAL))s, restored unbound as our resolver"
exit 1
