Skip to content

Commit

Permalink
feat: v0.0.1功能初步完成
Browse files Browse the repository at this point in the history
  • Loading branch information
lankeo committed Jun 23, 2022
1 parent d23b631 commit 53118f1
Show file tree
Hide file tree
Showing 13 changed files with 619 additions and 0 deletions.
Empty file added .gitignore
Empty file.
98 changes: 98 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Go Namesilo DDNS
动态解析本地 IPv6 地址到 namesilo.com 托管的域名

### 特性
- namesilo.com DNS 记录新增(批量新增)、删除、修改、批量查,已实现
- 获取本地公共 IPv6 地址,已实现
- 动态 IPv6 地址解析,已实现
- 域名批量解析,已实现
- 定时任务自动域名解析, 未实现

### 配置
程序根目录下 `config.yaml` 文件
```yaml
# namesilo API 请求 url
url:
base: "https://www.namesilo.com/api/"
get: "dnsListRecords"
add: "dnsAddRecord"
update: "dnsUpdateRecord"
delete: "dnsDeleteRecord"

# namesilo API 要求字段
version: "1"
type: "xml"

# 账户设定的 key
key: "dd911ac49199bb691795a"

# 需要解析的域名(目前每次仅支持单个域名)
domain: "example.com"

# 需要添加的 DNS 解析记录(不添加请忽略)
records:
-
# 记录值类型,值为 "A"、"AAAA"、"CNAME"、"MX"、"TXT","AAAA" 支持 IPv6
type: "AAAA"

# 主机名,修改时不用包含域名
host: "www"

# 记录值,IPv4 或 IPv6 地址
value: "260e:3b7:3223:d50::1000"

# DNS记录在DNS服务器上的缓存时间,最小可设置为 3600 秒, 默认 7200 秒
ttl: "3600"

# 仅用于 MX 类型(如果未提供,则默认为 10),其他类型默认为 0
distance: "0"
-
type: "AAAA"
host: ""
value: "260e:3b7:3223:d50::1000"
ttl: "3600"
distance: "0"
```
### Example
动态解析本地 IPv6 地址到 namesilo,所有的解析记录使用同一个本地 IPv6 地址
```go
# `main.go` 文件
package main

func main() {
for _, rr := range ResourceRecords {
rr.GetUpdateHost()
rr.LocalPublicIPv6DDNS()
}
}
```
- ResourceRecords 为所有记录值列表

根据配置文件 `config.yml` 中配置的 `records` 添加 DNS 解析记录,已存在则忽略
```go
# `main.go` 文件
package main

func main() {
for _, rr := range ResourceRecords {
rr.GetUpdateHost()
}

InitAddDNSRecord()
}
```
> Tips: 程序默认会动态解析本地 IPv6 地址到 namesilo,并根据配置添加 DNS 解析记录
### API
#### Variables
- var IPs [ ]string
- var TargetIP string
- var ResourceRecords [ ]ResourceRecord
#### func GetDNSRecords(result *DNSRecordsResult)
#### type ResourceRecord
- #### func (rr *ResourceRecord) GetUpdateHost()
- #### func (rr *ResourceRecord) UpdateDNSRecord()
- #### func (rr *ResourceRecord) AddDNSRecord()
- #### func (rr *ResourceRecord) DeleteDNSRecord()
- #### func (rr *ResourceRecord) DeleteDNSRecord()
219 changes: 219 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package main

import (
"encoding/xml"
"io"
"log"
"net/http"
"strings"
)

// 获取 DNS 记录列表
func GetDNSRecords(result *DNSRecordsResult) {
url := GlobalConfig.Url.Base + GlobalConfig.Url.Get
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}

q := req.URL.Query()
q.Add("version", GlobalConfig.Version)
q.Add("type", GlobalConfig.Type)
q.Add("key", GlobalConfig.Key)
q.Add("domain", GlobalConfig.Domain)
req.URL.RawQuery = q.Encode()
log.Println("【查询】", req.URL.String())

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

err = xml.Unmarshal(body, result)
if err != nil {
log.Fatal(err)
}

result.Reply.RecordFailedLog()
}

// 获取更新记录值时需要传的 host, 保持原 host 不变
func (rr *ResourceRecord) GetUpdateHost() {
if rr.Host == GlobalConfig.Domain {
rr.Host = ""
} else {
rr.Host = strings.Split(rr.Host, "."+GlobalConfig.Domain)[0]
}
}

// 更新 DNS 记录
func (rr *ResourceRecord) UpdateDNSRecord() {
url := GlobalConfig.Url.Base + GlobalConfig.Url.Update
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}

q := req.URL.Query()
q.Add("version", GlobalConfig.Version)
q.Add("type", GlobalConfig.Type)
q.Add("key", GlobalConfig.Key)
q.Add("domain", GlobalConfig.Domain)

q.Add("rrid", rr.RecordId)
q.Add("rrhost", rr.Host)
q.Add("rrvalue", rr.Value)
q.Add("rrttl", rr.Ttl)
q.Add("rrdistance", rr.Distance)
req.URL.RawQuery = q.Encode()
log.Println("【更新】", req.URL.String())

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

