@@ -2,169 +2,217 @@ package ddns
2
2
3
3
import (
4
4
"bytes"
5
- "encoding/json"
6
5
"fmt"
7
6
"io"
8
7
"log"
9
8
"net/http"
9
+ "net/url"
10
+
11
+ "github.com/naiba/nezha/pkg/utils"
10
12
)
11
13
14
+ const baseEndpoint = "https://api.cloudflare.com/client/v4/zones"
15
+
12
16
type ProviderCloudflare struct {
13
- Secret string
17
+ secret string
18
+ zoneId string
19
+ recordId string
20
+ domainConfig * DomainConfig
21
+ }
22
+
23
+ type cfReq struct {
24
+ Name string `json:"name"`
25
+ Type string `json:"type"`
26
+ Content string `json:"content"`
27
+ TTL uint32 `json:"ttl"`
28
+ Proxied bool `json:"proxied"`
29
+ }
30
+
31
+ type cfResp struct {
32
+ Result []struct {
33
+ ID string `json:"id"`
34
+ Name string `json:"name"`
35
+ } `json:"result"`
36
+ }
37
+
38
+ func NewProviderCloudflare (s string ) * ProviderCloudflare {
39
+ return & ProviderCloudflare {
40
+ secret : s ,
41
+ }
14
42
}
15
43
16
- func (provider * ProviderCloudflare ) UpdateDomain (domainConfig * DomainConfig ) bool {
44
+ func (provider * ProviderCloudflare ) UpdateDomain (domainConfig * DomainConfig ) error {
17
45
if domainConfig == nil {
18
- return false
46
+ return fmt . Errorf ( "获取 DDNS 配置失败" )
19
47
}
48
+ provider .domainConfig = domainConfig
20
49
21
- zoneID , err := provider .getZoneID (domainConfig . FullDomain )
50
+ err := provider .getZoneID ()
22
51
if err != nil {
23
- log .Printf ("无法获取 zone ID: %s\n " , err )
24
- return false
52
+ return fmt .Errorf ("无法获取 zone ID: %s" , err )
25
53
}
26
54
27
55
// 当IPv4和IPv6同时成功才算作成功
28
- var resultV4 = true
29
- var resultV6 = true
30
- if domainConfig .EnableIPv4 {
31
- if ! provider .addDomainRecord (zoneID , domainConfig , true ) {
32
- resultV4 = false
56
+ if provider .domainConfig .EnableIPv4 {
57
+ if err = provider .addDomainRecord (true ); err != nil {
58
+ return err
33
59
}
34
60
}
35
61
36
- if domainConfig .EnableIpv6 {
37
- if ! provider .addDomainRecord (zoneID , domainConfig , false ) {
38
- resultV6 = false
62
+ if provider . domainConfig .EnableIpv6 {
63
+ if err = provider .addDomainRecord (false ); err != nil {
64
+ return err
39
65
}
40
66
}
41
67
42
- return resultV4 && resultV6
68
+ return nil
43
69
}
44
70
45
- func (provider * ProviderCloudflare ) addDomainRecord (zoneID string , domainConfig * DomainConfig , isIpv4 bool ) bool {
46
- record , err := provider .findDNSRecord (zoneID , domainConfig . FullDomain , isIpv4 )
71
+ func (provider * ProviderCloudflare ) addDomainRecord (isIpv4 bool ) error {
72
+ err := provider .findDNSRecord (isIpv4 )
47
73
if err != nil {
48
- log .Printf ("查找 DNS 记录时出错: %s\n " , err )
49
- return false
74
+ return fmt .Errorf ("查找 DNS 记录时出错: %s" , err )
50
75
}
51
76
52
- if record == nil {
77
+ if provider . recordId == "" {
53
78
// 添加 DNS 记录
54
- return provider .createDNSRecord (zoneID , domainConfig , isIpv4 )
79
+ return provider .createDNSRecord (isIpv4 )
55
80
} else {
56
81
// 更新 DNS 记录
57
- return provider .updateDNSRecord (zoneID , record [ "id" ].( string ), domainConfig , isIpv4 )
82
+ return provider .updateDNSRecord (isIpv4 )
58
83
}
59
84
}
60
85
61
- func (provider * ProviderCloudflare ) getZoneID (domain string ) (string , error ) {
62
- _ , realDomain := SplitDomain (domain )
63
- url := fmt .Sprintf ("https://api.cloudflare.com/client/v4/zones?name=%s" , realDomain )
64
- body , err := provider .sendRequest ("GET" , url , nil )
86
+ func (provider * ProviderCloudflare ) getZoneID () error {
87
+ _ , realDomain := splitDomain (provider .domainConfig .FullDomain )
88
+ zu , _ := url .Parse (baseEndpoint )
89
+
90
+ q := zu .Query ()
91
+ q .Set ("name" , realDomain )
92
+ zu .RawQuery = q .Encode ()
93
+
94
+ body , err := provider .sendRequest ("GET" , zu .String (), nil )
65
95
if err != nil {
66
- return "" , err
96
+ return err
67
97
}
68
98
69
- var res map [ string ] interface {}
70
- err = json . Unmarshal (body , & res )
99
+ res := & cfResp {}
100
+ err = utils . Json . Unmarshal (body , res )
71
101
if err != nil {
72
- return "" , err
102
+ return err
73
103
}
74
104
75
- result := res [ "result" ].([] interface {})
105
+ result := res . Result
76
106
if len (result ) > 0 {
77
- zoneID : = result [0 ].( map [ string ] interface {})[ "id" ].( string )
78
- return zoneID , nil
107
+ provider . zoneId = result [0 ].ID
108
+ return nil
79
109
}
80
110
81
- return "" , fmt .Errorf ("找不到 Zone ID" )
111
+ return fmt .Errorf ("找不到 Zone ID" )
82
112
}
83
113
84
- func (provider * ProviderCloudflare ) findDNSRecord (zoneID string , domain string , isIPv4 bool ) (map [string ]interface {}, error ) {
85
- var ipType = "A"
86
- if ! isIPv4 {
114
+ func (provider * ProviderCloudflare ) findDNSRecord (isIPv4 bool ) error {
115
+ var ipType string
116
+ if isIPv4 {
117
+ ipType = "A"
118
+ } else {
87
119
ipType = "AAAA"
88
120
}
89
- url := fmt .Sprintf ("https://api.cloudflare.com/client/v4/zones/%s/dns_records?type=%s&name=%s" , zoneID , ipType , domain )
90
- body , err := provider .sendRequest ("GET" , url , nil )
121
+
122
+ de , _ := url .JoinPath (baseEndpoint , provider .zoneId , "dns_records" )
123
+ du , _ := url .Parse (de )
124
+
125
+ q := du .Query ()
126
+ q .Set ("name" , provider .domainConfig .FullDomain )
127
+ q .Set ("type" , ipType )
128
+ du .RawQuery = q .Encode ()
129
+
130
+ body , err := provider .sendRequest ("GET" , du .String (), nil )
91
131
if err != nil {
92
- return nil , err
132
+ return err
93
133
}
94
134
95
- var res map [ string ] interface {}
96
- err = json . Unmarshal (body , & res )
135
+ res := & cfResp {}
136
+ err = utils . Json . Unmarshal (body , res )
97
137
if err != nil {
98
- return nil , err
138
+ return err
99
139
}
100
140
101
- result := res [ "result" ].([] interface {})
141
+ result := res . Result
102
142
if len (result ) > 0 {
103
- return result [0 ].(map [string ]interface {}), nil
143
+ provider .recordId = result [0 ].ID
144
+ return nil
104
145
}
105
146
106
- return nil , nil // 没有找到 DNS 记录
147
+ return nil
107
148
}
108
149
109
- func (provider * ProviderCloudflare ) createDNSRecord (zoneID string , domainConfig * DomainConfig , isIPv4 bool ) bool {
110
- var ipType = "A"
111
- var ipAddr = domainConfig .Ipv4Addr
112
- if ! isIPv4 {
150
+ func (provider * ProviderCloudflare ) createDNSRecord (isIPv4 bool ) error {
151
+ var ipType , ipAddr string
152
+ if isIPv4 {
153
+ ipType = "A"
154
+ ipAddr = provider .domainConfig .Ipv4Addr
155
+ } else {
113
156
ipType = "AAAA"
114
- ipAddr = domainConfig .Ipv6Addr
115
- }
116
- url := fmt .Sprintf ("https://api.cloudflare.com/client/v4/zones/%s/dns_records" , zoneID )
117
- data := map [string ]interface {}{
118
- "type" : ipType ,
119
- "name" : domainConfig .FullDomain ,
120
- "content" : ipAddr ,
121
- "ttl" : 60 ,
122
- "proxied" : false ,
123
- }
124
- jsonData , _ := json .Marshal (data )
125
- _ , err := provider .sendRequest ("POST" , url , jsonData )
126
- return err == nil
157
+ ipAddr = provider .domainConfig .Ipv6Addr
158
+ }
159
+
160
+ de , _ := url .JoinPath (baseEndpoint , provider .zoneId , "dns_records" )
161
+ data := & cfReq {
162
+ Name : provider .domainConfig .FullDomain ,
163
+ Type : ipType ,
164
+ Content : ipAddr ,
165
+ TTL : 60 ,
166
+ Proxied : false ,
167
+ }
168
+
169
+ jsonData , _ := utils .Json .Marshal (data )
170
+ _ , err := provider .sendRequest ("POST" , de , jsonData )
171
+ return err
127
172
}
128
173
129
- func (provider * ProviderCloudflare ) updateDNSRecord (zoneID string , recordID string , domainConfig * DomainConfig , isIPv4 bool ) bool {
130
- var ipType = "A"
131
- var ipAddr = domainConfig .Ipv4Addr
132
- if ! isIPv4 {
174
+ func (provider * ProviderCloudflare ) updateDNSRecord (isIPv4 bool ) error {
175
+ var ipType , ipAddr string
176
+ if isIPv4 {
177
+ ipType = "A"
178
+ ipAddr = provider .domainConfig .Ipv4Addr
179
+ } else {
133
180
ipType = "AAAA"
134
- ipAddr = domainConfig .Ipv6Addr
135
- }
136
- url := fmt .Sprintf ("https://api.cloudflare.com/client/v4/zones/%s/dns_records/%s" , zoneID , recordID )
137
- data := map [string ]interface {}{
138
- "type" : ipType ,
139
- "name" : domainConfig .FullDomain ,
140
- "content" : ipAddr ,
141
- "ttl" : 60 ,
142
- "proxied" : false ,
143
- }
144
- jsonData , _ := json .Marshal (data )
145
- _ , err := provider .sendRequest ("PATCH" , url , jsonData )
146
- return err == nil
181
+ ipAddr = provider .domainConfig .Ipv6Addr
182
+ }
183
+
184
+ de , _ := url .JoinPath (baseEndpoint , provider .zoneId , "dns_records" , provider .recordId )
185
+ data := & cfReq {
186
+ Name : provider .domainConfig .FullDomain ,
187
+ Type : ipType ,
188
+ Content : ipAddr ,
189
+ TTL : 60 ,
190
+ Proxied : false ,
191
+ }
192
+
193
+ jsonData , _ := utils .Json .Marshal (data )
194
+ _ , err := provider .sendRequest ("PATCH" , de , jsonData )
195
+ return err
147
196
}
148
197
149
198
// 以下为辅助方法,如发送 HTTP 请求等
150
199
func (provider * ProviderCloudflare ) sendRequest (method string , url string , data []byte ) ([]byte , error ) {
151
- client := & http.Client {}
152
200
req , err := http .NewRequest (method , url , bytes .NewBuffer (data ))
153
201
if err != nil {
154
202
return nil , err
155
203
}
156
204
157
- req .Header .Add ("Authorization" , fmt .Sprintf ("Bearer %s" , provider .Secret ))
205
+ req .Header .Add ("Authorization" , fmt .Sprintf ("Bearer %s" , provider .secret ))
158
206
req .Header .Add ("Content-Type" , "application/json" )
159
207
160
- resp , err := client .Do (req )
208
+ resp , err := utils . HttpClient .Do (req )
161
209
if err != nil {
162
210
return nil , err
163
211
}
164
212
defer func (Body io.ReadCloser ) {
165
213
err := Body .Close ()
166
214
if err != nil {
167
- log .Printf ("NEZHA>> 无法关闭HTTP响应体流: %s\n " , err .Error ())
215
+ log .Printf ("NEZHA>> 无法关闭HTTP响应体流: %s" , err .Error ())
168
216
}
169
217
}(resp .Body )
170
218
0 commit comments