From 46fbd7f1e1fc355c34c76b6457e6a6959b5a387b Mon Sep 17 00:00:00 2001 From: "Steven M. Miano" Date: Thu, 14 Mar 2019 08:41:13 -0400 Subject: [PATCH] support ultradns.com api (#2117) support ultradns.com api (#2117) --- README.md | 1 + dnsapi/README.md | 24 +++++++ dnsapi/dns_ultra.sh | 164 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 dnsapi/dns_ultra.sh diff --git a/README.md b/README.md index 50466ad7..68d1b57d 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,7 @@ You don't have to do anything manually! 1. Core-Networks.de (https://core-networks.de) 1. NederHost API (https://www.nederhost.nl/) 1. Zone.ee (zone.eu) API (https://api.zone.eu/v2) +1. UltraDNS API (https://portal.ultradns.com) And: diff --git a/dnsapi/README.md b/dnsapi/README.md index de3148cf..3cce294a 100644 --- a/dnsapi/README.md +++ b/dnsapi/README.md @@ -1326,6 +1326,30 @@ acme.sh --issue -d example.com -d www.example.com --dns dns_zone ``` `ZONE_Username` and `ZONE_Key` will be saved in `~/.acme.sh/account.conf` and will be reused when needed. + +## 70. Use UltraDNS API + +UltraDNS is a paid for service that provides DNS, as well as Web and Mail forwarding (as well as reporting, auditing, and advanced tools). + +More information can be found here: https://www.security.neustar/lp/ultra20/index.html + +The REST API documentation for this service is found here: https://portal.ultradns.com/static/docs/REST-API_User_Guide.pdf + +Set your UltraDNS User name, and password; these would be the same you would use here: + +https://portal.ultradns.com/ - or if you create an API only user, that username and password would be better utilized. + +``` +export ULTRA_USR="abcd" +export ULTRA_PWD="efgh" + +To issue a cert run: + +acme.sh --issue --dns dns_ultra -d example.com -d www.example.com +``` + +`ULTRA_USR` and `ULTRA_PWD` will be saved in `~/.acme.sh/account.conf` and will be resued when needed. + # Use custom API If your API is not supported yet, you can write your own DNS API. diff --git a/dnsapi/dns_ultra.sh b/dnsapi/dns_ultra.sh new file mode 100644 index 00000000..0100b3b7 --- /dev/null +++ b/dnsapi/dns_ultra.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env sh + +# +# ULTRA_USR="your_user_goes_here" +# +# ULTRA_PWD="some_password_goes_here" + +ULTRA_API="https://restapi.ultradns.com/v2/" + +#Usage: add _acme-challenge.www.domain.com "some_long_string_of_characters_go_here_from_lets_encrypt" +dns_ultra_add() { + fulldomain=$1 + txtvalue=$2 + export txtvalue + ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" + ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" + if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then + ULTRA_USR="" + ULTRA_PWD="" + _err "You didn't specify an UltraDNS username and password yet" + return 1 + fi + # save the username and password to the account conf file. + _saveaccountconf_mutable ULTRA_USR "$ULTRA_USR" + _saveaccountconf_mutable ULTRA_PWD "$ULTRA_PWD" + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "${_domain_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${_domain}" + _debug "Getting txt records" + _ultra_rest GET "zones/${_domain_id}/rrsets/TXT?q=value:${fulldomain}" + if printf "%s" "$response" | grep \"totalCount\" >/dev/null; then + _err "Error, it would appear that this record already exists. Please review existing TXT records for this domain." + return 1 + fi + + _info "Adding record" + if _ultra_rest POST "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then + if _contains "$response" "Successful"; then + _info "Added, OK" + return 0 + elif _contains "$response" "Resource Record of type 16 with these attributes already exists"; then + _info "Already exists, OK" + return 0 + else + _err "Add txt record error." + return 1 + fi + fi + _err "Add txt record error." + +} + +dns_ultra_rm() { + fulldomain=$1 + txtvalue=$2 + export txtvalue + ULTRA_USR="${ULTRA_USR:-$(_readaccountconf_mutable ULTRA_USR)}" + ULTRA_PWD="${ULTRA_PWD:-$(_readaccountconf_mutable ULTRA_PWD)}" + if [ -z "$ULTRA_USR" ] || [ -z "$ULTRA_PWD" ]; then + ULTRA_USR="" + ULTRA_PWD="" + _err "You didn't specify an UltraDNS username and password yet" + return 1 + fi + + _debug "First detect the root zone" + if ! _get_root "$fulldomain"; then + _err "invalid domain" + return 1 + fi + _debug _domain_id "${_domain_id}" + _debug _sub_domain "${_sub_domain}" + _debug _domain "${domain}" + + _debug "Getting TXT records" + _ultra_rest GET "zones/${_domain_id}/rrsets?q=kind:RECORDS+owner:${_sub_domain}" + + if ! printf "%s" "$response" | grep \"resultInfo\" >/dev/null; then + _err "There was an error in obtaining the resource records for ${_domain_id}" + return 1 + fi + + count=$(echo "$response" | _egrep_o "\"returnedCount\":[^,]*" | cut -d: -f2 | cut -d'}' -f1) + _debug count "${count}" + if [ "${count}" = "" ]; then + _info "Text record is not present, will not delete anything." + else + if ! _ultra_rest DELETE "zones/$_domain_id/rrsets/TXT/${_sub_domain}" '{"ttl":300,"rdata":["'"${txtvalue}"'"]}'; then + _err "Deleting the record did not succeed, please verify/check." + return 1 + fi + _contains "$response" "" + fi + +} + +#################### Private functions below ################################## +#_acme-challenge.www.domain.com +#returns +# _sub_domain=_acme-challenge.www +# _domain=domain.com +# _domain_id=sdjkglgdfewsdfg +_get_root() { + domain=$1 + i=2 + p=1 + while true; do + h=$(printf "%s" "$domain" | cut -d . -f $i-100) + _debug h "$h" + _debug response "$response" + if [ -z "$h" ]; then + #not valid + return 1 + fi + if ! _ultra_rest GET "zones"; then + return 1 + fi + if _contains "${response}" "${h}." >/dev/null; then + _domain_id=$(echo "$response" | _egrep_o "${h}") + if [ "$_domain_id" ]; then + _sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p) + _domain="${h}" + _debug sub_domain "${_sub_domain}" + _debug domain "${_domain}" + return 0 + fi + return 1 + fi + p=$i + i=$(_math "$i" + 1) + done + return 1 +} + +_ultra_rest() { + m=$1 + ep="$2" + data="$3" + _debug "$ep" + _debug TOKEN "${AUTH_TOKEN}" + + _ultra_login + export _H1="Content-Type: application/json" + export _H2="Authorization: Bearer ${AUTH_TOKEN}" + + if [ "$m" != "GET" ]; then + _debug data "${data}" + response="$(_post "${data}" "${ULTRA_API}"/"${ep}" "" "${m}")" + else + response="$(_get "$ULTRA_API/$ep")" + fi +} + +_ultra_login() { + export _H1="" + export _H2="" + AUTH_TOKEN=$(_post "grant_type=password&username=${ULTRA_USR}&password=${ULTRA_PWD}" "${ULTRA_API}authorization/token" | cut -d, -f3 | cut -d\" -f4) + export AUTH_TOKEN +}