DNSPOD使用教程

DNSPOD使用教程

1、登录DNSPod

DNSPod:https://console.dnspod.cn/

2、创建API密钥

在这里插入图片描述
在这里插入图片描述

注意保存密码,只显示一次

3、配置请求

3.1、获取RecordList、RecordId

https://console.cloud.tencent.com/api/explorer?Product=dnspod&Version=2021-03-23&Action=DescribeRecordList

  • Domain填写一级域名
  • Subdomain填写二级域名

在这里插入图片描述

3.2、修改解析值

https://console.cloud.tencent.com/api/explorer?Product=dnspod&Version=2021-03-23&Action=ModifyRecord

在这里插入图片描述

确认在此页面可以修改正确后就进行下一步

4、修改域名工具(go)

编写过程中多有参考ddns-go:https://github.com/jeessy2/ddns-go,本工具链接:https://github.com/xumeng03/ddns

4.1、获取ipv6地址

package ip

import (
	"fmt"
	"net"
)

type NetInterface struct {
	Name    string
	Address []string
}

func Ipv6() ([]NetInterface, error) {
	// ipv6 有效地址是 2000::/3
	_, effectiveIpv6, _ := net.ParseCIDR("2000::/3")

	// 获取所有网络接口
	allNetInterfaces, err := net.Interfaces()
	if err != nil {
		fmt.Println("net.Interfaces failed, err:", err.Error())
		return nil, err
	}

	var ipv6NetInterfaces []NetInterface

	// 遍历网络接口
	for _, netInterface := range allNetInterfaces {
		// 只处理接口状态处于活跃状态的网络接口
		if netInterface.Flags&net.FlagUp == 0 {
			continue
		}

		var ipv6 []string

		// 获取网络接口的地址列表
		if addrs, err := netInterface.Addrs(); err == nil {
			// 遍历网络接口的地址列表
			for _, addr := range addrs {
				// 将接口值addr转换为*net.IPNet类型的指针
				ipNet := addr.(*net.IPNet)
				// 如果子网掩码长度 bits 为 128(即IPv6地址),如果子网掩码长度 bits 为 32(即IPv4地址)
				_, bits := ipNet.Mask.Size()
				if bits == 128 && effectiveIpv6.Contains(ipNet.IP) {
					ipv6 = append(ipv6, ipNet.IP.String())
				}
			}

			if len(ipv6) > 0 {
				ipv6NetInterfaces = append(ipv6NetInterfaces, NetInterface{
					Name:    netInterface.Name,
					Address: ipv6,
				})
			}
		}
	}
	return ipv6NetInterfaces, nil
}

4.2、修改解析值

package dns

import (
	"fmt"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
)

var client *dnspod.Client

func InitClient(secretId string, secretKey string) {
	// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
	// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
	// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
	credential := common.NewCredential(
		secretId,
		secretKey,
	)
	// 实例化一个client选项,可选的,没有特殊需求可以跳过
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "dnspod.tencentcloudapi.com"
	// 实例化要请求产品的client对象,clientProfile是可选的
	client, _ = dnspod.NewClient(credential, "", cpf)
}

func SelectRecord(domain string, subdomain string) *dnspod.RecordListItem {

	// 实例化一个请求对象,每个接口都会对应一个request对象
	request := dnspod.NewDescribeRecordListRequest()

	request.Domain = common.StringPtr(domain)
	request.Subdomain = common.StringPtr(subdomain)

	// 返回的resp是一个DescribeRecordListResponse的实例,与请求对象对应
	response, err := client.DescribeRecordList(request)
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		fmt.Printf("An API error has returned: %s", err)
	}
	if err != nil {
		fmt.Printf("client.DescribeRecordList failed, err: %s", err)
	}
	if len(response.Response.RecordList) > 0 {
		return response.Response.RecordList[0]
	}
	return nil
}

