golang版 阿里云DDNS 通过网页获取本地公网IP并更新DNS

运行环境:

go版本:go1.20
系统os:windows / mac / linux

运行结果:

2023/07/19 14:05:19 未获取到阿里云Ip解析记录,进行第一次记录
2023/07/19 14:05:19 记录成功,首次记录ip: 171.88.21.31
2023/07/19 14:15:19 当前公网IP(171.88.21.31) 与阿里云IP记录值(171.88.21.31)一致,无需更改

运行步骤:

go mod init
go mod tidy
go run main.go

使用注意事项:

注释里面已经写得非常详细了,直接拿来用就是了,记得配置一下:
aliCloudAccessKeyId,aliCloudAccessKeySecret,domainURL

当前程序会每10分钟会执行一次,首次运行也会执行一次

package main

import (
	"io"
	"log"
	"net/http"
	"regexp"
	"time"

	alidns20150109 "github.com/alibabacloud-go/alidns-20150109/v4/client"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	"github.com/alibabacloud-go/tea/tea"
)

const (
	// ----------以下内容可按需更改,且均为必填项----------
	aliCloudAccessKeyId     = ""  // 通过 https://ram.console.aliyun.com/manage/ak 获取
	aliCloudAccessKeySecret = ""  // 通过 https://ram.console.aliyun.com/manage/ak 获取
	domainURL               = ""  // 你的域名 比如 laghaim.cn
	rr                      = "@" // 主机记录 如果要解析@.exmaple.com,主机记录要填写”@”,而不是空。如果要解析www,就填写www即可
	//主机记录就是域名前缀,常见用法有:
	//www:解析后的域名为www.aliyun.com。
	//@:直接解析主域名 aliyun.com。
	//*:泛解析,匹配其他所有域名 *.aliyun.com。
	//mail:将域名解析为mail.aliyun.com,通常用于解析邮箱服务器。
	//二级域名:如:abc.aliyun.com,填写abc。
	//手机网站:如:m.aliyun.com,填写m。
	//显性URL:不支持泛解析(泛解析:将所有子域名解析到同一地址)
	recordType = "A" // ipv4 参考 https://help.aliyun.com/document_detail/29805.html?spm=a2c4g.29807.0.0.26dc3d95iVibLY

	// ----------以下内容不可更改----------
	aliDnsServer = "alidns.cn-hangzhou.aliyuncs.com" // 不要更改这个,阿里云服务器最快的一个DNS服务器
)

func main() {
	ticker := time.NewTicker(10 * time.Minute)
	err := refreshDDNS() // 首次执行先运行一次
	if err != nil {
		log.Println(err)
	}
	for {
		select {
		case <-ticker.C:
			err = refreshDDNS()
			if err != nil {
				log.Println(err)
			}
		}
	}
}

// CreateClient 创建发起请求的client
func CreateClient(accessKeyId *string, accessKeySecret *string) (result *alidns20150109.Client, err error) {
	config := &openapi.Config{
		AccessKeyId:     accessKeyId,
		AccessKeySecret: accessKeySecret,
	}
	// 访问的域名
	config.Endpoint = tea.String(aliDnsServer)
	result = &alidns20150109.Client{}
	result, err = alidns20150109.NewClient(config)
	return
}

// getRecordIp 获取当前阿里云的记录值
func getRecordIp(client *alidns20150109.Client) (*string, *string, error) {
	result, err := client.DescribeDomainRecords(&alidns20150109.DescribeDomainRecordsRequest{ // 文档出处:https://next.api.aliyun.com/api/Alidns/2015-01-09/UpdateDomainRecord
		DomainName: tea.String(domainURL),
	})
	if err != nil {
		log.Println("获取当前域名IP解析失败", err)
		return nil, nil, err
	}
	records := result.Body.DomainRecords.Record
	var (
		recordIp *string
		recordId *string
	)
	for _, record := range records {
		recordIp = record.Value
		recordId = record.RecordId
	}
	return recordIp, recordId, nil
}

// 执行比对当前ip和dns值,并更新操作
func refreshDDNS() (err error) {
	client, err := CreateClient(tea.String(aliCloudAccessKeyId), tea.String(aliCloudAccessKeySecret))
	if err != nil {
		return err
	}
	recordIp, recordId, err := getRecordIp(client)
	if err != nil {
		return err
	}
	// 获取本机ipv4地址
	realIp := getIpHost()
	if realIp == nil {
		return nil
	}
	if recordIp == nil {
		log.Println("未获取到阿里云Ip解析记录,进行第一次记录")
		err = addDomainFirst(client, realIp)
		if err != nil {
			return err
		}
		log.Println("记录成功,首次记录ip:", *realIp)
		return nil
	}
	if recordIp != nil && *recordIp == *realIp {
		log.Printf("当前公网IP(%s) 与阿里云IP记录值(%s)一致,无需更改\n", *realIp, *recordIp)
		return nil
	} else {
		_, err = client.UpdateDomainRecord(&alidns20150109.UpdateDomainRecordRequest{ // 文档出处:https://next.api.aliyun.com/api/Alidns/2015-01-09/UpdateDomainRecord
			RecordId: recordId,
			RR:       tea.String(rr),
			Type:     tea.String(recordType),
			Value:    realIp,
		})
		if err != nil {
			return err
		}
		recordIp, recordId, err = getRecordIp(client) // 再查一次吧
		if err != nil {
			return err
		}
		log.Printf("记录更新成功,当前的IP地址记录为:%s,记录ID为:%s\n", *recordIp, *recordId)
	}
	return err
}

// addDomainFirst 首次写入
func addDomainFirst(client *alidns20150109.Client, realIp *string) error {
	_, err := client.AddDomainRecord(&alidns20150109.AddDomainRecordRequest{ // 文档出处:https://next.api.aliyun.com/api/Alidns/2015-01-09/AddDomainRecord
		DomainName: tea.String(domainURL),
		RR:         tea.String(rr),
		Type:       tea.String(recordType),
		Value:      realIp,
	})
	if err != nil {
		return err
	}
	return nil
}

// getIpHost 通过访问网站的方式获取ip地址
func getIpHost() *string {
	resp, err := http.Get("https://www.taobao.com/help/getip.php") // 这是PHP写的功能,语言是工具,不是你炫耀的资本,更没有鄙视链一说,只有适合与不适合
	if err != nil {
		log.Println("ip地址查询时出错,error : ", err)
		return nil
	}
	defer resp.Body.Close()
	allByte, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Printf("解析时出错%s", err.Error())
		return nil
	}
	str := string(allByte)
	re := regexp.MustCompile(`ip:"(.*)"`)
	match := re.FindStringSubmatch(str)
	if len(match) != 0 {
		return &match[1]
	} else {
		log.Println("未找到本机公网IP地址")
		return nil
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值