#!/bin/bash
# lawleyos-dns - turn system-wide encrypted DNS (DNS-over-TLS via
# systemd-resolved) on or off. Run as root (LawleyOS Portal uses pkexec).
#   lawleyos-dns status
#   lawleyos-dns set quad9|cloudflare|mullvad
#   lawleyos-dns off
# Only the fixed providers below are accepted. If lookups fail after a
# change, the previous configuration is restored automatically.
set -u

CONF_DIR=/etc/systemd/resolved.conf.d
CONF=$CONF_DIR/90-lawleyos-encrypted-dns.conf

servers_for() {
    case "$1" in
        quad9)      echo "9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net" ;;
        cloudflare) echo "1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com 2606:4700:4700::1111#cloudflare-dns.com 2606:4700:4700::1001#cloudflare-dns.com" ;;
        mullvad)    echo "194.242.2.2#dns.mullvad.net 2a07:e340::2#dns.mullvad.net" ;;
        *)          return 1 ;;
    esac
}

current() {
    [ -f "$CONF" ] && sed -n 's/^# provider: //p' "$CONF" | head -1 || echo off
}

apply_and_verify() {
    systemctl restart systemd-resolved || return 1
    resolvectl flush-caches 2>/dev/null
    # give resolved a moment to bring up TLS, then check real lookups work
    for _ in 1 2 3 4 5; do
        if timeout 5 resolvectl query --cache=no lawleyos.com >/dev/null 2>&1 ||
           timeout 5 resolvectl query --cache=no debian.org >/dev/null 2>&1; then
            return 0
        fi
        sleep 1
    done
    return 1
}

need_root() {
    [ "$(id -u)" -eq 0 ] || { echo "lawleyos-dns: must be run as root" >&2; exit 1; }
}

case "${1:-}" in
    status)
        echo "$(current)"
        ;;
    set|off)
        need_root
        if [ "$1" = set ]; then
            provider="${2:-}"
            servers=$(servers_for "$provider") || { echo "lawleyos-dns: unknown provider '$provider'" >&2; exit 2; }
        fi
        backup=$(mktemp)
        had_conf=0
        [ -f "$CONF" ] && { cp -p "$CONF" "$backup"; had_conf=1; }

        if [ "$1" = set ]; then
            mkdir -p "$CONF_DIR"
            cat > "$CONF.tmp" <<EOF
# Managed by LawleyOS Portal (lawleyos-dns). Remove this file to undo.
# provider: $provider
[Resolve]
DNS=$servers
DNSOverTLS=yes
Domains=~.
EOF
            chmod 644 "$CONF.tmp" && mv -f "$CONF.tmp" "$CONF"
        else
            rm -f "$CONF"
        fi

        if apply_and_verify; then
            rm -f "$backup"
            echo "ok: $(current)"
        else
            # roll back so the computer isn't left without working DNS
            if [ "$had_conf" = 1 ]; then cp -p "$backup" "$CONF"; else rm -f "$CONF"; fi
            rm -f "$backup"
            systemctl restart systemd-resolved
            echo "lawleyos-dns: DNS lookups failed with that setting; previous setting restored" >&2
            exit 3
        fi
        ;;
    *)
        echo "usage: lawleyos-dns status | set quad9|cloudflare|mullvad | off" >&2
        exit 2
        ;;
esac
