#!/usr/bin/env bash # Copyright (C) 2017,2018 Timothe Litt litt at acm _dot org VERSION="2.0" PROG="$(basename "$0")" # This script is used to update TXT records in GoDaddy DNS server # It depends on JSON.sh from https://github.com/dominictarr/JSON.sh # Place it in (or softlink it to) the same directory as this script, # or specify its location with GODADDY_JSON # # See the usage text below, 00GoDaddy-README.txt, dns_add_godaddy # and dns_del_godaddy for additional information. # # It may be freely used providing this notice is included with # all copies. The name of the author may not be used to endorse # any other product or derivative work. No warranty is provided # and the user assumes all responsibility for use of this software. # # Bug reports are welcome at https://github.com/tlhackque/getssl/issues. API='https://api.godaddy.com/v1/domains' APISIGNUP='https://developer.godaddy.com/getstarted' GETJSON='https://github.com/dominictarr/JSON.sh' VERB="y" DEBUG="$GODADDY_DEBUG" [ -z "$JSON" ] && JSON="$GODADDY_JSON" [ -z "$JSON" ] && JSON="$(dirname "$0")/JSON.sh" while getopts 'dhj:k:s:t:qv' opt; do case $opt in d) DEBUG="Y" ;; j) JSON="$OPTARG" ;; k) GODADDY_KEY="$OPTARG" ;; s) GODADDY_SECRET="$OPTARG" ;; t) TRACE="$OPTARG" ;; q) VERB= ;; v) echo "dns_godaddy version $VERSION"; exit 0 ;; *) cat <&2 $0: requires JSON.sh as "$JSON" The full path to JSON.sh can be specified with -j, or the GODADDY_JSON environment variable. You can obtain a copy from $GETJSON Then place or softlink it to $JSON or set GODADDY_JSON. EOF exit 2 fi if [ -z "$GODADDY_KEY" ] || [ -z "$GODADDY_SECRET" ]; then echo "GODADDY_KEY and GODADDY secret must be defined" >&2 exit 3 fi [ -n "$DEBUG" ] && VERB="y" [ -n "$GODADDY_TRACE" ] && VERB="Y" [ -n "$GODADDY_TFILE" ] && TRACE="$GODADDY_TFILE" # Get parameters & validate op="$1" if ! [[ "$op" =~ ^(add|del)$ ]]; then echo "Operation must be \"add\" or \"del\"" >&2 exit 3 fi name="$2" if [ -z "$name" ]; then echo "'name' parameter is required, see -h" >&2 exit 3 fi data="$3" if [ -z "$data" ]; then echo "'data' parameter is required, see -h" >&2 exit 3 fi if [ "$op" = 'del' ]; then ttl= elif [ -z "$5" ]; then ttl="600" # GoDaddy minimum TTL is 600 elif ! [[ "$5" =~ ^[0-9]+$ ]]; then echo "TTL $5 is not numeric" >&2 exit 3 elif [ "$5" -lt 600 ]; then [ -n "$VERB" ] && \ echo "$5 is less than GoDaddy minimum of 600; increased to 600" >&2 ttl="600" else ttl="$5" fi # --- Done with parameters [ -n "$DEBUG" ] && \ echo "$PROG: $op $name \"$data\" $ttl" >&2 # Authorization header has secret and key authhdr="Authorization: sso-key $GODADDY_KEY:$GODADDY_SECRET" if [ -n "$TRACE" ]; then function timestamp { local tm="$(LC_TIME=C date '+%T.%N')" local class="$1"; shift echo "${tm:0:15} ** ${class}: $*" >>"$TRACE" } timestamp 'Info' "$PROG" "V$VERSION" 'Starting new protocol trace' timestamp 'Args' "$@" curl --help | grep -q -- --trace-time && CURL_TFLAGS="--trace-time" # 7.14.0 function curl { command curl ${CURL_TFLAGS} --trace-ascii % "$@" 2>>"$TRACE" } [ -n "$VERB" ] && echo "Appending protocol trace to $TRACE" fi [ -n "$DEBUG" ] && echo "$authhdr" >&2 #strip off the last period if [[ "$name" =~ ^.+\. ]]; then name=${name%?} fi reqdomain= reqname= # GoDaddy REST API URL is in the format /v1/domains/{domain}/records/{type}/{name} # for adding/updating (PUT) or deleting (DELETE) a record. The API will support up # to three segments in domain names (ex. mydomain.com and www.mydomain.com) # in order to determine which domain the API call will affect (both mydomain.com and # www.mydomain.com will result in the modification of the mydomain.com domain. Any # more than three segments (ex. sub.something.mydomain.com will result in # the API throwing a MISMATCH_FORMAT error. # # Examples # 1. If mydomain.com was provided to this script as the domain parameter, and # _acme-challengemydomain.com was provided as the name, then the URL # /v1/domains/mydomain.com/records/TXT/_acme-challenge will be used which # # 2. If www.mydomain.com was provided to this script as the domain parameter, # and _acme-challenge.www.mydomain.com was provided as the name, then the # URL /v1/domains/mydomain.com/records/TXT/_acme-challenge.www will be used. # Determine the domain and the name to use for the API the URL # The name parameter given to us is in the format challenge.domain. # (ex _acme-challenge.mydomain.com. - note the trailing period). We will just # use the name given us to determine the domain while [[ "$name" =~ ^([^.]+)\.([^.]+.*) ]]; do if [ -n "${reqname}" ]; then reqname="${reqname}."; fi reqname="${reqname}${BASH_REMATCH[1]}" testdomain="${BASH_REMATCH[2]}" name=$testdomain if [[ ! "$name" =~ [^.]+\.[^.]+ ]]; then exit 1 fi url="$API/$testdomain" [ -n "$DEBUG" ] && echo "Looking for domain ${testdomain}" response="$(curl -i -s -X GET --config - "${url}" <&2 <&2 exit $sts fi if echo "$response" | grep -q '^HTTP/.* 200 '; then [ -n "$DEBUG" ] && echo "Found domain ${testdomain}" reqdomain=${testdomain} break fi code="$(echo "$response" | grep '"code":' | sed -e's/^.*"code":"//; s/\".*$//')" if [ "$code" = 'NOT_FOUND' ]; then continue fi done if [ -z "$reqdomain" ] || [ -z "$reqname" ]; then echo "Unable to determine domain or RR name" >&2 exit 3 fi if [ "$op" = "add" ]; then url="$API/$reqdomain/records/TXT/$reqname" request='[{"data":"'$data'","ttl":'$ttl'}]' [ -n "$DEBUG" ] && cat >&2 <&2 <&2 exit $sts fi if ! echo "$result" | grep -q '^HTTP/.* 200 '; then code="$(echo "$result" | grep '"code":' | sed -e's/^.*"code":"//; s/\".*$//')" msg="$(echo "$result" | grep '"message":' | sed -e's/^.*"message":"//; s/\".*$//')" if [ "$code" = "DUPLICATE_RECORD" ]; then if [ -n "$VERB" ]; then echo "$msg in $reqdomain" >&2 fi exit 0 # Duplicate record is still success fi echo "Request failed $msg" >&2 exit 1 fi [ -n "$VERB" ] && echo "$reqdomain: added $reqname $ttl TXT \"$data\"" >&2 exit 0 fi if [ "$op" = "del" ]; then url="$API/$reqdomain/records/TXT/$reqname" [ -n "$DEBUG" ] && echo "Deleting challenge TXT records at: $url" >&2 current="$(curl -i -s -X DELETE --config - "$url" <&2 exit $sts fi [ -n "$DEBUG" ] && cat >&2 <&2 exit 1 fi [ -n "$VERB" ] && echo "$reqdomain: deleted $reqname TXT \"$data\"" >&2 exit 0 fi