refact: alidns (#43)

重构alidns。包大小更小
This commit is contained in:
jeessy2
2021-02-25 17:01:28 +08:00
committed by GitHub
parent 867333a7c5
commit 5140d299dd
6 changed files with 239 additions and 108 deletions

View File

@ -1,28 +1,47 @@
package dns
import (
"bytes"
"ddns-go/config"
"ddns-go/util"
"log"
alidnssdk "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
"net/http"
"net/url"
"time"
)
// Alidns 阿里云dns实现
const (
alidnsEndpoint string = "https://alidns.aliyuncs.com/"
)
// Alidns Alidns
type Alidns struct {
client *alidnssdk.Client
Domains config.Domains
DNSConfig config.DNSConfig
Domains config.Domains
}
// AlidnsSubDomainRecords 记录
type AlidnsSubDomainRecords struct {
TotalCount int
DomainRecords struct {
Record []struct {
DomainName string
RecordID string
Value string
}
}
}
// AlidnsResp 修改/添加返回结果
type AlidnsResp struct {
RecordID string
RequestID string
}
// Init 初始化
func (ali *Alidns) Init(conf *config.Config) {
client, err := alidnssdk.NewClientWithAccessKey("cn-hangzhou", conf.DNS.ID, conf.DNS.Secret)
if err != nil {
log.Println("Alidns链接失败")
}
ali.client = client
ali.DNSConfig = conf.DNS
ali.Domains.ParseDomain(conf)
}
// AddUpdateDomainRecords 添加或更新IPv4/IPv6记录
@ -39,56 +58,100 @@ func (ali *Alidns) addUpdateDomainRecords(recordType string) {
return
}
existReq := alidnssdk.CreateDescribeSubDomainRecordsRequest()
existReq.Type = recordType
for _, domain := range domains {
existReq.SubDomain = domain.GetFullDomain()
rep, err := ali.client.DescribeSubDomainRecords(existReq)
var record AlidnsSubDomainRecords
// 获取当前域名信息
params := url.Values{}
params.Set("Action", "DescribeSubDomainRecords")
params.Set("SubDomain", domain.GetFullDomain())
params.Set("Type", recordType)
err := ali.request(params, &record)
if err != nil {
domain.UpdateStatus = config.UpdatedFailed
log.Println(err)
return
}
if rep.TotalCount > 0 {
// Update
for _, record := range rep.DomainRecords.Record {
if record.Value == ipAddr {
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
continue
}
request := alidnssdk.CreateUpdateDomainRecordRequest()
request.Scheme = "https"
request.Value = ipAddr
request.Type = recordType
request.RR = domain.GetSubDomain()
request.RecordId = record.RecordId
updateResp, err := ali.client.UpdateDomainRecord(request)
if err == nil && updateResp.BaseResponse.IsSuccess() {
log.Printf("更新域名解析 %s 成功IP: %s", domain, ipAddr)
domain.UpdateStatus = config.UpdatedSuccess
} else {
log.Printf("更新域名解析 %s 失败IP: %s, Error: %s, Response: %s", domain, ipAddr, err, updateResp.GetHttpContentString())
domain.UpdateStatus = config.UpdatedFailed
}
}
if record.TotalCount > 0 {
// 存在,更新
ali.modify(record, domain, recordType, ipAddr)
} else {
// Add
request := alidnssdk.CreateAddDomainRecordRequest()
request.Scheme = "https"
request.Value = ipAddr
request.Type = recordType
request.RR = domain.GetSubDomain()
request.DomainName = domain.DomainName
createResp, err := ali.client.AddDomainRecord(request)
if err == nil && createResp.BaseResponse.IsSuccess() {
log.Printf("新增域名解析 %s 成功IP: %s", domain, ipAddr)
domain.UpdateStatus = config.UpdatedSuccess
} else {
log.Printf("新增域名解析 %s 失败IP: %s, Error: %s, Response: %s", domain, ipAddr, err, createResp.GetHttpContentString())
domain.UpdateStatus = config.UpdatedFailed
}
// 不存在,创建
ali.create(domain, recordType, ipAddr)
}
}
}
// 创建
func (ali *Alidns) create(domain *config.Domain, recordType string, ipAddr string) {
params := url.Values{}
params.Set("Action", "AddDomainRecord")
params.Set("DomainName", domain.DomainName)
params.Set("RR", domain.GetSubDomain())
params.Set("Type", recordType)
params.Set("Value", ipAddr)
var result AlidnsResp
err := ali.request(params, &result)
if err == nil && "" != result.RecordID {
log.Printf("新增域名解析 %s 成功IP: %s", domain, ipAddr)
domain.UpdateStatus = config.UpdatedSuccess
} else {
log.Printf("新增域名解析 %s 失败!", domain)
domain.UpdateStatus = config.UpdatedFailed
}
}
// 修改
func (ali *Alidns) modify(record AlidnsSubDomainRecords, domain *config.Domain, recordType string, ipAddr string) {
// 相同不修改
if len(record.DomainRecords.Record) > 0 && record.DomainRecords.Record[0].Value == ipAddr {
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
return
}
params := url.Values{}
params.Set("Action", "UpdateDomainRecord")
params.Set("RR", domain.GetSubDomain())
params.Set("RecordId", record.DomainRecords.Record[0].RecordID)
params.Set("Type", recordType)
params.Set("Value", ipAddr)
var result AlidnsResp
err := ali.request(params, &result)
if err == nil && "" != result.RecordID {
log.Printf("更新域名解析 %s 成功IP: %s", domain, ipAddr)
domain.UpdateStatus = config.UpdatedSuccess
} else {
log.Printf("更新域名解析 %s 失败!", domain)
domain.UpdateStatus = config.UpdatedFailed
}
}
// request 统一请求接口
func (ali *Alidns) request(params url.Values, result interface{}) (err error) {
util.AliyunSigner(ali.DNSConfig.ID, ali.DNSConfig.Secret, &params)
req, err := http.NewRequest(
"GET",
alidnsEndpoint,
bytes.NewBuffer(nil),
)
req.URL.RawQuery = params.Encode()
if err != nil {
log.Println("http.NewRequest失败. Error: ", err)
return
}
clt := http.Client{}
clt.Timeout = 30 * time.Second
resp, err := clt.Do(req)
err = util.GetHTTPResponse(resp, alidnsEndpoint, err, result)
return
}

9
go.mod
View File

@ -2,11 +2,4 @@ module ddns-go
go 1.16
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.439
github.com/jmespath/go-jmespath v0.3.0 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
gopkg.in/ini.v1 v1.60.1 // indirect
gopkg.in/yaml.v2 v2.3.0
)
require gopkg.in/yaml.v2 v2.3.0

