目标
- 使用云解析SDK,编写Go语言程序更新dns解析记录
- 使用Linux的systemd守护进程,每隔五分钟自动检测执行ddns
0. 准备工作
- 获取阿里云解析SDK
这一部分可以关注官方文档
- 获取阿里云RAM账户AccessId 和 secret
简单说就是创建一个最小权限账户来满足我们DDNS的需求。
1. Go语言脚本实现
设计思路:
- 获取本机当前的外网IP地址
- 获取域名当前的解析记录
- 比较1和2,如果不一致,那么更新域名解析记录为当前本机Ip
参考实现
封装一下获取本机当前ip的方法,我是使用了https://ip-api.me/ip
公共接口
func GetIpHost() *string {
resp, err := http.Get("https://ip-api.me/ip")
if err != nil {
println(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
result := IpResp{}
err = json.Unmarshal(body, &result)
if err != nil {
fmt.Printf("%s|ip query result is %s\n", *NowTime(), string(body))
return nil
} else {
fmt.Printf("%s|ip query result is %s\n", *NowTime(), *result.Ip)
}
return result.Ip
}
复制代码
通过SDK实现更新DNS解析值,代码参考了阿里云的SDK模板。
先通过getRecordIp()
方法获取对应recordId的当前记录值,对比本机Ip,如果不一致那么将对应recordId的记录值更新成本机ip。
最后,再次调用getRecordIp()
方法,确认更新后的结果是新的值。
这里的recordId
是指每个解析记录的唯一id,可以通过下面的DescribeDomainRecordsRequest
请求获取,详见阿里云的文档。
我在获取之后写死在脚本中了。
package main
import (
"fmt"
alidns20150109 "github.com/alibabacloud-go/alidns-20150109/v2/client"
openapi "github.com/alibabacloud-go/darabonba-openapi/client"
"github.com/alibabacloud-go/tea/tea"
"os"
)
// CreateClient 创建发起请求的client
func CreateClient(accessKeyId *string, accessKeySecret *string) (_result *alidns20150109.Client, _err error) {
config := &openapi.Config{
// 您的AccessKey ID
AccessKeyId: accessKeyId,
// 您的AccessKey Secret
AccessKeySecret: accessKeySecret,
}
// 访问的域名
config.Endpoint = tea.String("alidns.cn-hangzhou.aliyuncs.com")
_result = &alidns20150109.Client{}
_result, _err = alidns20150109.NewClient(config)
return _result, _err
}
//封装获取对应解析记录的方法
func getRecordIp(client *alidns20150109.Client, recordId *string) *string {
describeDomainRecordsRequest := &alidns20150109.DescribeDomainRecordsRequest{
DomainName: tea.String("my-domain.com"),
}
// 复制代码运行请自行打印 API 的返回值
result, _err := client.DescribeDomainRecords(describeDomainRecordsRequest)
if _err != nil {
return nil
}
records := result.Body.DomainRecords.Record
var recordIp *string
for _, record := range records {
if *record.RecordId == *recordId {
recordIp = record.Value
fmt.Printf("%s|now record value of domain is %s\n", *NowTime(), *record.Value)
}
}
return recordIp
}
//执行比对当前ip和dns值,并更新操作
func _main(args []*string) (_err error) {
recordId := "19504821127000000"
client, _err := CreateClient(tea.String("Access Id"), tea.String("Access Secret"))
if _err != nil {
return _err
}
recordIp := getRecordIp(client, &recordId)
if recordIp == nil {
fmt.Printf("%s|获取Ip解析记录失败\n", *NowTime())
return _err
}
realIp := GetIpHost()
if realIp == nil {
return _err
}
if *recordIp == *realIp {
fmt.Printf("%s|real ip %s equals dns record\n", *NowTime(), *realIp)
} else {
updateDomainRecordRequest := &alidns20150109.UpdateDomainRecordRequest{
RecordId: tea.String(recordId),
RR: tea.String("@"),
Type: tea.String("A"),
Value: realIp,
}
// 复制代码运行请自行打印 API 的返回值
_, _err := client.UpdateDomainRecord(updateDomainRecordRequest)
if _err != nil {
return _err
} else {
recordIp = getRecordIp(client, &recordId)
fmt.Printf("%s|update dns record success, now record ip is %s\n", *NowTime(), *recordIp)
}
}
return _err
}
func main() {
err := _main(tea.StringSlice(os.Args[1:]))
if err != nil {
panic(err)
}
}
复制代码
2. 编译生成Linux平台程序
export CGO_ENABLED=0
export GOOS=linux
export GOARCH=amd64
go build -o out/linux/alidns .
复制代码
最后生成的可执行文件为alidns
,我把它拷贝到/usr/local/bin/
目录下。
3. 使用systemd定时执行脚本
此部分代码参考了开源项目NewFuture
/
DDNS:https://github.com/NewFuture/DDNS
- 编写一个执行
alidns
的service,放在目录/usr/lib/systemd/system/ddns.service
:
[Unit]
Description=aliyun ddns
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/alidns
[Install]
WantedBy=multi-user.target
复制代码
- 编写定时任务触发器timer,放在
/usr/lib/systemd/system/ddns.timer
[Unit]
Description=aliyun ddns timer
[Timer]
OnBootSec=5m
OnUnitActiveSec=5m
Unit=ddns.service
[Install]
WantedBy=multi-user.target
复制代码
- 启动定时器并设置开机启动
systemctl start ddns.timer
systemctl enable ddns.timer
systemctl start ddns.service #手动执行一次service
复制代码
- 使用systemctl status 命令查看运行状态
deepin@deepin-desktop:~$ systemctl status ddns
● ddns.service - aliyun ddns
Loaded: loaded (/lib/systemd/system/ddns.service; disabled; vendor preset: enabled)
Active: inactive (dead) since Mon 2021-06-07 01:34:47 CST; 13s ago
TriggeredBy: ● ddns.timer
Process: 80733 ExecStart=/usr/local/bin/alidns (code=exited, status=0/SUCCESS)
Main PID: 80733 (code=exited, status=0/SUCCESS)
6月 07 01:34:46 deepin-desktop systemd[1]: Started aliyun ddns.
6月 07 01:34:46 deepin-desktop alidns[80733]: 2021-06-07 01:34:46|now record value of domain is 180.109.xxx.xxx
6月 07 01:34:47 deepin-desktop alidns[80733]: 2021-06-07 01:34:47|ip query result is 180.109.xxx.xxx
6月 07 01:34:47 deepin-desktop alidns[80733]: 2021-06-07 01:34:47|real ip 180.109.xxx.xxx equals dns record
6月 07 01:34:47 deepin-desktop systemd[1]: ddns.service: Succeeded.
复制代码
程序运行良好
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END