]> git.proxmox.com Git - mirror_acme.sh.git/blame - dnsapi/dns_freedns.sh
Merge pull request #4531 from NCDGHA/bugfix/issue_4530_fix_http_status_503
[mirror_acme.sh.git] / dnsapi / dns_freedns.sh
CommitLineData
600a2351
DK
1#!/usr/bin/env sh
2
3#This file name is "dns_freedns.sh"
4#So, here must be a method dns_freedns_add()
5#Which will be called by acme.sh to add the txt record to your api system.
6#returns 0 means success, otherwise error.
7#
8#Author: David Kerr
9#Report Bugs here: https://github.com/dkerr64/acme.sh
d795fac3 10#or here... https://github.com/acmesh-official/acme.sh/issues/2305
600a2351
DK
11#
12######## Public functions #####################
13
39f32396 14# Export FreeDNS userid and password in following variables...
600a2351
DK
15# FREEDNS_User=username
16# FREEDNS_Password=password
17# login cookie is saved in acme account config file so userid / pw
18# need to be set only when changed.
19
20#Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
21dns_freedns_add() {
22 fulldomain="$1"
23 txtvalue="$2"
24
25 _info "Add TXT record using FreeDNS"
26 _debug "fulldomain: $fulldomain"
27 _debug "txtvalue: $txtvalue"
28
29 if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then
30 FREEDNS_User=""
31 FREEDNS_Password=""
32 if [ -z "$FREEDNS_COOKIE" ]; then
33 _err "You did not specify the FreeDNS username and password yet."
34 _err "Please export as FREEDNS_User / FREEDNS_Password and try again."
35 return 1
36 fi
37 using_cached_cookies="true"
38 else
39 FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")"
40 if [ -z "$FREEDNS_COOKIE" ]; then
41 return 1
42 fi
43 using_cached_cookies="false"
44 fi
45
46 _debug "FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)"
47
48 _saveaccountconf FREEDNS_COOKIE "$FREEDNS_COOKIE"
49
09fb9dcd
DK
50 # We may have to cycle through the domain name to find the
51 # TLD that we own...
52 i=1
53 wmax="$(echo "$fulldomain" | tr '.' ' ' | wc -w)"
54 while [ "$i" -lt "$wmax" ]; do
55 # split our full domain name into two parts...
56 sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
57 i="$(_math "$i" + 1)"
58 top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)"
59 _debug "sub_domain: $sub_domain"
60 _debug "top_domain: $top_domain"
61
66c39a95 62 DNSdomainid="$(_freedns_domain_id "$top_domain")"
09fb9dcd
DK
63 if [ "$?" = "0" ]; then
64 _info "Domain $top_domain found at FreeDNS, domain_id $DNSdomainid"
600a2351 65 break
09fb9dcd
DK
66 else
67 _info "Domain $top_domain not found at FreeDNS, try with next level of TLD"
600a2351 68 fi
600a2351
DK
69 done
70
09fb9dcd
DK
71 if [ -z "$DNSdomainid" ]; then
72 # If domain ID is empty then something went wrong (top level
73 # domain not found at FreeDNS).
74 _err "Domain $top_domain not found at FreeDNS"
75 return 1
76 fi
77
e3ddb677
DK
78 # Add in new TXT record with the value provided
79 _debug "Adding TXT record for $fulldomain, $txtvalue"
80 _freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
81 return $?
600a2351
DK
82}
83
84#Usage: fulldomain txtvalue
85#Remove the txt record after validation.
86dns_freedns_rm() {
87 fulldomain="$1"
88 txtvalue="$2"
89
90 _info "Delete TXT record using FreeDNS"
91 _debug "fulldomain: $fulldomain"
92 _debug "txtvalue: $txtvalue"
93
94 # Need to read cookie from conf file again in case new value set
95 # during login to FreeDNS when TXT record was created.
2cb0b00e 96 FREEDNS_COOKIE="$(_readaccountconf "FREEDNS_COOKIE")"
600a2351
DK
97 _debug "FreeDNS login cookies: $FREEDNS_COOKIE"
98
09fb9dcd
DK
99 TXTdataid="$(_freedns_data_id "$fulldomain" "TXT")"
100 if [ "$?" != "0" ]; then
101 _info "Cannot delete TXT record for $fulldomain, record does not exist at FreeDNS"
102 return 1
103 fi
104 _debug "Data ID's found, $TXTdataid"
105
106 # now we have one (or more) TXT record data ID's. Load the page
107 # for that record and search for the record txt value. If match
108 # then we can delete it.
109 lines="$(echo "$TXTdataid" | wc -l)"
110 _debug "Found $lines TXT data records for $fulldomain"
111 i=0
112 while [ "$i" -lt "$lines" ]; do
113 i="$(_math "$i" + 1)"
114 dataid="$(echo "$TXTdataid" | sed -n "${i}p")"
115 _debug "$dataid"
116
117 htmlpage="$(_freedns_retrieve_data_page "$FREEDNS_COOKIE" "$dataid")"
600a2351 118 if [ "$?" != "0" ]; then
09fb9dcd
DK
119 if [ "$using_cached_cookies" = "true" ]; then
120 _err "Has your FreeDNS username and password changed? If so..."
121 _err "Please export as FREEDNS_User / FREEDNS_Password and try again."
122 fi
600a2351
DK
123 return 1
124 fi
125
09fb9dcd
DK
126 echo "$htmlpage" | grep "value=\""$txtvalue"\"" >/dev/null
127 if [ "$?" = "0" ]; then
128 # Found a match... delete the record and return
129 _info "Deleting TXT record for $fulldomain, $txtvalue"
130 _freedns_delete_txt_record "$FREEDNS_COOKIE" "$dataid"
131 return $?
132 fi
600a2351
DK
133 done
134
09fb9dcd 135 # If we get this far we did not find a match
600a2351 136 # Not necessarily an error, but log anyway.
e3ddb677 137 _info "Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS"
600a2351
DK
138 return 0
139}
140
141#################### Private functions below ##################################
142
143# usage: _freedns_login username password
144# print string "cookie=value" etc.
145# returns 0 success
146_freedns_login() {
87f5ec5b 147 export _H1="Accept-Language:en-US"
600a2351
DK
148 username="$1"
149 password="$2"
150 url="https://freedns.afraid.org/zc.php?step=2"
151
152 _debug "Login to FreeDNS as user $username"
153
154 htmlpage="$(_post "username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth" "$url")"
155
156 if [ "$?" != "0" ]; then
157 _err "FreeDNS login failed for user $username bad RC from _post"
158 return 1
159 fi
160
161 cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
162
163 # if cookies is not empty then logon successful
164 if [ -z "$cookies" ]; then
e3ddb677 165 _debug3 "htmlpage: $htmlpage"
600a2351
DK
166 _err "FreeDNS login failed for user $username. Check $HTTP_HEADER file"
167 return 1
168 fi
169
170 printf "%s" "$cookies"
171 return 0
172}
173
174# usage _freedns_retrieve_subdomain_page login_cookies
175# echo page retrieved (html)
176# returns 0 success
177_freedns_retrieve_subdomain_page() {
178 export _H1="Cookie:$1"
87f5ec5b 179 export _H2="Accept-Language:en-US"
600a2351
DK
180 url="https://freedns.afraid.org/subdomain/"
181
7f32488b 182 _debug "Retrieve subdomain page from FreeDNS"
600a2351
DK
183
184 htmlpage="$(_get "$url")"
185
186 if [ "$?" != "0" ]; then
7f32488b 187 _err "FreeDNS retrieve subdomains failed bad RC from _get"
600a2351 188 return 1
f78b656f 189 elif [ -z "$htmlpage" ]; then
600a2351
DK
190 _err "FreeDNS returned empty subdomain page"
191 return 1
192 fi
193
e3ddb677 194 _debug3 "htmlpage: $htmlpage"
600a2351
DK
195
196 printf "%s" "$htmlpage"
197 return 0
198}
199
09fb9dcd
DK
200# usage _freedns_retrieve_data_page login_cookies data_id
201# echo page retrieved (html)
202# returns 0 success
203_freedns_retrieve_data_page() {
204 export _H1="Cookie:$1"
205 export _H2="Accept-Language:en-US"
206 data_id="$2"
207 url="https://freedns.afraid.org/subdomain/edit.php?data_id=$2"
208
209 _debug "Retrieve data page for ID $data_id from FreeDNS"
210
211 htmlpage="$(_get "$url")"
212
213 if [ "$?" != "0" ]; then
214 _err "FreeDNS retrieve data page failed bad RC from _get"
215 return 1
216 elif [ -z "$htmlpage" ]; then
217 _err "FreeDNS returned empty data page"
218 return 1
219 fi
220
221 _debug3 "htmlpage: $htmlpage"
222
223 printf "%s" "$htmlpage"
224 return 0
225}
226
600a2351
DK
227# usage _freedns_add_txt_record login_cookies domain_id subdomain value
228# returns 0 success
229_freedns_add_txt_record() {
230 export _H1="Cookie:$1"
87f5ec5b 231 export _H2="Accept-Language:en-US"
600a2351
DK
232 domain_id="$2"
233 subdomain="$3"
234 value="$(printf '%s' "$4" | _url_encode)"
912bcf94 235 url="https://freedns.afraid.org/subdomain/save.php?step=2"
600a2351
DK
236
237 htmlpage="$(_post "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")"
238
239 if [ "$?" != "0" ]; then
240 _err "FreeDNS failed to add TXT record for $subdomain bad RC from _post"
241 return 1
f78b656f 242 elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then
e3ddb677 243 _debug3 "htmlpage: $htmlpage"
600a2351
DK
244 _err "FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
245 return 1
f78b656f 246 elif _contains "$htmlpage" "security code was incorrect"; then
e3ddb677 247 _debug3 "htmlpage: $htmlpage"
00777a10 248 _err "FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code"
f78b656f
DK
249 _err "Note that you cannot use automatic DNS validation for FreeDNS public domains"
250 return 1
600a2351 251 fi
f78b656f 252
e3ddb677 253 _debug3 "htmlpage: $htmlpage"
600a2351
DK
254 _info "Added acme challenge TXT record for $fulldomain at FreeDNS"
255 return 0
256}
257
258# usage _freedns_delete_txt_record login_cookies data_id
259# returns 0 success
260_freedns_delete_txt_record() {
261 export _H1="Cookie:$1"
87f5ec5b 262 export _H2="Accept-Language:en-US"
600a2351
DK
263 data_id="$2"
264 url="https://freedns.afraid.org/subdomain/delete2.php"
265
266 htmlheader="$(_get "$url?data_id%5B%5D=$data_id&submit=delete+selected" "onlyheader")"
267
268 if [ "$?" != "0" ]; then
269 _err "FreeDNS failed to delete TXT record for $data_id bad RC from _get"
270 return 1
f78b656f 271 elif ! _contains "$htmlheader" "200 OK"; then
e3ddb677 272 _debug2 "htmlheader: $htmlheader"
600a2351
DK
273 _err "FreeDNS failed to delete TXT record $data_id"
274 return 1
275 fi
276
277 _info "Deleted acme challenge TXT record for $fulldomain at FreeDNS"
278 return 0
279}
09fb9dcd
DK
280
281# usage _freedns_domain_id domain_name
282# echo the domain_id if found
283# return 0 success
284_freedns_domain_id() {
285 # Start by escaping the dots in the domain name
286 search_domain="$(echo "$1" | sed 's/\./\\./g')"
287
288 # Sometimes FreeDNS does not return the subdomain page but rather
289 # returns a page regarding becoming a premium member. This usually
290 # happens after a period of inactivity. Immediately trying again
291 # returns the correct subdomain page. So, we will try twice to
292 # load the page and obtain our domain ID
293 attempts=2
294 while [ "$attempts" -gt "0" ]; do
295 attempts="$(_math "$attempts" - 1)"
296
297 htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
298 if [ "$?" != "0" ]; then
299 if [ "$using_cached_cookies" = "true" ]; then
300 _err "Has your FreeDNS username and password changed? If so..."
301 _err "Please export as FREEDNS_User / FREEDNS_Password and try again."
302 fi
303 return 1
304 fi
305
19c43451 306 domain_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' |
307 grep "<td>$search_domain</td>\|<td>$search_domain(.*)</td>" |
308 sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' |
309 cut -d = -f 2)"
09fb9dcd
DK
310 # The above beauty extracts domain ID from the html page...
311 # strip out all blank space and new lines. Then insert newlines
312 # before each table row <tr>
313 # search for the domain within each row (which may or may not have
314 # a text string in brackets (.*) after it.
315 # And finally extract the domain ID.
316 if [ -n "$domain_id" ]; then
317 printf "%s" "$domain_id"
318 return 0
319 fi
320 _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)"
321 done
66c39a95 322 _debug "Domain $search_domain not found after retry"
09fb9dcd
DK
323 return 1
324}
325
326# usage _freedns_data_id domain_name record_type
327# echo the data_id(s) if found
328# return 0 success
329_freedns_data_id() {
330 # Start by escaping the dots in the domain name
331 search_domain="$(echo "$1" | sed 's/\./\\./g')"
332 record_type="$2"
333
334 # Sometimes FreeDNS does not return the subdomain page but rather
335 # returns a page regarding becoming a premium member. This usually
336 # happens after a period of inactivity. Immediately trying again
337 # returns the correct subdomain page. So, we will try twice to
338 # load the page and obtain our domain ID
339 attempts=2
340 while [ "$attempts" -gt "0" ]; do
341 attempts="$(_math "$attempts" - 1)"
342
343 htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
344 if [ "$?" != "0" ]; then
345 if [ "$using_cached_cookies" = "true" ]; then
346 _err "Has your FreeDNS username and password changed? If so..."
347 _err "Please export as FREEDNS_User / FREEDNS_Password and try again."
348 fi
349 return 1
350 fi
10994d65 351
19c43451 352 data_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' |
353 grep "<td[a-zA-Z=#]*>$record_type</td>" |
354 grep "<ahref.*>$search_domain</a>" |
355 sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' |
356 cut -d = -f 2)"
09fb9dcd
DK
357 # The above beauty extracts data ID from the html page...
358 # strip out all blank space and new lines. Then insert newlines
359 # before each table row <tr>
360 # search for the record type withing each row (e.g. TXT)
361 # search for the domain within each row (which is within a <a..>
ac9f6e3a 362 # </a> anchor. And finally extract the domain ID.
09fb9dcd
DK
363 if [ -n "$data_id" ]; then
364 printf "%s" "$data_id"
365 return 0
366 fi
367 _debug "Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)"
368 done
66c39a95 369 _debug "Domain $search_domain not found after retry"
09fb9dcd
DK
370 return 1
371}