44
go.sum
View File

@ -1,46 +1,4 @@
github.com/aliyun/alibaba-cloud-sdk-go v1.61.439 h1:vRjH9EcYcCkVUwti0q6AKcO8vFqCqe3EQOQl1QK+1zw=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.439/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-bindata/go-bindata v1.0.0 h1:DZ34txDXWn1DyWa+vQf7V9ANc2ILTtrEjtlsdJRF26M=
github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE=
github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang/tools v0.0.0-20200826040757-bc8aaaa29e06 h1:o8QN2yZHpPfla7J9ZQpaypzCL6fyEGCsLYv1+FpWdJc=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.60.1 h1:P5y5shSkb0CFe44qEeMBgn8JLow09MP17jlJHanke5g=
gopkg.in/ini.v1 v1.60.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

97
util/aliyun_signer.go Normal file
View File

@ -0,0 +1,97 @@
package util
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"fmt"
"hash"
"io"
"net/url"
)
// https://github.com/rosbit/aliyun-sign/blob/master/aliyun-sign.go
var (
signMethodMap = map[string]func() hash.Hash{
"HMAC-SHA1": sha1.New,
"HMAC-SHA256": sha256.New,
"HMAC-MD5": md5.New,
}
)
func HmacSign(signMethod string, httpMethod string, appKeySecret string, vals url.Values) (signature []byte) {
key := []byte(appKeySecret + "&")
var h hash.Hash
if method, ok := signMethodMap[signMethod]; ok {
h = hmac.New(method, key)
} else {
h = hmac.New(sha1.New, key)
}
makeDataToSign(h, httpMethod, vals)
return h.Sum(nil)
}
func HmacSignToB64(signMethod string, httpMethod string, appKeySecret string, vals url.Values) (signature string) {
return base64.StdEncoding.EncodeToString(HmacSign(signMethod, httpMethod, appKeySecret, vals))
}
type strToEnc struct {
s string
e bool
}
func makeDataToSign(w io.Writer, httpMethod string, vals url.Values) {
in := make(chan *strToEnc)
go func() {
in <- &strToEnc{s: httpMethod}
in <- &strToEnc{s: "&"}
in <- &strToEnc{s: "/", e: true}
in <- &strToEnc{s: "&"}
in <- &strToEnc{s: vals.Encode(), e: true}
close(in)
}()
specialUrlEncode(in, w)
}
var (
encTilde = "%7E" // '~' -> "%7E"
encBlank = []byte("%20") // ' ' -> "%20"
tilde = []byte("~")
)
func specialUrlEncode(in <-chan *strToEnc, w io.Writer) {
for s := range in {
if !s.e {
io.WriteString(w, s.s)
continue
}
l := len(s.s)
for i := 0; i < l; {
ch := s.s[i]
switch ch {
case '%':
if encTilde == s.s[i:i+3] {
w.Write(tilde)
i += 3
continue
}
fallthrough
case '*', '/', '&', '=':
fmt.Fprintf(w, "%%%02X", ch)
case '+':
w.Write(encBlank)
default:
fmt.Fprintf(w, "%c", ch)
}
i += 1
}
}
}

View File

@ -0,0 +1,20 @@
package util
import (
"net/url"
"strconv"
"time"
)
// AliyunSigner AliyunSigner
func AliyunSigner(accessKeyID, accessSecret string, params *url.Values) {
// 公共参数
params.Set("SignatureMethod", "HMAC-SHA1")
params.Set("SignatureNonce", strconv.FormatInt(time.Now().UnixNano(), 10))
params.Set("AccessKeyId", accessKeyID)
params.Set("SignatureVersion", "1.0")
params.Set("Timestamp", time.Now().UTC().Format("2006-01-02T15:04:05Z"))
params.Set("Format", "JSON")
params.Set("Version", "2015-01-09")
params.Set("Signature", HmacSignToB64("HMAC-SHA1", "GET", accessSecret, *params))
}