diff options
| author | Lexi Winter <ivy@FreeBSD.org> | 2025-06-04 08:51:26 +0100 |
|---|---|---|
| committer | Lexi Winter <ivy@FreeBSD.org> | 2025-06-04 08:51:26 +0100 |
| commit | 63f6a3181fea59360b2bfe430f5c798f88b22527 (patch) | |
| tree | a9f5471dfdc5478a5b337854660773e3bea861b4 /dnsutils.sh | |
| parent | 7284f9864fad4432b6a6e641c03adee321148107 (diff) | |
| download | lfacme-63f6a3181fea59360b2bfe430f5c798f88b22527.tar.gz lfacme-63f6a3181fea59360b2bfe430f5c798f88b22527.tar.bz2 | |
add a TSIG-based dns validation handler
while here, reorganise and improve documentation a bit.
Diffstat (limited to 'dnsutils.sh')
| -rw-r--r-- | dnsutils.sh | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/dnsutils.sh b/dnsutils.sh new file mode 100644 index 0000000..a1523ff --- /dev/null +++ b/dnsutils.sh @@ -0,0 +1,84 @@ +# This source code is released into the public domain. +# +# Utility functions for DNS-based authorizations. + +# Retrieve the nameservers for a given domain. On failure, prints an error +# message and exits. +lfacme_dns_getnameservers() { + local domain="$1" + + # Keep removing labels from the name until we find one with nameservers. + local _trydomain="$domain" + while ! [ -z "$_trydomain" ]; do + if [ "$_trydomain" = "${_trydomain#*.}" ]; then + # If there are no dots in the domain, we couldn't + # find the nameservers. + break + fi + + # For CNAME records, a query for NS will return the CNAME. + # Therefore we have to check we actually got NS records. + local nameservers="$( + dig "$_trydomain" ns +noall +answer | \ + awk '$4 == "NS" { print $5 }' + )" + + if ! [ -z "$nameservers" ]; then + echo "$nameservers" + return + fi + + _trydomain="${_trydomain#*.}" + done + + _fatal "unable to find nameservers for %s" "$_trydomain" +} + +# Wait for the DNS record to appear on a specific nameserver. +lfacme_dns_wait_for_nameserver() { + local domain="$1" + local auth="$2" + local nameserver="$3" + + _verbose "waiting for nameserver %s" "$nameserver" + + local waited=0 + local waitlimit=60 + while sleep 1; do + waited=$((waited + 1)) + if [ "$waited" -ge "$waitlimit" ]; then + _error "timed out waiting for '%s' on '%s'" \ + "$domain" "$nameserver" + return 1 + fi + + local _rdatas="$( + dig "_acme-challenge.$domain" txt @$nameserver \ + +noall +answer \ + | awk '$4 == "TXT" { print $5 }' + )" + for rdata in $_rdatas; do + if [ "$rdata" = "\"$auth\"" ]; then + return 0 + fi + done + done +} + +# Wait for DNS servers to have the given record. +lfacme_dns_wait_for_record() { + local domain="$1" + local auth="$2" + local nameservers="$(lfacme_dns_getnameservers "$domain")" + + _verbose "waiting for the DNS record '%s' to be published" "$domain" + for ns in $nameservers; do + if ! lfacme_dns_wait_for_nameserver "$domain" "$auth" "$ns"; then + return 1 + fi + done + + return 0 +} + + |