result := &DNSRecordsOperateResult{}
err = xml.Unmarshal(body, result)
if err != nil {
log.Fatal(err)
}

result.Reply.RecordFailedLog()

result.RecordSuccessLog(rr.Value, "Update")
}

// 添加 DNS 记录
func (rr *ResourceRecord) AddDNSRecord() {
url := GlobalConfig.Url.Base + GlobalConfig.Url.Add
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}

q := req.URL.Query()
q.Add("version", GlobalConfig.Version)
q.Add("type", GlobalConfig.Type)
q.Add("key", GlobalConfig.Key)
q.Add("domain", GlobalConfig.Domain)

q.Add("rrtype", rr.Type)
q.Add("rrhost", rr.Host)
q.Add("rrvalue", rr.Value)
q.Add("rrttl", rr.Ttl)
q.Add("rrdistance", rr.Distance)
req.URL.RawQuery = q.Encode()
log.Println("【新增】", req.URL.String())

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

result := &DNSRecordsOperateResult{}
err = xml.Unmarshal(body, result)
if err != nil {
log.Fatal(err)
}

result.Reply.RecordFailedLog()

result.RecordSuccessLog(rr.Value, "Add")
}

// 删除 DNS 记录
func (rr *ResourceRecord) DeleteDNSRecord() {
url := GlobalConfig.Url.Base + GlobalConfig.Url.Delete
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}

q := req.URL.Query()
q.Add("version", GlobalConfig.Version)
q.Add("type", GlobalConfig.Type)
q.Add("key", GlobalConfig.Key)
q.Add("domain", GlobalConfig.Domain)

q.Add("rrid", rr.RecordId)

req.URL.RawQuery = q.Encode()
log.Println("【删除】", req.URL.String())

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}

result := &DNSRecordsOperateResult{}
err = xml.Unmarshal(body, result)
if err != nil {
log.Fatal(err)
}

result.Reply.RecordFailedLog()

result.RecordSuccessLog(rr.Value, "Delete")
}

// 动态解析本地 IPv6 地址到 namesilo
func (rr *ResourceRecord) LocalPublicIPv6DDNS() {
// ip 变化则更新记录值
if isLatest := InList(IPs, rr.Value); isLatest {
// 记录值已是最新 ip
rr.RecordIsLatestLog()
} else {
// 更新记录值
rr.Value = TargetIP
rr.UpdateDNSRecord()
}
}

// 配置中需要初始化添加的记录值
func InitAddDNSRecord() {
for _, record := range GlobalConfig.Records {
if InList(ResourceRecordHosts, record.Host) {
log.Printf(`【配置记录值初始化】Host: "%s" 已存在于记录值列表,将自动忽略`, record.Host)
continue
}
if len(record.Type) == 0 || len(record.Value) == 0 || len(record.Distance) == 0 {
log.Fatalln("ConfigError: record 中 type, value, ttl 为必填项")
}
r := ResourceRecord{}
r.Type = record.Type
r.Host = record.Host
r.Value = record.Value
r.Ttl = record.Ttl
r.Distance = record.Distance
r.AddDNSRecord()
}
}
41 changes: 41 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# namesilo API 请求 url
url:
base: "https://www.namesilo.com/api/"
get: "dnsListRecords"
add: "dnsAddRecord"
update: "dnsUpdateRecord"
delete: "dnsDeleteRecord"

# namesilo API 要求字段
version: "1"
type: "xml"

# 账户设定的 key
key: "dd911ac49199bb691795a"

# 需要解析的域名(目前每次仅支持单个域名)
domain: "example.com"

# 需要添加的 DNS 解析记录(不添加请忽略)
records:
-
# 记录值类型,值为 "A"、"AAAA"、"CNAME"、"MX"、"TXT","AAAA" 支持 IPv6
type: "AAAA"

# 主机名,修改时不用包含域名
host: "www"

# 记录值,IPv4 或 IPv6 地址
value: "260e:3b7:3223:d50::1000"

# DNS记录在DNS服务器上的缓存时间,最小可设置为 3600 秒, 默认 7200 秒
ttl: "3600"

# 仅用于 MX 类型(如果未提供,则默认为 10),其他类型默认为 0
distance: "0"
-
type: "AAAA"
host: ""
value: "260e:3b7:3223:d50::1000"
ttl: "3600"
distance: "0"
28 changes: 28 additions & 0 deletions example.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

// func main() {
// for _, rr := range ResourceRecords {
// rr.LocalPublicIPv6DDNS()

// // 更新单个记录值
// if rr.Host == "scpc.games."+GlobalConfig.Domain {
// rr.Value = IPs[0]
// rr.Host = ""
// rr.UpdateDNSRecord()
// }

// // 删除单个记录
// if rr.Host == "bad."+GlobalConfig.Domain {
// rr.DeleteDNSRecord()
// }
// }

// // 添加记录值
// rr := &ResourceRecord{
// Type: "AAAA",
// Host: "Bad3",
// Value: "240e:3b7:3223:da50:881d:b582:8fae:1cbd",
// Ttl: "3600",
// }
// rr.AddDNSRecord()
// }
Loading

0 comments on commit 53118f1

Please sign in to comment.