Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Dynadot. #1050

Merged
merged 3 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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)
Comment on lines +120 to +121
Copy link
Owner

@jeessy2 jeessy2 Mar 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

每次都要请求接口,所以IP没有变动也会请求接口,会导致收到webhook通知过多

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

参考godaddy.go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好,我这两天改一下


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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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