阿里云域名動態(tài)DDNS配置

一、設(shè)置阿里云域名管理賬號

為了安全,我們新建一個子賬號,僅編程訪問且只有域名修改的權(quán)限。

1.1 登錄阿里云控制臺

1.2 在產(chǎn)品與服務(wù)中搜“訪問控制”

1.3 創(chuàng)建新用戶,只勾選編程訪問。

這里要記住AccessKeyID和AccessKey Secret,后面需要用到。

1.4 添加DNS管理權(quán)限

找到AliyunDNSFullAccess權(quán)限,并添加。


二、編寫程序?qū)崟r判斷本地公網(wǎng)IP并修改阿里云域名解析IP

2.1 新建maven項目,并添加阿里云開發(fā)工具包。

<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": "前面創(chuàng)建賬號的AccessKeyID",
  "secret": "前面創(chuàng)建賬號的AccessKey Secret",
  "tld":"zengwu.com.cn",
  "rr": "a",
  "dnsInterval": 86400,
  "ipInterval": 10
}
  • regionId: 區(qū)域,域名管理一般是杭州"cn-hangzhou"
  • accessKeyId: 前面創(chuàng)建賬號的AccessKeyID
  • secret: 前面創(chuàng)建賬號的AccessKey Secret
  • tld: 頂級域名
  • rr: 主機名
  • dnsInterval: 檢查阿里云DNS配置的間隔時間(秒)
  • ipInterval: 檢查本地公網(wǎng)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;        // 上次公網(wǎng)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;
        }
    }

    /**
     * 獲取當前主機公網(wǎng)IP
     */
    private String getCurrenHostIp() {
        // 這里使用jsonip.com第三方接口獲取本地IP
        String jsonip = "https://jsonip.com";
        // 接口返回結(jié)果
        String result = "";
        BufferedReader in = null;
        try {
            // 使用HttpURLConnection網(wǎng)絡(luò)請求第三方接口
            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塊來關(guān)閉輸入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        //  正則表達式,提取xxx.xxx.xxx.xxx,將IP地址從接口返回結(jié)果中提取出來
        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{
            // 調(diào)用SDK發(fā)送請求
            return client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            // 發(fā)生調(diào)用錯誤,拋出運行時異常
            throw new RuntimeException();
        }
    }
    /**
     * 修改解析記錄
     */
    private UpdateDomainRecordResponse updateDomainRecord(UpdateDomainRecordRequest request, IAcsClient client) {
        try {
            //  調(diào)用SDK發(fā)送請求
            return client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            //  發(fā)生調(diào)用錯誤,拋出運行時異常
            throw new RuntimeException();
        }
    }

    /**
     * 檢測IP是否改變,改變了就修改
     */
    private void check(String ip){
        //  設(shè)置鑒權(quán)參數(shù),初始化客戶端
        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();

            //  當前主機公網(wǎng)IP
            String ip = getCurrenHostIp();

            // 查詢域名服務(wù)器值是否改變
            if (lastDnsTime < now){
                check(ip);
                lastIpTime = now + cfg.ipInterval;
                lastDnsTime = now + cfg.dnsInterval;
            }

            // 公網(wǎng)IP是否發(fā)生改變
            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項目

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容