使用阿里DNS云解析SDK实现一个Go语言DDNS脚本

目标

  1. 使用云解析SDK,编写Go语言程序更新dns解析记录
  2. 使用Linux的systemd守护进程,每隔五分钟自动检测执行ddns

0. 准备工作

  1. 获取阿里云解析SDK

这一部分可以关注官方文档

  1. 获取阿里云RAM账户AccessId 和 secret

简单说就是创建一个最小权限账户来满足我们DDNS的需求。

1. Go语言脚本实现

设计思路:

  1. 获取本机当前的外网IP地址
  2. 获取域名当前的解析记录
  3. 比较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

  1. 编写一个执行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
复制代码
  1. 编写定时任务触发器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
复制代码
  1. 启动定时器并设置开机启动
systemctl start ddns.timer
systemctl enable ddns.timer
systemctl start ddns.service #手动执行一次service
复制代码
  1. 使用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
喜欢就支持一下吧
点赞0 分享