From 32010c77d1df297454cf17583a80769bfa61ca37 Mon Sep 17 00:00:00 2001 From: suguo <25950955@qq.com> Date: Tue, 17 Mar 2026 10:16:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9IPv4=E8=BF=9B=E8=A1=8C=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=A7=A3=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 +++ Dockerfile | 16 ++++++ go.mod | 14 ++++++ main.go | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 29 +++++++++++ 5 files changed, 211 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 go.mod create mode 100644 main.go create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ef3b6e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.exe +.vscode/ +go.sum +ddns6 +*.cmd +.env +ddns4 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7bb2fa8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM harbor.ks.easyj.top/zt/alpine:0.1 + +ENV APP_DIR=/app \ + DOMAIN=myschools.me \ + RR=pi \ + REGIONID=cn-hangzhou \ + ACCESSKEYID=LTAI5tJV828nqSqGpkouh1FD \ + ACCESSSECRET=aiMEp37bHLOjtoJFTDTfpq1o37cGtA + +COPY ddns4 ${APP_DIR}/ddns4 + +WORKDIR ${APP_DIR} + +RUN chmod +x ddns4 + +CMD ["./ddns4"] diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bed773d --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module myschools.me/suguo/ddns6 + +go 1.19 + +require github.com/aliyun/alibaba-cloud-sdk-go v1.62.676 + +require ( + github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect + github.com/json-iterator/go v1.1.10 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect + gopkg.in/ini.v1 v1.66.2 // indirect +) diff --git a/main.go b/main.go new file mode 100644 index 0000000..4da6c40 --- /dev/null +++ b/main.go @@ -0,0 +1,145 @@ +package main + +import ( + "fmt" + "io" + "log" + "net" + "net/http" + "os" + "strings" + "time" + + "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" +) + +// getPublicIP 通过外部 API 获取公网 IPv4 地址 +func getPublicIP() (string, error) { + // 使用多个 IP 查询服务作为备选 + apis := []string{ + "https://api.ipify.org", + "https://ifconfig.me/ip", + "https://ipecho.net/plain", + } + + for _, api := range apis { + resp, err := http.Get(api) + if err != nil { + log.Printf("Error fetching IP from %s: %v", api, err) + continue + } + + body, err := io.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + log.Printf("Error reading response from %s: %v", api, err) + continue + } + + ip := strings.TrimSpace(string(body)) + if net.ParseIP(ip) != nil { + return ip, nil + } + } + + return "", fmt.Errorf("failed to get public IP from all APIs") +} + +func main() { + domain := os.Getenv("DOMAIN") + rr := os.Getenv("RR") + regionID := os.Getenv("REGIONID") + if regionID == "" { + regionID = "cn-hangzhou" + } + accessKeyID := os.Getenv("ACCESSKEYID") + accessSecret := os.Getenv("ACCESSSECRET") + + ip4 := "" + for { + time.Sleep(10 * time.Second) + + currentIPV4, err := getPublicIP() + if err != nil { + log.Println("Error getting public IP:", err) + continue + } + + if currentIPV4 == "" || currentIPV4 == ip4 { + continue + } + + client, err := alidns.NewClientWithAccessKey(regionID, accessKeyID, accessSecret) + if err != nil { + log.Println(err.Error()) + continue + } + + drRequest := alidns.CreateDescribeDomainRecordsRequest() + drRequest.KeyWord = rr + drRequest.DomainName = domain + drRequest.TypeKeyWord = "A" + + drResponse, err := client.DescribeDomainRecords(drRequest) + if err != nil { + log.Println(err) + continue + } + if !drResponse.IsSuccess() { + continue + } + + rid := "" + for _, r := range drResponse.DomainRecords.Record { + rid = r.RecordId + if r.Value == currentIPV4 { + ip4 = currentIPV4 + rid = "" + } + break + } + + if rid == "" { + continue + } + + //修改域名对应的IP,修改成功后continue + req := alidns.CreateUpdateDomainRecordRequest() + req.Scheme = "https" + req.RR = rr + req.RecordId = rid + req.Value = currentIPV4 + req.Type = "A" + + resp, err := client.UpdateDomainRecord(req) + if err != nil { + log.Println(err.Error()) + if !strings.Contains(err.Error(), fmt.Sprintf("not %s", domain)) { + continue + } + } + + if resp.IsSuccess() { + ip4 = currentIPV4 + log.Println("update success: ", ip4) + continue + } + + //当域名修改失败时判断是否是没有对应的记录,不存在时创建新的域名记录 + request := alidns.CreateAddDomainRecordRequest() + request.Scheme = "https" + request.Value = currentIPV4 + request.Type = "A" + request.RR = rr + request.DomainName = domain + response, err := client.AddDomainRecord(request) + if err != nil { + fmt.Print(err.Error()) + continue + } + if !response.IsSuccess() { + fmt.Print(response.GetHttpContentString()) + ip4 = currentIPV4 + } + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..1e73e97 --- /dev/null +++ b/readme.md @@ -0,0 +1,29 @@ +# DDNS4 + +--- + + +一、概述 + + 把当前主机的IPV4向阿里DNS进行注册,实现IPV4 DDNS功能。当二级域名没有创建时会自动创建,解释使用A类型,每10秒检测一次当前主机的IPV4地址,如果发生变化则自动更新到阿里DNS。如果存在多个IPV4地址,则只更新第一个IPV4地址。 + +二、组件 + + github.com/aliyun/alibaba-cloud-sdk-go v1.62.676 + +三、配置 + + 1. 阿里云配置RAM访问控制,权限如下: + + AliyunDNSFullAccess + AliyunHTTPDNSFullAccess + + 2. 环境变量 + DOMAIN 域名 + RR 二级域名 + REGIONID 地域,默认cn-hangzhou + ACCESSKEYID 访问key + ACCESSSECRET 访问私钥 + +四、 调试 +