1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
#!/bin/bash
# This is an example DNS hook script which uses the nsupdate utility to update
# nameservers. The script waits until updates have propagated to all
# nameservers listed for a zone. The script fails if this takes more than 60
# seconds by default; this timeout can be adjusted.
#
# The script is ready to use, but to use it you must create
# /etc/default/acme-dns or /etc/conf.d/acme-dns and set the following options:
#
# # Needed if using TSIG for updates. If authenticating updates by source IP,
# # not necessary.
# TSIG_KEY_NAME="hmac-sha256:tk1"
# TSIG_KEY="a base64-encoded TSIG key"
#
# # DNS synchronization timeout in seconds. Default is 60.
# DNS_SYNC_TIMEOUT=60
#
# # Optional: inject extra arguments and commands to nsupdate.
# NSUPDATE_ARGS="-v"
# nsupdate_cmds() {
# # Usually not necessary:
# echo zone example.com.
# }
#
# Having done this, rename it to /usr/lib[exec]/acme/hooks/dns.
#
# How to test this script:
# ./dns.hook challenge-dns-start example.com "" "foobar"
# ./dns.hook challenge-dns-stop example.com "" "foobar"
#
set -e
get_apex() {
local name="$1"
if [ -z "$name" ]; then
echo "$0: couldn't get apex for $name" >&2
return 1
fi
local ans="`dig +noall +answer SOA "${name}."`"
if [ "`echo "$ans" | grep SOA | wc -l`" == "1" -a "`echo "$ans" | grep CNAME | wc -l`" == "0" ]; then
APEX="$name"
return
fi
local sname="$(echo $name | sed 's/^[^.]\+\.//')"
get_apex "$sname"
}
waitns() {
local ns="$1"
for ctr in $(seq 1 "$DNS_SYNC_TIMEOUT"); do
[ "$(dig +short "@${ns}" TXT "_acme-challenge.${CH_HOSTNAME}." | grep -- "$CH_TXT_VALUE" | wc -l)" == "1" ] && return 0
sleep 1
done
# Best effort cleanup.
echo $0: timed out waiting ${DNS_SYNC_TIMEOUT}s for nameserver $ns >&2
updns delete || echo $0: failed to clean up records after timing out >&2
return 1
}
updns() {
local op="$1"
(
declare -f nsupdate_cmds >/dev/null && nsupdate_cmds "$APEX"
[ -n "$TSIG_KEY" ] && echo key "$TSIG_KEY_NAME" "$TSIG_KEY"
echo update $op "_acme-challenge.${CH_HOSTNAME}." 60 IN TXT "\"${CH_TXT_VALUE}\""
echo send
) | nsupdate $NSUPDATE_ARGS
}
[ -e "/etc/default/acme-dns" ] && . /etc/default/acme-dns
[ -e "/etc/conf.d/acme-dns" ] && . /etc/conf.d/acme-dns
# e.g.
# TSIG_KEY_NAME="hmac-sha256:tk1"
# TSIG_KEY="base64-key-value"
EVENT_NAME="$1"
CH_HOSTNAME="$2"
CH_TARGET_FILENAME="$3"
CH_TXT_VALUE="$4"
[ -z "$DNS_SYNC_TIMEOUT" ] && DNS_SYNC_TIMEOUT=60
# Older versions of this script used TKIP_KEY{,_NAME} instead of
# TSIG_KEY{,_NAME}. Brainfart — TKIP is part of Wi-Fi's WPA2 and has nothing to
# do with DNS's TSIG. Support the old naming.
if [ -n "$TKIP_KEY" ]; then
TSIG_KEY="$TKIP_KEY"
fi
if [ -n "$TKIP_KEY_NAME" ]; then
TSIG_KEY_NAME="$TKIP_KEY_NAME"
fi
case "$EVENT_NAME" in
challenge-dns-start)
get_apex "$CH_HOSTNAME"
updns add
# Wait for all nameservers to update.
for ns in $(dig +short NS "${APEX}."); do
waitns "$ns"
done
;;
challenge-dns-stop)
get_apex "$CH_HOSTNAME"
updns delete
;;
*)
exit 42
;;
esac
|