#!/usr/bin/env bash fulldomain="${1}" token="${2}" api_url="${PDNS_API_URL:-}" api_key="${PDNS_API_KEY:-}" server_id="${PDNS_SERVER_ID:-localhost}" ttl="${PDNS_TTL:-120}" if [[ -z "$fulldomain" ]]; then echo "DNS script requires full domain name as first parameter" exit 1 fi if [[ -z "$token" ]]; then echo "DNS script requires challenge token as second parameter" exit 1 fi if [[ -z "$api_url" ]]; then echo "PDNS_API_URL variable not set" exit 1 fi if [[ -z "$api_key" ]]; then echo "PDNS_API_KEY variable not set" exit 1 fi if ! command -v jq >/dev/null 2>&1; then echo "jq command not found" exit 1 fi api_get() { curl --silent -X GET "${1}" \ -H "X-API-Key: ${api_key}" } find_zone() { local domain="${1}" local candidate="${domain}" while [[ "${candidate}" == *"."* ]]; do response=$(curl --silent "${api_url%/}/api/v1/servers/${server_id}/zones/${candidate}." \ -H "X-API-Key: ${api_key}" \ -o /dev/null \ -w '%{http_code}') if [[ "$response" == "200" ]]; then printf '%s.\n' "${candidate}" return 0 fi candidate="$(echo "${candidate}" | cut -d. -f1 --complement)" done return 1 } zone_name=$(find_zone "$fulldomain") if [[ -z "$zone_name" ]]; then echo "Cannot find matching PowerDNS zone" exit 1 fi txtname="_acme-challenge.${fulldomain}." zone_data=$(api_get "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}") records=$(echo "$zone_data" | jq -c --arg txtname "$txtname" --arg token "$token" ' [ .rrsets[]? | select(.name == $txtname and .type == "TXT") | .records[]?.content ] as $existing | ($existing + [$token | @json] | unique) | map({content: ., disabled: false}) ') payload=$(jq -cn \ --arg txtname "$txtname" \ --argjson ttl "${ttl}" \ --argjson records "$records" \ '{rrsets:[{changetype:"REPLACE",name:$txtname,type:"TXT",ttl:$ttl,records:$records}]}') response=$(curl --silent -X PATCH "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}" \ -H 'Content-Type: application/json' \ -H "X-API-Key: ${api_key}" \ -d "$payload" \ -o /dev/null -w '%{http_code}') if [[ "$response" != "204" ]]; then echo "Record not created" echo "Response code: $response" exit 1 fi curl --silent -X PUT "${api_url%/}/api/v1/servers/${server_id}/zones/${zone_name}/notify" \ -H "X-API-Key: ${api_key}" \ -o /dev/null