#!/bin/sh
# La prova vera del DNS dei televisori sul router: una domanda a ciascuna delle
# tre istanze e la sua risposta, non «il servizio è su» e non «c'è un socket».
# Stessa forma di velmo-guardia-dns.j2 di main (nomi, soglia, intervallo, riga
# «data<TAB>dns<TAB>testo» nel registro eventi), con due differenze del ramo:
# la domanda la fa velmo-guardiano -prova-dns, perché sul router python non c'è
# (spec §14.9), e un'istanza si riavvia uccidendo il suo processo, che procd
# rimette su.
#
# Ogni istanza si prova due volte:
#
#   1. un nome che l'istanza risolve da sé (velmo.lan -> 10.42.0.1): dice che
#      risponde, e senza uscire su internet - una domanda verso un nome
#      qualunque misurerebbe il resolver di casa e farebbe riavviare un dnsmasq
#      sano ogni volta che è la rete di casa a perdere le risposte.
#   2. un nome che la sua lista deve fermare, e la risposta dev'essere 0.0.0.0:
#      protetta e leggibile il primo nome del filtro del blocco, aggressiva un
#      nome che nessuna whitelist può contenere. Questa seconda domanda nasce
#      dalla fuga del 16 settembre 2026: l'istanza protetta ha risposto con gli
#      indirizzi veri a infinity-c32.youboranqs01.com, che il suo filtro blocca,
#      e dallo stato del servizio non si vedeva niente. Se in protetta il blocco
#      non vale, la modalità protetta è finta e l'utente non lo sa.
#
#   velmo-guardia-dns              una passata (dal ciclo di velmo-guardia, ogni minuto):
#                                  dopo SOGLIA passate fallite di fila riavvia l'istanza,
#                                  al massimo una ogni INTERVALLO secondi, e lo annota
#   velmo-guardia-dns --verifica   prova ogni istanza, riavvia quelle che non rispondono
#                                  e riprova; esce 1 se una non risponde nemmeno dopo
#   velmo-guardia-dns --mostra     prova e stampa, senza riavviare niente e senza contare
set -u
. /etc/velmo/router.conf
CARTELLA=${CARTELLA:-/tmp/velmo-dns}
FILTRI=${FILTRI:-/etc/velmo/dns}
EVENTI=${EVENTI:-$VELMO_DATI/eventi.log}
STATO_DIR=${STATO_DIR:-/var/run/velmo/guardia-dns}
GUARDIANO=${GUARDIANO:-/usr/sbin/velmo-guardiano}
SOGLIA=${SOGLIA:-2}
INTERVALLO=${INTERVALLO:-300}
ATTESA=${ATTESA:-1}
# istanza:porta, nell'ordine in cui partono.
ISTANZE=${ISTANZE:-"leggibile:$VELMO_DNS_LEGGIBILE protetta:$VELMO_DNS_PROTETTA aggressiva:$VELMO_DNS_AGGRESSIVA"}
# Il nome che ogni istanza risolve da sé, e la risposta attesa.
NOME=${NOME:-$VELMO_BACHECA_NOME}
ATTESO=${ATTESO:-$VELMO_INDIRIZZO}
# Il nome che nessuna whitelist dell'aggressiva può contenere: «.invalid» non
# esiste e non si può ammettere.
NOME_FERMATO_AGGRESSIVA=${NOME_FERMATO_AGGRESSIVA:-prova-guardia.invalid}

annota() { printf '%s\tdns\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$1" >> "$EVENTI" 2>/dev/null; logger -t velmo-guardia-dns "$1"; }

# Il primo nome del filtro del blocco: la lista cambia, la guardia no.
nome_fermato() { # istanza
	[ "$1" = aggressiva ] && { echo "$NOME_FERMATO_AGGRESSIVA"; return; }
	sed -n 's,^address=/\([^/]*\)/0\.0\.0\.0$,\1,p' "$FILTRI/protetta.d/velmo-blocco.conf" 2>/dev/null | head -1
}

# chiedi porta nome atteso -> 0 risposta attesa, 1 muta, 2 risposta diversa
chiedi() {
	"$GUARDIANO" -prova-dns -dns-indirizzo "$VELMO_INDIRIZZO" -dns-porta "$1" \
		-dns-nome "$2" -dns-atteso "$3" -dns-attesa "${ATTESA}s"
}

# prova istanza porta: scrive cosa non va e torna 0 se è tutto a posto.
prova() { # istanza porta
	riga=$(chiedi "$2" "$NOME" "$ATTESO"); codice=$?
	[ $codice -eq 1 ] && { echo "$1 non risponde"; return 1; }
	[ $codice -ne 0 ] && { echo "$1 risponde male a $NOME: ${riga#*: }"; return 1; }
	fermato=$(nome_fermato "$1")
	[ -n "$fermato" ] || return 0
	# Se non risponde a questa è muta come sopra; se risponde con un indirizzo
	# vero il blocco della sua modalità non è in vigore.
	riga=$(chiedi "$2" "$fermato" 0.0.0.0); codice=$?
	[ $codice -eq 1 ] && { echo "$1 non risponde"; return 1; }
	[ $codice -ne 0 ] && { echo "$1 non ferma $fermato: ${riga#*: }"; return 1; }
	return 0
}

riavvia() { # istanza
	pid=$(cat "$CARTELLA/$1.pid" 2>/dev/null)
	[ -n "$pid" ] && kill "$pid" 2>/dev/null && return 0
	/etc/init.d/velmo-dns restart >/dev/null 2>&1
}

mkdir -p "$STATO_DIR"
uscita=0
for coppia in $ISTANZE; do
	n=${coppia%%:*}; p=${coppia##*:}
	guaio=$(prova "$n" "$p") && { rm -f "$STATO_DIR/$n"; continue; }
	case "${1:-}" in
	--mostra)
		echo "$guaio"; uscita=1; continue ;;
	--verifica)
		annota "$guaio: riavvio l'istanza e riprovo"
		riavvia "$n"
		giro=0
		while [ $giro -lt 10 ]; do sleep 1; giro=$((giro + 1)); prova "$n" "$p" >/dev/null && break; done
		if guaio=$(prova "$n" "$p"); then rm -f "$STATO_DIR/$n"; continue; fi
		annota "$guaio: non risponde nemmeno dopo il riavvio"
		uscita=1 ;;
	*)
		conta=$(cat "$STATO_DIR/$n" 2>/dev/null); conta=$((${conta:-0} + 1))
		echo "$conta" > "$STATO_DIR/$n"
		uscita=1
		[ "$conta" -lt "$SOGLIA" ] && { annota "$guaio (passata $conta)"; continue; }
		ultimo=$(cat "$STATO_DIR/$n.riavvio" 2>/dev/null)
		adesso=$(date +%s)
		if [ -n "$ultimo" ] && [ $((adesso - ultimo)) -lt "$INTERVALLO" ]; then
			annota "$guaio: riavviata da poco, aspetto"
			continue
		fi
		annota "$guaio: riavvio l'istanza"
		echo "$adesso" > "$STATO_DIR/$n.riavvio"
		riavvia "$n"
		rm -f "$STATO_DIR/$n" ;;
	esac
done
exit $uscita
