Skip to content

Commit

Permalink
Add support for Dynadot. (#1050)
Browse files Browse the repository at this point in the history
* Add support for Dynadot.
* Fix incorrect logging/printing of errors.
  • Loading branch information
YangerStars committed Mar 22, 2024
1 parent 997c05e commit 77caa37
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 3 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -18,7 +18,7 @@
## 特性

- 支持Mac、Windows、Linux系统,支持ARM、x86架构
- 支持的域名服务商 `阿里云` `腾讯云` `Dnspod` `Cloudflare` `华为云` `Callback` `百度云` `Porkbun` `GoDaddy` `Google Domain` `Namecheap` `NameSilo`
- 支持的域名服务商 `阿里云` `腾讯云` `Dnspod` `Cloudflare` `华为云` `Callback` `百度云` `Porkbun` `GoDaddy` `Google Domain` `Namecheap` `NameSilo` `Dynadot`
- 支持接口/网卡/[命令](https://github.com/jeessy2/ddns-go/wiki/通过命令获取IP参考)获取IP
- 支持以服务的方式运行
- 默认间隔5分钟同步一次
Expand All @@ -43,7 +43,7 @@
- [可选] 服务卸载
- Mac/Linux: `sudo ./ddns-go -s uninstall`
- Win(以管理员打开cmd): `.\ddns-go.exe -s uninstall`
- [可选] 支持安装带参数
- [可选] 支持安装带参数
- `-l` 监听地址
- `-f` 同步间隔时间(秒)
- `-cacheTimes` 间隔N次与服务商比对
Expand Down
2 changes: 1 addition & 1 deletion README_EN.md
Expand Up @@ -16,7 +16,7 @@ Automatically obtain your public IPv4 or IPv6 address and resolve it to the corr
## Features

- Support Mac, Windows, Linux system, support ARM, x86 architecture
- Support domain service providers `Aliyun` `Tencent` `Dnspod` `Cloudflare` `Huawei` `Callback` `Baidu` `Porkbun` `GoDaddy` `Google Domain` `Namecheap` `NameSilo`
- Support domain service providers `Aliyun` `Tencent` `Dnspod` `Cloudflare` `Huawei` `Callback` `Baidu` `Porkbun` `GoDaddy` `Google Domain` `Namecheap` `NameSilo` `Dynadot`
- Support interface / netcard / command to get IP
- Support running as a service
- Default interval is 5 minutes
Expand Down
162 changes: 162 additions & 0 deletions dns/dynadot.go
@@ -0,0 +1,162 @@
package dns

import (
"bytes"
"github.com/jeessy2/ddns-go/v6/config"
"github.com/jeessy2/ddns-go/v6/util"
"net/http"
"net/url"
"strings"
)

// https://www.dynadot.com/set_ddns
const (
dynadotEndpoint string = "https://www.dynadot.com/set_ddns"
)

// Dynadot Dynadot
type Dynadot struct {
DNS config.DNS
Domains config.Domains
TTL string
}

// DynadotRecord record
type DynadotRecord struct {
DomainName string
SubDomainNames []string
CustomParams url.Values
Domains []*config.Domain
}

// DynadotResp 修改/添加返回结果
type DynadotResp struct {
Status string `json:"status"`
ErrorCode int `json:"error_code"`
Content []string `json:"content"`
}

// Init 初始化
func (dynadot *Dynadot) Init(dnsConf *config.DnsConfig, ipv4cache *util.IpCache, ipv6cache *util.IpCache) {
dynadot.Domains.Ipv4Cache = ipv4cache
dynadot.Domains.Ipv6Cache = ipv6cache
dynadot.DNS = dnsConf.DNS
dynadot.Domains.GetNewIp(dnsConf)
if dnsConf.TTL == "" {
// 默认600s
dynadot.TTL = "600"
} else {
dynadot.TTL = dnsConf.TTL
}
}

// AddUpdateDomainRecords 添加或更新IPv4/IPv6记录
func (dynadot *Dynadot) AddUpdateDomainRecords() config.Domains {
dynadot.addOrUpdateDomainRecords("A")
dynadot.addOrUpdateDomainRecords("AAAA")
return dynadot.Domains
}

// addOrUpdateDomainRecords 添加或更新记录
func (dynadot *Dynadot) addOrUpdateDomainRecords(recordType string) {
ipAddr, domains := dynadot.Domains.GetNewIpResult(recordType)

if len(ipAddr) == 0 {
return
}

records := mergeDomains(domains)
// dynadot 仅支持一个域名对应一个dynamic password
if len(records) != 1 {
util.Log("dynadot仅支持单域名配置,多个域名请添加更多配置")
return
}
for _, record := range records {
// 创建或更新
dynadot.createOrModify(record, recordType, ipAddr)
}
}

// 合并域名的子域名
func mergeDomains(domains []*config.Domain) (records []*DynadotRecord) {
records = make([]*DynadotRecord, 0)
for _, domain := range domains {
var record *DynadotRecord
for _, r := range records {
if r.DomainName == domain.DomainName {
record = r
params := domain.GetCustomParams()
for key := range params {
record.CustomParams.Add(key, params.Get(key))
}
record.Domains = append(record.Domains, domain)
record.SubDomainNames = append(record.SubDomainNames, domain.GetSubDomain())
break
}
}
if record == nil {
record = &DynadotRecord{
DomainName: domain.DomainName,
CustomParams: domain.GetCustomParams(),
Domains: []*config.Domain{domain},
SubDomainNames: []string{domain.GetSubDomain()},
}
records = append(records, record)
}
}
return records
}

// 创建或变更记录
func (dynadot *Dynadot) createOrModify(record *DynadotRecord, recordType string, ipAddr string) {
params := record.CustomParams
params.Set("domain", record.DomainName)
params.Set("subDomain", strings.Join(record.SubDomainNames, ","))
params.Set("type", recordType)
params.Set("ip", ipAddr)
params.Set("pwd", dynadot.DNS.Secret)
params.Set("ttl", dynadot.TTL)

var result DynadotResp
err := dynadot.request(params, &result)

domains := record.Domains
for _, domain := range domains {

if err != nil {
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, err)
domain.UpdateStatus = config.UpdatedFailed
return
}

if result.ErrorCode != -1 {
util.Log("更新域名解析 %s 成功! IP: %s", domain, ipAddr)
domain.UpdateStatus = config.UpdatedSuccess
} else {
util.Log("更新域名解析 %s 失败! 异常信息: %s", domain, strings.Join(result.Content, ","))
domain.UpdateStatus = config.UpdatedFailed
}
}

}

// request 统一请求接口
func (dynadot *Dynadot) request(params url.Values, result interface{}) (err error) {

req, err := http.NewRequest(
"GET",
dynadotEndpoint,
bytes.NewBuffer(nil),
)
req.URL.RawQuery = params.Encode()

if err != nil {
return
}

client := util.CreateHTTPClient()
resp, err := client.Do(req)
err = util.GetHTTPResponse(resp, err, result)

return
}
3 changes: 3 additions & 0 deletions dns/index.go
Expand Up @@ -27,6 +27,7 @@ var (
nameSiloListRecordEndpoint,
porkbunEndpoint,
tencentCloudEndPoint,
dynadotEndpoint,
}

Ipcache = [][2]util.IpCache{}
Expand Down Expand Up @@ -84,6 +85,8 @@ func RunOnce() {
dnsSelected = &NameSilo{}
case "vercel":
dnsSelected = &Vercel{}
case "dynadot":
dnsSelected = &Dynadot{}
default:
dnsSelected = &Alidns{}
}
Expand Down
11 changes: 11 additions & 0 deletions static/constant.js
Expand Up @@ -146,6 +146,17 @@ const DNS_PROVIDERS = {
"zh-cn": "<a target='_blank' href='https://vercel.com/account/tokens'>创建令牌</a>",
}
},
dynadot: {
name: {
"en": "Dynadot",
},
idLabel: "",
secretLabel: "Password",
helpHtml: {
"en": "<a target='_blank' href='https://www.dynadot.com/community/help/question/enable-DDNS'>How to get started</a>",
"zh-cn": "<a target='_blank' href='https://www.dynadot.com/community/help/question/enable-DDNS'>开启Dynadot动态域名解析</a>",
}
},
};

const SVG_CODE = {
Expand Down
2 changes: 2 additions & 0 deletions util/messages.go
Expand Up @@ -28,6 +28,8 @@ func init() {
message.SetString(language.English, "你的IPv6未变化, 未触发 %s 请求", "Your's IPv6 has not changed, %s request has not been triggered")
message.SetString(language.English, "Namecheap 不支持更新 IPv6", "Namecheap don't supports IPv6")

message.SetString(language.English, "dynadot仅支持单域名配置,多个域名请添加更多配置", "dynadot only supports single domain configuration, please add more configurations")

// http_util
message.SetString(language.English, "异常信息: %s", "Exception: %s")
message.SetString(language.English, "查询域名信息发生异常! %s", "Query domain info failed! %s")
Expand Down

0 comments on commit 77caa37

Please sign in to comment.