func UpdateRecord(domain string, subdomain string, ipv6 string, recordId uint64) {

	// 实例化一个请求对象,每个接口都会对应一个request对象
	request := dnspod.NewModifyRecordRequest()

	request.Domain = common.StringPtr(domain)
	request.SubDomain = common.StringPtr(subdomain)
	request.RecordType = common.StringPtr("AAAA")
	request.RecordLine = common.StringPtr("默认")
	request.Value = common.StringPtr(ipv6)
	request.RecordId = common.Uint64Ptr(recordId)

	// 返回的resp是一个ModifyRecordResponse的实例,与请求对象对应
	response, err := client.ModifyRecord(request)
	if _, ok := err.(*errors.TencentCloudSDKError); ok {
		fmt.Printf("An API error has returned: %s", err)
		return
	}
	if err != nil {
		panic(err)
	}
	// 输出json格式的字符串回包
	fmt.Println(response.ToJsonString())
}

4.3、定时运行

package main

import (
	"ddns/utils/dns"
	"ddns/utils/effective"
	"ddns/utils/ip"
	"flag"
	"fmt"
	dnspod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod/v20210323"
	"time"
)

var secretId = flag.String("secretId", "", "SecretId")
var secretKey = flag.String("secretKey", "", "SecretKey")
var domain = flag.String("domain", "", "Domain")
var subdomain = flag.String("subdomain", "", "Subdomain")
var interval = flag.Int64("interval", 15, "Interval")
var record *dnspod.RecordListItem

func main() {
	// 解析命令行参数
	flag.Parse()
	if !effective.EffectiveString(*secretId, *secretKey, *domain, *subdomain) {
		fmt.Println("secretId and secretKey and domain and subdomain are required!")
		return
	}

	// 初始化 dns
	dns.InitClient(*secretId, *secretKey)
	// 查询 dns 记录
	record = dns.SelectRecord(*domain, *subdomain)
	if record == nil {
		fmt.Println("No records were found from dnspod!")
		return
	}
	// 启动先触发一次
	fmt.Println("Execution time: ", time.Now())
	dnns()

	// 定时查看 ip 是否发生变化
	ticker := time.NewTicker(time.Duration(*interval) * time.Minute)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			fmt.Println("Execution time: ", time.Now())
			dnns()
		}
	}
}

func dnns() {
	// 获取当前 ipv6 地址
	ipv6NetInterfaces, err := ip.Ipv6()
	if err != nil {
		fmt.Println("Error getting ipv6 ", err)
		return
	}
	// 遍历所有 ipv6 地址,查看是否有与 dns 解析一致的地址
	f := false
	for _, netInterface := range ipv6NetInterfaces {
		for _, addr := range netInterface.Address {
			if addr == *record.Value {
				f = true
			}
		}
	}
	// 如果所有的 ipv6 地址与 dns 解析的地址都不一致,将设备中国第一个 ipv6 地址更新到 dns 解析中,并更新记录值
	if !f {
		fmt.Println("IPV6 has changed!")
		dns.UpdateRecord(*domain, *subdomain, ipv6NetInterfaces[0].Address[0], *record.RecordId)
		record = dns.SelectRecord(*domain, *subdomain)
	} else {
		fmt.Println("IPV6 has not changed!")
	}
}

4.4、直接运行

  • SECRETID:上文获取的API密钥的ID
  • SECRETKEY:上文获取的API密钥
  • DOMAIN:一级域名
  • SUBDOMAIN:二级域名
  • INTERVAL:运行间隔,单位分钟,默认15分钟
go run main.go -secretId SECRETID -secretKey SECRETKEY -domain DOMAIN -subdomain SUBDOMAIN -interval INTERVAL

4.5、作为守护进程运行

/etc/systemd/system/下新建ddns.service

[Unit]
Description=easily configure dynamic domain names
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/ddns/ddns -secretId SECRETID -secretKey SECRETKEY -domain DOMAIN -subdomain SUBDOMAIN -interval INTERVAL
StandardOutput=file:/var/log/ddns.log
StandardError=file:/var/log/ddns_error.log
Restart=always
User=root

[Install]
WantedBy=multi-user.target
# 修改文件重新加载 Systemd 并重新启动服务
# sudo systemctl daemon-reload
# 设置开机启动并立即启动服务
systemctl enable ddns.service --now
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

眼眸流转

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值