@@ -4,40 +4,43 @@ import (
4
4
"context"
5
5
"crypto/tls"
6
6
"encoding/json"
7
+ "errors"
7
8
"fmt"
8
9
"github.com/libdns/libdns"
9
10
"io"
10
11
"log"
11
12
"net/http"
12
13
"net/url"
13
- "runtime"
14
14
"strconv"
15
15
"strings"
16
16
)
17
17
18
18
func (p * Provider ) getZoneRecords (ctx context.Context , zone string ) ([]libdns.Record , error ) {
19
- callerSkipDepth := 2
20
-
21
19
reqURL , err := url .Parse (p .ServerURL )
22
20
if err != nil {
23
- fmt .Printf ("[%s] failed to parse server url: %v\n " , p . caller ( callerSkipDepth ) , err )
21
+ fmt .Printf ("failed to parse server url: %v\n " , err )
24
22
return nil , err
25
23
}
26
24
25
+ rootZone , err := p .findRoot (ctx , zone )
26
+ if err != nil {
27
+ rootZone = zone
28
+ }
29
+
27
30
reqURL .Path = "/CMD_API_DNS_CONTROL"
28
31
29
32
queryString := make (url.Values )
30
33
queryString .Set ("json" , "yes" )
31
34
queryString .Set ("full_mx_records" , "yes" )
32
35
queryString .Set ("allow_dns_underscore" , "yes" )
33
36
queryString .Set ("ttl" , "yes" )
34
- queryString .Set ("domain" , zone )
37
+ queryString .Set ("domain" , rootZone )
35
38
36
39
reqURL .RawQuery = queryString .Encode ()
37
40
38
41
req , err := http .NewRequestWithContext (ctx , http .MethodGet , reqURL .String (), nil )
39
42
if err != nil {
40
- fmt .Printf ("[%s] failed to build new request: %v\n " , p . caller ( callerSkipDepth ) , err )
43
+ fmt .Printf ("failed to build new request: %v\n " , err )
41
44
return nil , err
42
45
}
43
46
@@ -52,35 +55,35 @@ func (p *Provider) getZoneRecords(ctx context.Context, zone string) ([]libdns.Re
52
55
53
56
resp , err := client .Do (req )
54
57
if err != nil {
55
- fmt .Printf ("[%s] failed to execute request: %v\n " , p . caller ( callerSkipDepth ) , err )
58
+ fmt .Printf ("failed to execute request: %v\n " , err )
56
59
return nil , err
57
60
}
58
61
defer func (Body io.ReadCloser ) {
59
62
err := Body .Close ()
60
63
if err != nil {
61
- fmt .Printf ("[%s] failed to close body: %v\n " , p . caller ( callerSkipDepth ) , err )
64
+ fmt .Printf ("failed to close body: %v\n " , err )
62
65
}
63
66
}(resp .Body )
64
67
65
68
if resp .StatusCode != http .StatusOK {
66
- fmt .Printf ("[%s] api response error, status code: %v\n " , p . caller ( callerSkipDepth ) , resp .StatusCode )
69
+ fmt .Printf ("api response error, status code: %v\n " , resp .StatusCode )
67
70
return nil , err
68
71
}
69
72
70
73
var respData daZone
71
74
err = json .NewDecoder (resp .Body ).Decode (& respData )
72
75
if err != nil {
73
- fmt .Printf ("[%s] failed to json decode response: %v\n " , p . caller ( callerSkipDepth ) , err )
76
+ fmt .Printf ("failed to json decode response: %v\n " , err )
74
77
return nil , err
75
78
}
76
79
77
80
recs := make ([]libdns.Record , 0 , len (respData .Records ))
78
81
for i := range respData .Records {
79
82
libDnsRecord , err := respData .Records [i ].libdnsRecord (zone )
80
83
if err != nil {
81
- switch err {
82
- case ErrUnsupported :
83
- fmt .Printf ("[%s] unsupported record conversion of type %v: %v\n " , p . caller ( callerSkipDepth ) , libDnsRecord .Type , libDnsRecord .Name )
84
+ switch {
85
+ case errors . Is ( err , ErrUnsupported ) :
86
+ fmt .Printf ("unsupported record conversion of type %v: %v\n " , libDnsRecord .Type , libDnsRecord .Name )
84
87
continue
85
88
default :
86
89
return nil , err
@@ -98,18 +101,23 @@ func (p *Provider) appendZoneRecord(ctx context.Context, zone string, record lib
98
101
99
102
reqURL , err := url .Parse (p .ServerURL )
100
103
if err != nil {
101
- fmt .Printf ("[%s] failed to parse server url: %v\n " , p . caller ( 2 ) , err )
104
+ fmt .Printf ("failed to parse server url: %v\n " , err )
102
105
return libdns.Record {}, err
103
106
}
104
107
108
+ rootZone , err := p .findRoot (ctx , zone )
109
+ if err != nil {
110
+ rootZone = zone
111
+ }
112
+
105
113
reqURL .Path = "/CMD_API_DNS_CONTROL"
106
114
107
115
queryString := make (url.Values )
108
116
queryString .Set ("action" , "add" )
109
117
queryString .Set ("json" , "yes" )
110
118
queryString .Set ("full_mx_records" , "yes" )
111
119
queryString .Set ("allow_dns_underscore" , "yes" )
112
- queryString .Set ("domain" , zone )
120
+ queryString .Set ("domain" , rootZone )
113
121
queryString .Set ("type" , record .Type )
114
122
queryString .Set ("name" , record .Name )
115
123
queryString .Set ("value" , record .Value )
@@ -120,7 +128,7 @@ func (p *Provider) appendZoneRecord(ctx context.Context, zone string, record lib
120
128
121
129
reqURL .RawQuery = queryString .Encode ()
122
130
123
- err = p .executeRequest (ctx , http .MethodGet , reqURL .String ())
131
+ err = p .executeJsonRequest (ctx , http .MethodGet , reqURL .String ())
124
132
if err != nil {
125
133
return libdns.Record {}, err
126
134
}
@@ -136,16 +144,21 @@ func (p *Provider) setZoneRecord(ctx context.Context, zone string, record libdns
136
144
137
145
reqURL , err := url .Parse (p .ServerURL )
138
146
if err != nil {
139
- fmt .Printf ("[%s] failed to parse server url: %v\n " , p . caller ( 2 ) , err )
147
+ fmt .Printf ("failed to parse server url: %v\n " , err )
140
148
return libdns.Record {}, err
141
149
}
142
150
151
+ rootZone , err := p .findRoot (ctx , zone )
152
+ if err != nil {
153
+ rootZone = zone
154
+ }
155
+
143
156
reqURL .Path = "/CMD_API_DNS_CONTROL"
144
157
145
158
queryString := make (url.Values )
146
159
queryString .Set ("action" , "edit" )
147
160
queryString .Set ("json" , "yes" )
148
- queryString .Set ("domain" , zone )
161
+ queryString .Set ("domain" , rootZone )
149
162
queryString .Set ("type" , record .Type )
150
163
queryString .Set ("name" , record .Name )
151
164
queryString .Set ("value" , record .Value )
@@ -173,7 +186,7 @@ func (p *Provider) setZoneRecord(ctx context.Context, zone string, record libdns
173
186
174
187
reqURL .RawQuery = queryString .Encode ()
175
188
176
- err = p .executeRequest (ctx , http .MethodGet , reqURL .String ())
189
+ err = p .executeJsonRequest (ctx , http .MethodGet , reqURL .String ())
177
190
if err != nil {
178
191
return libdns.Record {}, err
179
192
}
@@ -189,40 +202,116 @@ func (p *Provider) deleteZoneRecord(ctx context.Context, zone string, record lib
189
202
190
203
reqURL , err := url .Parse (p .ServerURL )
191
204
if err != nil {
192
- fmt .Printf ("[%s] failed to parse server url: %v\n " , p . caller ( 2 ) , err )
205
+ fmt .Printf ("failed to parse server url: %v\n " , err )
193
206
return libdns.Record {}, err
194
207
}
195
208
209
+ rootZone , err := p .findRoot (ctx , zone )
210
+ if err != nil {
211
+ rootZone = zone
212
+ }
213
+
196
214
reqURL .Path = "/CMD_API_DNS_CONTROL"
197
215
198
216
queryString := make (url.Values )
199
217
queryString .Set ("action" , "select" )
200
218
queryString .Set ("json" , "yes" )
201
- queryString .Set ("domain" , zone )
219
+ queryString .Set ("domain" , rootZone )
202
220
203
221
editKey := fmt .Sprintf ("%vrecs0" , strings .ToLower (record .Type ))
204
222
editValue := fmt .Sprintf ("name=%v&value=%v" , record .Name , record .Value )
205
223
queryString .Set (editKey , editValue )
206
224
207
225
reqURL .RawQuery = queryString .Encode ()
208
226
209
- err = p .executeRequest (ctx , http .MethodGet , reqURL .String ())
227
+ err = p .executeJsonRequest (ctx , http .MethodGet , reqURL .String ())
210
228
if err != nil {
211
229
return libdns.Record {}, err
212
230
}
213
231
214
232
return record , nil
215
233
}
216
234
217
- func (p * Provider ) executeRequest (ctx context.Context , method , url string ) error {
218
- callerSkipDepth := 3
235
+ func (p * Provider ) findRoot (ctx context.Context , zone string ) (string , error ) {
236
+ reqURL , err := url .Parse (p .ServerURL )
237
+ if err != nil {
238
+ fmt .Printf ("failed to parse server url: %v\n " , err )
239
+ return "" , err
240
+ }
241
+
242
+ reqURL .Path = "/CMD_API_SHOW_DOMAINS"
219
243
220
- req , err := http .NewRequestWithContext (ctx , method , url , nil )
244
+ resp , err := p .executeQueryRequest (ctx , http .MethodGet , reqURL .String ())
245
+ if err != nil {
246
+ return "" , err
247
+ }
248
+
249
+ zoneParts := strings .Split (zone , "." )
250
+
251
+ // Limit to 100 rounds
252
+ for i := 0 ; i < 100 ; i ++ {
253
+ for _ , value := range resp {
254
+ if value == strings .Join (zoneParts , "." ) {
255
+ return value , nil
256
+ }
257
+ }
258
+
259
+ zoneParts = zoneParts [1 :]
260
+ }
261
+
262
+ return "" , errors .New ("root zone not found" )
263
+ }
264
+
265
+ func (p * Provider ) executeJsonRequest (ctx context.Context , method , requestUrl string ) error {
266
+ resp , err := p .doRequest (ctx , method , requestUrl )
221
267
if err != nil {
222
- fmt .Printf ("[%s] failed to build new request: %v\n " , p .caller (callerSkipDepth ), err )
223
268
return err
224
269
}
225
270
271
+ var respData daResponse
272
+ err = json .Unmarshal (resp , & respData )
273
+ if err != nil {
274
+ fmt .Printf ("failed to json decode response: %v\n " , err )
275
+ return err
276
+ }
277
+
278
+ if len (respData .Error ) > 0 {
279
+ trimmedResult := strings .Split (respData .Result , "\n " )[0 ]
280
+ fmt .Printf ("api response error: %v: %v\n " , respData .Error , trimmedResult )
281
+ return fmt .Errorf ("api response error: %v: %v\n " , respData .Error , trimmedResult )
282
+ }
283
+
284
+ return nil
285
+ }
286
+
287
+ func (p * Provider ) executeQueryRequest (ctx context.Context , method , requestUrl string ) ([]string , error ) {
288
+ resp , err := p .doRequest (ctx , method , requestUrl )
289
+ if err != nil {
290
+ return nil , err
291
+ }
292
+
293
+ params , err := url .ParseQuery (string (resp ))
294
+ if err != nil {
295
+ return nil , err
296
+ }
297
+
298
+ var domains []string
299
+ for _ , param := range params {
300
+ for _ , domain := range param {
301
+ domains = append (domains , domain )
302
+ }
303
+ }
304
+
305
+ return domains , nil
306
+ }
307
+
308
+ func (p * Provider ) doRequest (ctx context.Context , method , url string ) ([]byte , error ) {
309
+ req , err := http .NewRequestWithContext (ctx , method , url , nil )
310
+ if err != nil {
311
+ fmt .Printf ("failed to build new request: %v\n " , err )
312
+ return nil , err
313
+ }
314
+
226
315
req .SetBasicAuth (p .User , p .LoginKey )
227
316
228
317
client := & http.Client {
@@ -234,48 +323,32 @@ func (p *Provider) executeRequest(ctx context.Context, method, url string) error
234
323
235
324
resp , err := client .Do (req )
236
325
if err != nil {
237
- fmt .Printf ("[%s] failed to execute request: %v\n " , p . caller ( callerSkipDepth ) , err )
238
- return err
326
+ fmt .Printf ("failed to execute request: %v\n " , err )
327
+ return nil , err
239
328
}
240
329
defer func (Body io.ReadCloser ) {
241
330
err := Body .Close ()
242
331
if err != nil {
243
- fmt .Printf ("[%s] failed to close body: %v\n " , p . caller ( callerSkipDepth ) , err )
332
+ fmt .Printf ("failed to close body: %v\n " , err )
244
333
}
245
334
}(resp .Body )
246
335
247
- var respData daResponse
248
- err = json .NewDecoder (resp .Body ).Decode (& respData )
249
- if err != nil {
250
- fmt .Printf ("[%s] failed to json decode response: %v\n " , p .caller (callerSkipDepth ), err )
251
- return err
252
- }
253
-
254
- if len (respData .Error ) > 0 {
255
- trimmedResult := strings .Split (respData .Result , "\n " )[0 ]
256
- fmt .Printf ("[%s] api response error: %v: %v\n " , p .caller (callerSkipDepth ), respData .Error , trimmedResult )
257
- return fmt .Errorf ("[%s] api response error: %v: %v\n " , p .caller (callerSkipDepth ), respData .Error , trimmedResult )
258
- }
259
-
260
336
if resp .StatusCode != http .StatusOK {
261
337
bodyBytes , err := io .ReadAll (resp .Body )
262
338
if err != nil {
263
- fmt .Printf ("[%s] failed to read response body: %v\n " , p . caller ( callerSkipDepth ) , err )
264
- return err
339
+ fmt .Printf ("failed to read response body: %v\n " , err )
340
+ return nil , err
265
341
}
266
342
bodyString := string (bodyBytes )
267
343
log .Println (bodyString )
268
344
269
- return err
345
+ return nil , err
270
346
}
271
347
272
- return nil
273
- }
348
+ bodyBytes , err := io .ReadAll (resp .Body )
349
+ if err != nil {
350
+ return nil , err
351
+ }
274
352
275
- func (p * Provider ) caller (skip int ) string {
276
- pc := make ([]uintptr , 15 )
277
- n := runtime .Callers (skip , pc )
278
- frames := runtime .CallersFrames (pc [:n ])
279
- frame , _ := frames .Next ()
280
- return frame .Function
353
+ return bodyBytes , nil
281
354
}
0 commit comments