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.
9 #Report Bugs here: https://github.com/dkerr64/acme.sh
10 #or here... https://github.com/acmesh-official/acme.sh/issues/2305
12 ######## Public functions #####################
14 # Export FreeDNS userid and password in following variables...
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.
20 #Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
25 _info
"Add TXT record using FreeDNS"
26 _debug
"fulldomain: $fulldomain"
27 _debug
"txtvalue: $txtvalue"
29 if [ -z "$FREEDNS_User" ] ||
[ -z "$FREEDNS_Password" ]; then
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."
37 using_cached_cookies
="true"
39 FREEDNS_COOKIE
="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")"
40 if [ -z "$FREEDNS_COOKIE" ]; then
43 using_cached_cookies
="false"
46 _debug
"FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)"
48 _saveaccountconf FREEDNS_COOKIE
"$FREEDNS_COOKIE"
50 # We may have to cycle through the domain name to find the
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")"
58 top_domain
="$(echo "$fulldomain" | cut -d. -f "$i"-100)"
59 _debug
"sub_domain: $sub_domain"
60 _debug
"top_domain: $top_domain"
62 DNSdomainid
="$(_freedns_domain_id "$top_domain")"
63 if [ "$?" = "0" ]; then
64 _info
"Domain $top_domain found at FreeDNS, domain_id $DNSdomainid"
67 _info
"Domain $top_domain not found at FreeDNS, try with next level of TLD"
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"
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"
84 #Usage: fulldomain txtvalue
85 #Remove the txt record after validation.
90 _info
"Delete TXT record using FreeDNS"
91 _debug
"fulldomain: $fulldomain"
92 _debug
"txtvalue: $txtvalue"
94 # Need to read cookie from conf file again in case new value set
95 # during login to FreeDNS when TXT record was created.
96 FREEDNS_COOKIE
="$(_readaccountconf "FREEDNS_COOKIE
")"
97 _debug
"FreeDNS login cookies: $FREEDNS_COOKIE"
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"
104 _debug
"Data ID's found, $TXTdataid"
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"
112 while [ "$i" -lt "$lines" ]; do
113 i
="$(_math "$i" + 1)"
114 dataid
="$(echo "$TXTdataid" | sed -n "${i}p
")"
117 htmlpage
="$(_freedns_retrieve_data_page "$FREEDNS_COOKIE" "$dataid")"
118 if [ "$?" != "0" ]; then
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."
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"
135 # If we get this far we did not find a match
136 # Not necessarily an error, but log anyway.
137 _info
"Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS"
141 #################### Private functions below ##################################
143 # usage: _freedns_login username password
144 # print string "cookie=value" etc.
147 export _H1
="Accept-Language:en-US"
150 url
="https://freedns.afraid.org/zc.php?step=2"
152 _debug
"Login to FreeDNS as user $username"
154 htmlpage
="$(_post "username
=$
(printf '%s' "$username" | _url_encode
)&password
=$
(printf '%s' "$password" | _url_encode
)&submit
=Login
&action
=auth
" "$url")"
156 if [ "$?" != "0" ]; then
157 _err
"FreeDNS login failed for user $username bad RC from _post"
161 cookies
="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
163 # if cookies is not empty then logon successful
164 if [ -z "$cookies" ]; then
165 _debug3
"htmlpage: $htmlpage"
166 _err
"FreeDNS login failed for user $username. Check $HTTP_HEADER file"
170 printf "%s" "$cookies"
174 # usage _freedns_retrieve_subdomain_page login_cookies
175 # echo page retrieved (html)
177 _freedns_retrieve_subdomain_page
() {
178 export _H1
="Cookie:$1"
179 export _H2
="Accept-Language:en-US"
180 url
="https://freedns.afraid.org/subdomain/"
182 _debug
"Retrieve subdomain page from FreeDNS"
184 htmlpage
="$(_get "$url")"
186 if [ "$?" != "0" ]; then
187 _err
"FreeDNS retrieve subdomains failed bad RC from _get"
189 elif [ -z "$htmlpage" ]; then
190 _err
"FreeDNS returned empty subdomain page"
194 _debug3
"htmlpage: $htmlpage"
196 printf "%s" "$htmlpage"
200 # usage _freedns_retrieve_data_page login_cookies data_id
201 # echo page retrieved (html)
203 _freedns_retrieve_data_page
() {
204 export _H1
="Cookie:$1"
205 export _H2
="Accept-Language:en-US"
207 url
="https://freedns.afraid.org/subdomain/edit.php?data_id=$2"
209 _debug
"Retrieve data page for ID $data_id from FreeDNS"
211 htmlpage
="$(_get "$url")"
213 if [ "$?" != "0" ]; then
214 _err
"FreeDNS retrieve data page failed bad RC from _get"
216 elif [ -z "$htmlpage" ]; then
217 _err
"FreeDNS returned empty data page"
221 _debug3
"htmlpage: $htmlpage"
223 printf "%s" "$htmlpage"
227 # usage _freedns_add_txt_record login_cookies domain_id subdomain value
229 _freedns_add_txt_record
() {
230 export _H1
="Cookie:$1"
231 export _H2
="Accept-Language:en-US"
234 value
="$(printf '%s' "$4" | _url_encode)"
235 url
="https://freedns.afraid.org/subdomain/save.php?step=2"
237 htmlpage
="$(_post "type=TXT
&domain_id
=$domain_id&subdomain
=$subdomain&address
=%22$value%22&send
=Save
%21" "$url")"
239 if [ "$?" != "0" ]; then
240 _err
"FreeDNS failed to add TXT record for $subdomain bad RC from _post"
242 elif ! grep "200 OK" "$HTTP_HEADER" >/dev
/null
; then
243 _debug3
"htmlpage: $htmlpage"
244 _err
"FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
246 elif _contains
"$htmlpage" "security code was incorrect"; then
247 _debug3
"htmlpage: $htmlpage"
248 _err
"FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code"
249 _err
"Note that you cannot use automatic DNS validation for FreeDNS public domains"
253 _debug3
"htmlpage: $htmlpage"
254 _info
"Added acme challenge TXT record for $fulldomain at FreeDNS"
258 # usage _freedns_delete_txt_record login_cookies data_id
260 _freedns_delete_txt_record
() {
261 export _H1
="Cookie:$1"
262 export _H2
="Accept-Language:en-US"
264 url
="https://freedns.afraid.org/subdomain/delete2.php"
266 htmlheader
="$(_get "$url?data_id
%5B
%5D
=$data_id&submit
=delete
+selected
" "onlyheader
")"
268 if [ "$?" != "0" ]; then
269 _err
"FreeDNS failed to delete TXT record for $data_id bad RC from _get"
271 elif ! _contains
"$htmlheader" "200 OK"; then
272 _debug2
"htmlheader: $htmlheader"
273 _err
"FreeDNS failed to delete TXT record $data_id"
277 _info
"Deleted acme challenge TXT record for $fulldomain at FreeDNS"
281 # usage _freedns_domain_id domain_name
282 # echo the domain_id if found
284 _freedns_domain_id
() {
285 # Start by escaping the dots in the domain name
286 search_domain
="$(echo "$1" | sed 's/\./\\./g')"
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
294 while [ "$attempts" -gt "0" ]; do
295 attempts
="$(_math "$attempts" - 1)"
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."
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' |
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"
320 _debug
"Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)"
322 _debug
"Domain $search_domain not found after retry"
326 # usage _freedns_data_id domain_name record_type
327 # echo the data_id(s) if found
330 # Start by escaping the dots in the domain name
331 search_domain
="$(echo "$1" | sed 's/\./\\./g')"
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
340 while [ "$attempts" -gt "0" ]; do
341 attempts
="$(_math "$attempts" - 1)"
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."
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' |
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..>
362 # </a> anchor. And finally extract the domain ID.
363 if [ -n "$data_id" ]; then
364 printf "%s
" "$data_id"
367 _debug "Domain
$search_domain not found. Retry loading subdomain page
($attempts attempts remaining
)"
369 _debug "Domain
$search_domain not found after retry
"