]>
Commit | Line | Data |
---|---|---|
0f54cf83 S |
1 | #!/usr/bin/env sh |
2 | #Author StefanAbl | |
3 | #Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"' | |
9190ce37 | 4 | #or use the HTTP REST API by by specifying a token 'export DYNV6_TOKEN="value" |
0f54cf83 | 5 | #if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub |
9190ce37 S |
6 | |
7 | dynv6_api="https://dynv6.com/api/v2" | |
0f54cf83 S |
8 | ######## Public functions ##################### |
9 | # Please Read this guide first: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide | |
9190ce37 | 10 | #Usage: dns_dynv6_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" |
0f54cf83 S |
11 | dns_dynv6_add() { |
12 | fulldomain=$1 | |
13 | txtvalue=$2 | |
14 | _info "Using dynv6 api" | |
15 | _debug fulldomain "$fulldomain" | |
16 | _debug txtvalue "$txtvalue" | |
9dd50899 S |
17 | _get_authentication |
18 | if [ "$dynv6_token" ]; then | |
19 | _dns_dynv6_add_http | |
20 | return $? | |
6651801b | 21 | else |
9dd50899 S |
22 | _info "using key file $dynv6_keyfile" |
23 | _your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)" | |
24 | if ! _get_domain "$fulldomain" "$_your_hosts"; then | |
25 | _err "Host not found on your account" | |
26 | return 1 | |
27 | fi | |
28 | _debug "found host on your account" | |
29 | returnval="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts \""$_host"\" records set \""$_record"\" txt data \""$txtvalue"\")" | |
30 | _debug "Dynv6 returned this after record was added: $returnval" | |
31 | if _contains "$returnval" "created"; then | |
32 | return 0 | |
33 | elif _contains "$returnval" "updated"; then | |
34 | return 0 | |
35 | else | |
36 | _err "Something went wrong! it does not seem like the record was added successfully" | |
37 | return 1 | |
38 | fi | |
0f54cf83 S |
39 | return 1 |
40 | fi | |
41 | return 1 | |
42 | } | |
43 | #Usage: fulldomain txtvalue | |
44 | #Remove the txt record after validation. | |
45 | dns_dynv6_rm() { | |
46 | fulldomain=$1 | |
47 | txtvalue=$2 | |
943d419f | 48 | _info "Using dynv6 API" |
0f54cf83 S |
49 | _debug fulldomain "$fulldomain" |
50 | _debug txtvalue "$txtvalue" | |
9190ce37 | 51 | _get_authentication |
6651801b | 52 | if [ "$dynv6_token" ]; then |
9190ce37 S |
53 | _dns_dynv6_rm_http |
54 | return $? | |
6651801b | 55 | else |
9dd50899 S |
56 | _info "using key file $dynv6_keyfile" |
57 | _your_hosts="$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts)" | |
58 | if ! _get_domain "$fulldomain" "$_your_hosts"; then | |
59 | _err "Host not found on your account" | |
60 | return 1 | |
61 | fi | |
62 | _debug "found host on your account" | |
63 | _info "$(ssh -i "$dynv6_keyfile" api@dynv6.com hosts "\"$_host\"" records del "\"$_record\"" txt)" | |
64 | return 0 | |
9190ce37 | 65 | fi |
0f54cf83 S |
66 | } |
67 | #################### Private functions below ################################## | |
68 | #Usage: No Input required | |
69 | #returns | |
9190ce37 | 70 | #dynv6_keyfile the path to the new key file that has been generated |
0f54cf83 S |
71 | _generate_new_key() { |
72 | dynv6_keyfile="$(eval echo ~"$USER")/.ssh/dynv6" | |
73 | _info "Path to key file used: $dynv6_keyfile" | |
74 | if [ ! -f "$dynv6_keyfile" ] && [ ! -f "$dynv6_keyfile.pub" ]; then | |
75 | _debug "generating key in $dynv6_keyfile and $dynv6_keyfile.pub" | |
76 | ssh-keygen -f "$dynv6_keyfile" -t ssh-ed25519 -N '' | |
77 | else | |
78 | _err "There is already a file in $dynv6_keyfile or $dynv6_keyfile.pub" | |
79 | return 1 | |
80 | fi | |
0f54cf83 | 81 | } |
91a8b97c S |
82 | |
83 | #Usage: _acme-challenge.www.example.dynv6.net "$_your_hosts" | |
84 | #where _your_hosts is the output of ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts | |
0f54cf83 S |
85 | #returns |
86 | #_host= example.dynv6.net | |
87 | #_record=_acme-challenge.www | |
88 | #aborts if not a valid domain | |
89 | _get_domain() { | |
91a8b97c | 90 | #_your_hosts="$(ssh -i ~/.ssh/dynv6.pub api@dynv6.com hosts)" |
0f54cf83 | 91 | _full_domain="$1" |
91a8b97c | 92 | _your_hosts="$2" |
0f54cf83 | 93 | |
91a8b97c S |
94 | _your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')" |
95 | for l in $_your_hosts; do | |
90e2064d | 96 | #echo "host: $l" |
e275cb1e | 97 | if test "${_full_domain#*"$l"}" != "$_full_domain"; then |
60315e5b | 98 | _record=${_full_domain%."$l"} |
90e2064d S |
99 | _host=$l |
100 | _debug "The host is $_host and the record $_record" | |
101 | return 0 | |
102 | fi | |
91a8b97c S |
103 | done |
104 | _err "Either their is no such host on your dnyv6 account or it cannot be accessed with this key" | |
105 | return 1 | |
0f54cf83 S |
106 | } |
107 | ||
108 | # Usage: No input required | |
109 | #returns | |
110 | #dynv6_keyfile path to the key that will be used | |
9dd50899 | 111 | _get_authentication() { |
551316bc S |
112 | dynv6_token="${DYNV6_TOKEN:-$(_readaccountconf_mutable dynv6_token)}" |
113 | if [ "$dynv6_token" ]; then | |
114 | _debug "Found HTTP Token. Going to use the HTTP API and not the SSH API" | |
115 | if [ "$DYNV6_TOKEN" ]; then | |
116 | _saveaccountconf_mutable dynv6_token "$dynv6_token" | |
117 | fi | |
9dd50899 S |
118 | else |
119 | _debug "no HTTP token found. Looking for an SSH key" | |
120 | dynv6_keyfile="${dynv6_keyfile:-$(_readaccountconf_mutable dynv6_keyfile)}" | |
121 | _debug "Your key is $dynv6_keyfile" | |
122 | if [ -z "$dynv6_keyfile" ]; then | |
123 | if [ -z "$KEY" ]; then | |
124 | _err "You did not specify a key to use with dynv6" | |
125 | _info "Creating new dynv6 API key to add to dynv6.com" | |
126 | _generate_new_key | |
127 | _info "Please add this key to dynv6.com $(cat "$dynv6_keyfile.pub")" | |
128 | _info "Hit Enter to continue" | |
129 | read -r _ | |
130 | #save the credentials to the account conf file. | |
131 | else | |
132 | dynv6_keyfile="$KEY" | |
133 | fi | |
134 | _saveaccountconf_mutable dynv6_keyfile "$dynv6_keyfile" | |
9190ce37 | 135 | fi |
0f54cf83 | 136 | fi |
0f54cf83 | 137 | } |
9190ce37 | 138 | |
6651801b S |
139 | _dns_dynv6_add_http() { |
140 | _debug "Got HTTP token form _get_authentication method. Going to use the HTTP API" | |
141 | if ! _get_zone_id "$fulldomain"; then | |
142 | _err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone" | |
143 | return 1 | |
144 | fi | |
145 | _get_zone_name "$_zone_id" | |
60315e5b | 146 | record=${fulldomain%%."$_zone_name"} |
6651801b S |
147 | _set_record TXT "$record" "$txtvalue" |
148 | if _contains "$response" "$txtvalue"; then | |
149 | _info "Successfully added record" | |
150 | return 0 | |
151 | else | |
152 | _err "Something went wrong while adding the record" | |
153 | return 1 | |
154 | fi | |
9190ce37 S |
155 | } |
156 | ||
6651801b | 157 | _dns_dynv6_rm_http() { |
9190ce37 | 158 | _debug "Got HTTP token form _get_authentication method. Going to use the HTTP API" |
6651801b S |
159 | if ! _get_zone_id "$fulldomain"; then |
160 | _err "Could not find a matching zone for $fulldomain. Maybe your HTTP Token is not authorized to access the zone" | |
161 | return 1 | |
162 | fi | |
163 | _get_zone_name "$_zone_id" | |
60315e5b | 164 | record=${fulldomain%%."$_zone_name"} |
6651801b S |
165 | _get_record_id "$_zone_id" "$record" "$txtvalue" |
166 | _del_record "$_zone_id" "$_record_id" | |
167 | if [ -z "$response" ]; then | |
168 | _info "Successfully deleted record" | |
169 | return 0 | |
170 | else | |
171 | _err "Something went wrong while deleting the record" | |
172 | return 1 | |
173 | fi | |
9190ce37 S |
174 | } |
175 | ||
9190ce37 S |
176 | #get the zoneid for a specifc record or zone |
177 | #usage: _get_zone_id §record | |
178 | #where $record is the record to get the id for | |
179 | #returns _zone_id the id of the zone | |
6651801b | 180 | _get_zone_id() { |
9190ce37 S |
181 | record="$1" |
182 | _debug "getting zone id for $record" | |
183 | _dynv6_rest GET zones | |
6651801b S |
184 | |
185 | zones="$(echo "$response" | tr '}' '\n' | tr ',' '\n' | grep name | sed 's/\[//g' | tr -d '{' | tr -d '"')" | |
186 | #echo $zones | |
187 | ||
188 | selected="" | |
189 | for z in $zones; do | |
190 | z="${z#name:}" | |
191 | _debug zone: "$z" | |
192 | if _contains "$record" "$z"; then | |
193 | _debug "$z found in $record" | |
194 | selected="$z" | |
195 | fi | |
196 | done | |
197 | if [ -z "$selected" ]; then | |
198 | _err "no zone found" | |
199 | return 1 | |
200 | fi | |
201 | ||
202 | zone_id="$(echo "$response" | tr '}' '\n' | grep "$selected" | tr ',' '\n' | grep id | tr -d '"')" | |
203 | _zone_id="${zone_id#id:}" | |
204 | _debug "zone id: $_zone_id" | |
9190ce37 S |
205 | } |
206 | ||
6651801b S |
207 | _get_zone_name() { |
208 | _zone_id="$1" | |
209 | _dynv6_rest GET zones/"$_zone_id" | |
210 | _zone_name="$(echo "$response" | tr ',' '\n' | tr -d '{' | grep name | tr -d '"')" | |
211 | _zone_name="${_zone_name#name:}" | |
9190ce37 S |
212 | } |
213 | ||
214 | #usaage _get_record_id $zone_id $record | |
215 | # where zone_id is thevalue returned by _get_zone_id | |
216 | # and record ist in the form _acme.www for an fqdn of _acme.www.example.com | |
217 | # returns _record_id | |
6651801b | 218 | _get_record_id() { |
9190ce37 S |
219 | _zone_id="$1" |
220 | record="$2" | |
221 | value="$3" | |
6651801b S |
222 | _dynv6_rest GET "zones/$_zone_id/records" |
223 | if ! _get_record_id_from_response "$response"; then | |
224 | _err "no such record $record found in zone $_zone_id" | |
225 | return 1 | |
226 | fi | |
9190ce37 S |
227 | } |
228 | ||
6651801b | 229 | _get_record_id_from_response() { |
9190ce37 | 230 | response="$1" |
6651801b S |
231 | _record_id="$(echo "$response" | tr '}' '\n' | grep "\"name\":\"$record\"" | grep "\"data\":\"$value\"" | tr ',' '\n' | grep id | tr -d '"' | tr -d 'id:')" |
232 | #_record_id="${_record_id#id:}" | |
233 | if [ -z "$_record_id" ]; then | |
234 | _err "no such record: $record found in zone $_zone_id" | |
235 | return 1 | |
236 | fi | |
237 | _debug "record id: $_record_id" | |
238 | return 0 | |
9190ce37 S |
239 | } |
240 | #usage: _set_record TXT _acme_challenge.www longvalue 12345678 | |
241 | #zone id is optional can also be set as vairable bevor calling this method | |
6651801b S |
242 | _set_record() { |
243 | type="$1" | |
244 | record="$2" | |
245 | value="$3" | |
246 | if [ "$4" ]; then | |
247 | _zone_id="$4" | |
248 | fi | |
249 | data="{\"name\": \"$record\", \"data\": \"$value\", \"type\": \"$type\"}" | |
250 | #data='{ "name": "acme.test.thorn.dynv6.net", "type": "A", "data": "192.168.0.1"}' | |
251 | echo "$data" | |
252 | #"{\"type\":\"TXT\",\"name\":\"$fulldomain\",\"content\":\"$txtvalue\",\"ttl\":120}" | |
253 | _dynv6_rest POST "zones/$_zone_id/records" "$data" | |
9190ce37 | 254 | } |
6651801b | 255 | _del_record() { |
9190ce37 S |
256 | _zone_id=$1 |
257 | _record_id=$2 | |
258 | _dynv6_rest DELETE zones/"$_zone_id"/records/"$_record_id" | |
259 | } | |
260 | ||
261 | _dynv6_rest() { | |
6651801b | 262 | m=$1 #method GET,POST,DELETE or PUT |
4242354c | 263 | ep="$2" #the endpoint |
9190ce37 S |
264 | data="$3" |
265 | _debug "$ep" | |
266 | ||
267 | token_trimmed=$(echo "$dynv6_token" | tr -d '"') | |
6651801b | 268 | |
9190ce37 S |
269 | export _H1="Authorization: Bearer $token_trimmed" |
270 | export _H2="Content-Type: application/json" | |
6651801b | 271 | |
9190ce37 S |
272 | if [ "$m" != "GET" ]; then |
273 | _debug data "$data" | |
274 | response="$(_post "$data" "$dynv6_api/$ep" "" "$m")" | |
275 | else | |
276 | response="$(_get "$dynv6_api/$ep")" | |
277 | fi | |
278 | ||
279 | if [ "$?" != "0" ]; then | |
280 | _err "error $ep" | |
281 | return 1 | |
282 | fi | |
283 | _debug2 response "$response" | |
284 | return 0 | |
285 | } |