阿里云域名动态DDNS配置

一、设置阿里云域名管理账号

为了安全,我们新建一个子账号,仅编程访问且只有域名修改的权限。

1.1 登录阿里云控制台

1.2 在产品与服务中搜“访问控制”

1.3 创建新用户,只勾选编程访问。

这里要记住AccessKeyID和AccessKey Secret,后面需要用到。

1.4 添加DNS管理权限

找到AliyunDNSFullAccess权限,并添加。

二、编写程序实时判断本地公网IP并修改阿里云域名解析IP

2.1 新建maven项目,并添加阿里云开发工具包。

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-alidns</artifactId>
    <version>2.0.10</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.3.2</version>
</dependency>
<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.76</version>
    </dependency>

2.2 配置文件

{
  "regionId": "cn-hangzhou",
  "accessKeyId": "前面创建账号的AccessKeyID",
  "secret": "前面创建账号的AccessKey Secret",
  "tld":"zengwu.com.cn",
  "rr": "a",
  "dnsInterval": 86400,
  "ipInterval": 10
}
  • regionId: 区域,域名管理一般是杭州”cn-hangzhou”
  • accessKeyId: 前面创建账号的AccessKeyID
  • secret: 前面创建账号的AccessKey Secret
  • tld: 顶级域名
  • rr: 主机名
  • dnsInterval: 检查阿里云DNS配置的间隔时间(秒)
  • ipInterval: 检查本地公网IP的间隔时间(秒)

2.3 程序代码

package com.zngw.aliddns;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.alidns.model.v20150109.DescribeSubDomainRecordsRequest;
import com.aliyuncs.alidns.model.v20150109.DescribeSubDomainRecordsResponse;
import com.aliyuncs.alidns.model.v20150109.UpdateDomainRecordRequest;
import com.aliyuncs.alidns.model.v20150109.UpdateDomainRecordResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.google.gson.Gson;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * DDNS  class
 *
 * @author 55
 * @date 2021/6/28
 */
public class DDNS {
    private String recordsIp = "";      // 域名IP
    private long lastDnsTime = 0;       // 上次域名查询时间
    private long lastIpTime = 0;        // 上次公网ip查询时间
    private String host = null;         // 完整域名
    private Config cfg = null;          // 配置文件

    /**
     * 初始化
     */
    private void init(String filename){
        String cfgStr = readJsonFile(filename);
        cfg = JSON.parseObject(cfgStr, Config.class);
        if (cfg == null){
            System.out.println("读取配置文件"+filename+"失败");
            return;
        }
        cfg.dnsInterval *= 1000;
        cfg.ipInterval *= 1000;

        host = cfg.rr + "." +cfg.tld;
        if (cfg.rr == null || cfg.rr.length() == 0 || "@".equals(cfg.rr)){
            // 顶级域名处理
            cfg.rr = "@";
            host = cfg.tld;
        }
    }

    /**
     * 获取当前主机公网IP
     */
    private String getCurrenHostIp() {
        // 这里使用jsonip.com第三方接口获取本地IP
        String jsonip = "https://jsonip.com";
        // 接口返回结果
        String result = "";
        BufferedReader in = null;
        try {
            // 使用HttpURLConnection网络请求第三方接口
            URL url = new URL(jsonip);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();
            in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            while((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        //  正则表达式,提取xxx.xxx.xxx.xxx,将IP地址从接口返回结果中提取出来
        String rexp = "(\\d{1,3}\\.){3}\\d{1,3}";
        Pattern pat = Pattern.compile(rexp);
        Matcher mat = pat.matcher(result);
        String res = "";
        while (mat.find()) {
            res = mat.group();
            break;
        }
        return res;
    }
    /**
     * 获取主域名的所有解析记录列表
     */
    private DescribeSubDomainRecordsResponse describeSubDomainRecords(DescribeSubDomainRecordsRequest request, IAcsClient client) {
        try{
            // 调用SDK发送请求
            return client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            // 发生调用错误,抛出运行时异常
            throw new RuntimeException();
        }
    }
    /**
     * 修改解析记录
     */
    private UpdateDomainRecordResponse updateDomainRecord(UpdateDomainRecordRequest request, IAcsClient client) {
        try {
            //  调用SDK发送请求
            return client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            //  发生调用错误,抛出运行时异常
            throw new RuntimeException();
        }
    }

    /**
     * 检测IP是否改变,改变了就修改
     */
    private void check(String ip){
        //  设置鉴权参数,初始化客户端
        DefaultProfile profile;
        profile = DefaultProfile.getProfile(cfg.regionId,cfg.accessKeyId,cfg.secret);
        IAcsClient client = new DefaultAcsClient(profile);

        //查询指定域名的最新解析记录
        DescribeSubDomainRecordsRequest describeSubDomainRecordsRequest = new DescribeSubDomainRecordsRequest();
        describeSubDomainRecordsRequest.setSubDomain(host);
        DescribeSubDomainRecordsResponse describeSubDomainRecordsResponse = describeSubDomainRecords(describeSubDomainRecordsRequest, client);
        List<DescribeSubDomainRecordsResponse.Record> domainRecords = describeSubDomainRecordsResponse.getDomainRecords();
        //最新的一条解析记录
        if (domainRecords.size() != 0) {
            DescribeSubDomainRecordsResponse.Record record = domainRecords.get(0);
            //  记录ID
            String recordId = record.getRecordId();
            //  记录值
            recordsIp = record.getValue();

            if (!ip.equals(recordsIp)) {
                //  修改解析记录
                UpdateDomainRecordRequest updateDomainRecordRequest = new UpdateDomainRecordRequest();
                //  主机记录
                updateDomainRecordRequest.setRR(cfg.rr);
                //  记录ID
                updateDomainRecordRequest.setRecordId(recordId);
                //  将主机记录值改为当前主机IP
                updateDomainRecordRequest.setValue(ip);
                //  解析记录类型
                updateDomainRecordRequest.setType("A");
                UpdateDomainRecordResponse updateDomainRecordResponse = updateDomainRecord(updateDomainRecordRequest, client);

                System.out.println("域名 "+host+" 解析地址已修改为:" + ip);

                recordsIp = ip;
            }
        }
    }

    /**
     * 运行检测
     */
    private void run(){
        while (true){
            long now = System.currentTimeMillis();

            //  当前主机公网IP
            String ip = getCurrenHostIp();

            // 查询域名服务器值是否改变
            if (lastDnsTime < now){
                check(ip);
                lastIpTime = now + cfg.ipInterval;
                lastDnsTime = now + cfg.dnsInterval;
            }

            // 公网IP是否发生改变
            if (lastIpTime < now){
                if (ip!=null && !ip.equals(recordsIp)){
                    check(ip);
                    lastDnsTime = now + cfg.dnsInterval;
                }
                lastIpTime = now + cfg.ipInterval;
            }

            try {
                // 进程睡眠释放CPU并达到延迟效果
                Thread.sleep(Math.min( lastIpTime,lastDnsTime) - now -1);
            }catch(InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * 读取json文件,返回json串
     * @param fileName
     * @return
     */
    public String readJsonFile(String fileName) {
        String jsonStr = "";
        try {
            File jsonFile = new File(fileName);
            FileReader fileReader = new FileReader(jsonFile);

            Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }

            fileReader.close();
            reader.close();
            jsonStr = sb.toString();
            return jsonStr;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        String filename = "./config.json";
        DDNS ddns = new DDNS();
        ddns.init(filename);
        ddns.run();
    }
}

三、运行

编译好jar程序,将jar和config.json放到同一目录下,直接后台运行jar就可以了。

附:完整mavn项目

0%