# Shared zone-loading + recursive-forwarding config.
# CoreDNS snippets are textually expanded by `import`, so we keep anything
# that's not transport-specific (TLS) in here.
(common) {
    auto {
        directory /zones (.*)\.zone {1}
        reload 30s
    }

    # AXFR authorization is `to *` at this layer, with HE-only filtering
    # done by the FortiWiFi firewall (source IP restriction on the
    # TCP/53 DNAT rule). Reasons we don't filter at CoreDNS:
    #
    #  1. CoreDNS plugin quirk: `to <specific-IP>` (any form — single,
    #     multi-line, space-separated) silently fails to start server
    #     blocks. Reproduced on 1.11.3 and 1.12.2. Only `to *` works.
    #  2. Docker port publishing with userland-proxy rewrites source
    #     IPs to the bridge gateway, so IP filtering wouldn't see HE's
    #     real address anyway (without network_mode: host).
    #  3. Filtering at the perimeter (FortiWiFi) is correct-layered
    #     defense: bad packets don't reach the host at all.
    #
    # Required FortiWiFi rule:
    #   VIP "coredns-tcp" — src in {216.218.130.2, 216.218.131.2,
    #     216.218.132.2, 216.218.133.2, 216.66.1.2} —
    #     dst WAN:53/tcp → 172.16.1.15:5353/tcp
    transfer {
        to *
    }

    forward . 1.1.1.1 1.0.0.1 9.9.9.9 {
        max_concurrent 1000
    }
    cache 30
    errors
    log
    loop
    reload 10s
}

# Plain DNS — UDP/TCP :53. Health + metrics live here only (one binding).
. {
    import common
    health :8080
    prometheus :9153
}

# DNS-over-TLS — RFC 7858. Port 853 is the IANA-assigned DoT port.
tls://.:853 {
    tls /etc/coredns/certs/cert.pem /etc/coredns/certs/key.pem
    import common
}

# DNS-over-HTTPS — RFC 8484. Default path is /dns-query.
# Clients: curl -H 'accept: application/dns-message' https://host:8443/dns-query?dns=...
https://.:443 {
    tls /etc/coredns/certs/cert.pem /etc/coredns/certs/key.pem
    import common
}
