2
0
mirror of https://github.com/acmesh-official/acme.sh synced 2025-08-22 09:57:29 +00:00
acme.sh/dnsapi/dns_dynv6.sh

292 lines
8.8 KiB
Bash
Raw Normal View History

2020-01-18 13:48:29 +01:00
#!/usr/bin/env sh
# shellcheck disable=SC2034
dns_dynv6_info='DynV6.com
Site: DynV6.com
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dynv6
Options:
DYNV6_TOKEN REST API token. Get from https://DynV6.com/keys
OptionsAlt:
KEY Path to SSH private key file. E.g. "/root/.ssh/dynv6"
Issues: github.com/acmesh-official/acme.sh/issues/2702
Upload latest dev branch to master (#3) * Fix for empty error objects in response breaking extraction of domain validation types Fix for empty error objects in the response which mess up the extraction of domain validation types due to the closing brace in the error object prematurely matching the end of the search pattern. This seems to be a recent change with ZeroSSL in particular where "error":{} is being included in responses. There could potentially be a related issue if there is a complex error object ever returned in the validation check response where an embedded sub-object could lead to an incomplete extraction of the error message, roughly around line 5040. Adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018 * Add new dnsapi support for OpenProvider.eu using new REST API * Cleanup duplicate debug log output based on DNS test run * Resolve spellcheck error * Configure 10 second timeout to ACME_DIRECTORY API call * add support for AIX style netstat * add * fix for wiki * minor * minor * wiki * wiki * dnsapi: dns_mydnsjp.sh fix author The @epgdatacapbon was renamed to @tkmsst Signed-off-by: Sergey Ponomarev <stokito@gmail.com> * dnsapi: dns_ddnss.sh remove RaidenII from authors He made the DuckDNS script that was used for this script but he can't support the script. Signed-off-by: Sergey Ponomarev <stokito@gmail.com> * dnsapi: fix authors: use @ for GitHub profiles Signed-off-by: Sergey Ponomarev <stokito@gmail.com> * dnsapi: dns_vultr.sh remove empty author Signed-off-by: Sergey Ponomarev <stokito@gmail.com> * dnsapi: dns_mijnhost.sh rearrange fields, use user docs instead of API docs Signed-off-by: Sergey Ponomarev <stokito@gmail.com> * dnsapi: fix Structured DNS Info Signed-off-by: Sergey Ponomarev <stokito@gmail.com> * Fix logged typo when running pre hook * Run post hook when _on_before_issue errors --------- Signed-off-by: Sergey Ponomarev <stokito@gmail.com> Co-authored-by: Ciaran Walsh <ciaran@ciaran-walsh.com> Co-authored-by: Lambiek12 <algemeen@lambiek12.nl> Co-authored-by: Erwin Oegema <blablaechthema@hotmail.com> Co-authored-by: laDanz <cdanzmann@gmail.com> Co-authored-by: neil <github@neilpang.com> Co-authored-by: neil <gitpc@neilpang.com> Co-authored-by: Sergey Ponomarev <stokito@gmail.com> Co-authored-by: David Beitey <david@davidjb.com> Co-authored-by: Jan-willem van Kampen <Lambiek12@users.noreply.github.com>
2025-08-12 11:12:09 +03:00
Author: @StefanAbl
'
2020-07-13 15:42:45 +02:00
dynv6_api="https://dynv6.com/api/v2"
2020-01-18 13:48:29 +01:00
######## Public functions #####################
# Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
2020-07-13 15:42:45 +02:00
#Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
2020-01-18 13:48:29 +01:00
dns_dynv6_add() {
fulldomain="$(echo "$1" | _lower_case)"
txtvalue="$2"
2020-01-18 13:48:29 +01:00
_info "Using dynv6 api"
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
2020-07-13 15:49:25 +02:00
_get_authentication
if [ "$dynv6_token" ]; then
_dns_dynv6_add_http
return $?
2020-07-13 15:49:25 +02:00
else
2020-07-13 15:49:25 +02:00
_info "using key file $dynv6_keyfile"
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
if ! _get_domain "$fulldomain" "$_your_hosts"; then
_err "Host not found on your account"
return 1
fi
_debug "found host on your account"
returnval="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts \""$_host"\" records set \""$_record"\" txt data \""$txtvalue"\")"
_debug "Dynv6 returned this after record was added: $returnval"
if _contains "$returnval" "created"; then
return 0
elif _contains "$returnval" "updated"; then
return 0
else
_err "Something went wrong! it does not seem like the record was added successfully"
return 1
fi
2020-01-18 13:48:29 +01:00
fi
2024-10-13 17:49:29 +02:00
2020-01-18 13:48:29 +01:00
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_dynv6_rm() {
fulldomain="$(echo "$1" | _lower_case)"
txtvalue="$2"
2020-05-31 18:49:39 +02:00
_info "Using dynv6 API"
2020-01-18 13:48:29 +01:00
_debug fulldomain "$fulldomain"
_debug txtvalue "$txtvalue"
2020-07-13 15:42:45 +02:00
_get_authentication
2020-07-13 15:49:25 +02:00
if [ "$dynv6_token" ]; then
2020-07-13 15:42:45 +02:00
_dns_dynv6_rm_http
return $?
2020-07-13 15:49:25 +02:00
else
2020-07-13 15:49:25 +02:00
_info "using key file $dynv6_keyfile"
_your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)"
if ! _get_domain "$fulldomain" "$_your_hosts"; then
_err "Host not found on your account"
return 1
fi
_debug "found host on your account"
_info "$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts "\"$_host\"" records del "\"$_record\"" txt)"
return 0
2020-07-13 15:42:45 +02:00
fi
2020-01-18 13:48:29 +01:00
}
#################### Private functions below ##################################
#Usage: No Input required
#returns
2020-07-13 15:42:45 +02:00
#dynv6_keyfile the path to the new key file that has been generated
2020-01-18 13:48:29 +01:00
_generate_new_key() {
dynv6_keyfile="$(eval echo ~"$USER")/.ssh/dynv6"
_info "Path to key file used: $dynv6_keyfile"
if [ ! -f "$dynv6_keyfile" ] && [ ! -f "$dynv6_keyfile.pub" ]; then
_debug "generating key in $dynv6_keyfile and $dynv6_keyfile.pub"
ssh-keygen -f "$dynv6_keyfile" -t ssh-ed25519 -N ''
else
_err "There is already a file in $dynv6_keyfile or $dynv6_keyfile.pub"
return 1
fi
}
2020-05-31 18:49:39 +02:00
#Usage: _acme-challenge.www.example.dynv6.net "$_your_hosts"
#where _your_hosts is the output of ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts
2020-01-18 13:48:29 +01:00
#returns
#_host= example.dynv6.net
#_record=_acme-challenge.www
#aborts if not a valid domain
_get_domain() {
2020-05-31 18:49:39 +02:00
#_your_hosts="$(ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts)"
2020-01-18 13:48:29 +01:00
_full_domain="$1"
2020-05-31 18:49:39 +02:00
_your_hosts="$2"
2020-01-18 13:48:29 +01:00
2020-05-31 18:49:39 +02:00
_your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')"
for l in $_your_hosts; do
2020-05-31 19:09:27 +02:00
#echo "host: $l"
2022-11-23 21:33:29 +08:00
if test "${_full_domain#*"$l"}" != "$_full_domain"; then
2022-11-23 21:28:17 +08:00
_record=${_full_domain%."$l"}
2020-05-31 19:09:27 +02:00
_host=$l
_debug "The host is $_host and the record $_record"
return 0
fi
2020-05-31 18:49:39 +02:00
done
_err "Either their is no such host on your dnyv6 account or it cannot be accessed with this key"
return 1
2020-01-18 13:48:29 +01:00
}
# Usage: No input required
#returns
#dynv6_keyfile path to the key that will be used
2020-07-13 15:49:25 +02:00
_get_authentication() {
2020-07-13 16:01:46 +02:00
dynv6_token="${DYNV6_TOKEN:-$(_readaccountconf_mutable dynv6_token)}"
if [ "$dynv6_token" ]; then
_debug "Found HTTP Token. Going to use the HTTP API and not the SSH API"
if [ "$DYNV6_TOKEN" ]; then
_saveaccountconf_mutable dynv6_token "$dynv6_token"
fi
2020-07-13 15:49:25 +02:00
else
_debug "no HTTP token found. Looking for an SSH key"
dynv6_keyfile="${dynv6_keyfile:-$(_readaccountconf_mutable dynv6_keyfile)}"
_debug "Your key is $dynv6_keyfile"
if [ -z "$dynv6_keyfile" ]; then
if [ -z "$KEY" ]; then
_err "You did not specify a key to use with dynv6"
_info "Creating new dynv6 API key to add to dynv6.com"
_generate_new_key
_info "Please add this key to dynv6.com $(cat "$dynv6_keyfile.pub")"
_info "Hit Enter to continue"
read -r _
#save the credentials to the account conf file.
else
dynv6_keyfile="$KEY"
fi
_saveaccountconf_mutable dynv6_keyfile "$dynv6_keyfile"
2020-07-13 15:42:45 +02:00
fi
2020-01-18 13:48:29 +01:00
fi
}
2020-07-13 15:42:45 +02:00
2020-07-13 15:49:25 +02:00
_dns_dynv6_add_http() {
_debug "Got HTTP token form _get_authentication method. Going to use the HTTP API"
if ! _get_zone_id "$fulldomain"; then
_err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone"
return 1
fi
_get_zone_name "$_zone_id"
2022-11-23 21:28:17 +08:00
record=${fulldomain%%."$_zone_name"}
2020-07-13 15:49:25 +02:00
_set_record TXT "$record" "$txtvalue"
if _contains "$response" "$txtvalue"; then
_info "Successfully added record"
return 0
else
_err "Something went wrong while adding the record"
return 1
fi
2020-07-13 15:42:45 +02:00
}
2020-07-13 15:49:25 +02:00
_dns_dynv6_rm_http() {
2020-07-13 15:42:45 +02:00
_debug "Got HTTP token form _get_authentication method. Going to use the HTTP API"
2020-07-13 15:49:25 +02:00
if ! _get_zone_id "$fulldomain"; then
_err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone"
return 1
fi
_get_zone_name "$_zone_id"
2022-11-23 21:28:17 +08:00
record=${fulldomain%%."$_zone_name"}
2020-07-13 15:49:25 +02:00
_get_record_id "$_zone_id" "$record" "$txtvalue"
_del_record "$_zone_id" "$_record_id"
if [ -z "$response" ]; then
_info "Successfully deleted record"
return 0
else
_err "Something went wrong while deleting the record"
return 1
fi
2020-07-13 15:42:45 +02:00
}
#get the zoneid for a specifc record or zone
#usage: _get_zone_id §record
#where $record is the record to get the id for
#returns _zone_id the id of the zone
2020-07-13 15:49:25 +02:00
_get_zone_id() {
2020-07-13 15:42:45 +02:00
record="$1"
_debug "getting zone id for $record"
_dynv6_rest GET zones
2020-07-13 15:49:25 +02:00
zones="$(echo "$response" | tr '}' '\n' | tr ',' '\n' | grep name | sed 's/\[//g' | tr -d '{' | tr -d '"')"
#echo $zones
selected=""
for z in $zones; do
z="${z#name:}"
_debug zone: "$z"
if _contains "$record" "$z"; then
_debug "$z found in $record"
selected="$z"
fi
done
if [ -z "$selected" ]; then
_err "no zone found"
return 1
fi
zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep '"id":' | tr -d '"')"
2020-07-13 15:49:25 +02:00
_zone_id="${zone_id#id:}"
_debug "zone id: $_zone_id"
2020-07-13 15:42:45 +02:00
}
2020-07-13 15:49:25 +02:00
_get_zone_name() {
_zone_id="$1"
_dynv6_rest GET zones/"$_zone_id"
_zone_name="$(echo "$response" | tr ',' '\n' | tr -d '{' | grep name | tr -d '"')"
_zone_name="${_zone_name#name:}"
2020-07-13 15:42:45 +02:00
}
#usaage _get_record_id $zone_id $record
# where zone_id is thevalue returned by _get_zone_id
# and record ist in the form _acme.www for an fqdn of _acme.www.example.com
# returns _record_id
2020-07-13 15:49:25 +02:00
_get_record_id() {
2020-07-13 15:42:45 +02:00
_zone_id="$1"
record="$2"
value="$3"
2020-07-13 15:49:25 +02:00
_dynv6_rest GET "zones/$_zone_id/records"
if ! _get_record_id_from_response "$response"; then
_err "no such record $record found in zone $_zone_id"
return 1
fi
2020-07-13 15:42:45 +02:00
}
2020-07-13 15:49:25 +02:00
_get_record_id_from_response() {
2020-07-13 15:42:45 +02:00
response="$1"
2020-07-13 15:49:25 +02:00
_record_id="$(echo "$response" | tr '}' '\n' | grep "\"name\":\"$record\"" | grep "\"data\":\"$value\"" | tr ',' '\n' | grep id | tr -d '"' | tr -d 'id:')"
#_record_id="${_record_id#id:}"
if [ -z "$_record_id" ]; then
_err "no such record: $record found in zone $_zone_id"
return 1
fi
_debug "record id: $_record_id"
return 0
2020-07-13 15:42:45 +02:00
}
#usage: _set_record TXT _acme_challenge.www longvalue 12345678
#zone id is optional can also be set as vairable bevor calling this method
2020-07-13 15:49:25 +02:00
_set_record() {
type="$1"
record="$2"
value="$3"
if [ "$4" ]; then
_zone_id="$4"
fi
data="{\"name\": \"$record\", \"data\": \"$value\", \"type\": \"$type\"}"
#data='{ "name": "acme.test.thorn.dynv6.net", "type": "A", "data": "192.168.0.1"}'
echo "$data"
#"{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}"
_dynv6_rest POST "zones/$_zone_id/records" "$data"
2020-07-13 15:42:45 +02:00
}
2020-07-13 15:49:25 +02:00
_del_record() {
2020-07-13 15:42:45 +02:00
_zone_id=$1
_record_id=$2
_dynv6_rest DELETE zones/"$_zone_id"/records/"$_record_id"
}
_dynv6_rest() {
2020-07-13 15:49:25 +02:00
m=$1 #method GET,POST,DELETE or PUT
2020-08-28 19:46:45 +02:00
ep="$2" #the endpoint
2020-07-13 15:42:45 +02:00
data="$3"
_debug "$ep"
token_trimmed=$(echo "$dynv6_token" | tr -d '"')
2020-07-13 15:49:25 +02:00
2020-07-13 15:42:45 +02:00
export _H1="Authorization: Bearer $token_trimmed"
export _H2="Content-Type: application/json"
2020-07-13 15:49:25 +02:00
2020-07-13 15:42:45 +02:00
if [ "$m" != "GET" ]; then
_debug data "$data"
response="$(_post "$data" "$dynv6_api/$ep" "" "$m")"
else
response="$(_get "$dynv6_api/$ep")"
fi
if [ "$?" != "0" ]; then
_err "error $ep"
return 1
fi
_debug2 response "$response"
return 0
}