Java实现阿里云域名动态解析,DDNS功能


前言

最近在家里搭建了一个家庭服务器,但是家庭宽带无法申请固定IP,在外网以及公司无法远程或访问该服务器(观察IP是隔1天动态变化一次),但是我的域名又是阿里云的,目前路由器的DDNS功能好像没有支持阿里云的。

好在阿里云提供了DNS相关的SDK,这里使用SpringBoot+AliYunSDK实现动态刷新DNS解析记录,从而实现通过域名,随时随地访问家里的电脑的功能


一、DDNS是什么?

DDNS(Dynamic Domain Name Server,动态域名服务)是将用户的动态IP地址映射到一个固定的域名解析服务上,用户每次连接网络的时候客户端程序就会通过信息传递把该主机的动态IP地址传送给位于服务商主机上的服务器程序,服务器程序负责提供DNS服务并实现动态域名解析。

二、实现步骤

1. 阿里云添加解析记录

打开阿里云控制台>云解析DNS>选中使用的域名>解析设置>添加一条解析记录(示例):

2.创建AccessKey

打开AccessKey管理界面,创建自己的AccessKey并保存AccessKeyId和AccessKeySecretId
在这里插入图片描述

3. 创建SpringBoot项目并引入依赖

Maven依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>tea-openapi</artifactId>
            <version>0.0.19</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>alidns20150109</artifactId>
            <version>2.0.1</version>
        </dependency>
    </dependencies>

4. 相关功能开发

  • 封装获取当前公网IP工具类WebToolUtils

    package org.feasy.www.util;
    
    import org.springframework.util.StringUtils;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.InetAddress;
    import java.net.NetworkInterface;
    import java.net.URL;
    import java.util.Enumeration;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * @author yangxiaohui
     * @since 2022/4/15 10:35
     */
    public class WebToolUtils {
        // 方法1
        private static String getNowIP1() throws IOException {
            String ip = null;
            String chinaz = "http://ip.chinaz.com";
            StringBuilder inputLine = new StringBuilder();
            String read = "";
            URL url = null;
            HttpURLConnection urlConnection = null;
            BufferedReader in = null;
            try {
                url = new URL(chinaz);
                urlConnection = (HttpURLConnection) url.openConnection();
                in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
                while ((read = in.readLine()) != null) {
                    inputLine.append(read + "\r\n");
                }
                Pattern p = Pattern.compile("\\<dd class\\=\"fz24\">(.*?)\\<\\/dd>");
                Matcher m = p.matcher(inputLine.toString());
                if (m.find()) {
                    String ipstr = m.group(1);
                    ip = ipstr;
                }
            } finally {
                if (in != null) {
                    in.close();
                }
            }
            if (StringUtils.isEmpty(ip)) {
                throw new RuntimeException();
            }
            return ip;
        }
        // 方法2
        private static String getNowIP2() throws IOException {
            String ip = null;
            BufferedReader br = null;
            try {
                URL url = new URL("https://v6r.ipip.net/?format=callback");
                br = new BufferedReader(new InputStreamReader(url.openStream()));
                String s = "";
                StringBuffer sb = new StringBuffer("");
                String webContent = "";
                while ((s = br.readLine()) != null) {
                    sb.append(s + "\r\n");
                }
                webContent = sb.toString();
                int start = webContent.indexOf("(") + 2;
                int end = webContent.indexOf(")") - 1;
                webContent = webContent.substring(start, end);
                ip = webContent;
            } finally {
                if (br != null)
                    br.close();
            }
            if (StringUtils.isEmpty(ip)) {
                throw new RuntimeException();
            }
            return ip;
        }
        // 方法3
        private static String getNowIP3() throws IOException {
            String ip = null;
            String objWebURL = "https://ip.900cha.com/";
            BufferedReader br = null;
            try {
                URL url = new URL(objWebURL);
                br = new BufferedReader(new InputStreamReader(url.openStream()));
                String s = "";
                String webContent = "";
                while ((s = br.readLine()) != null) {
                    if (s.indexOf("我的IP:") != -1) {
                        ip = s.substring(s.indexOf(":") + 1);
                        break;
                    }
                }
            } finally {
                if (br != null)
                    br.close();
            }
            if (StringUtils.isEmpty(ip)) {
                throw new RuntimeException();
            }
            return ip;
        }
        // 方法4
        private static String getNowIP4() throws IOException {
            String ip = null;
            String objWebURL = "https://bajiu.cn/ip/";
            BufferedReader br = null;
            try {
                URL url = new URL(objWebURL);
                br = new BufferedReader(new InputStreamReader(url.openStream()));
                String s = "";
                String webContent = "";
                while ((s = br.readLine()) != null) {
                    if (s.indexOf("互联网IP") != -1) {
                        ip = s.substring(s.indexOf("'") + 1, s.lastIndexOf("'"));
                        break;
                    }
                }
            } finally {
                if (br != null)
                    br.close();
            }
            if (StringUtils.isEmpty(ip)) {
                throw new RuntimeException();
            }
            return ip;
        }
    
        public static String getPublicIP() {
            String ip = null;
            // 第一种方式
            try {
                ip = getNowIP1();
                ip.trim();
            } catch (Exception e) {
                System.out.println("getPublicIP - getNowIP1 failed ~ ");
            }
            if (!StringUtils.isEmpty(ip))
                return ip;
            // 第二种方式
            try {
                ip = getNowIP2();
                ip.trim();
            } catch (Exception e) {
                System.out.println("getPublicIP - getNowIP2 failed ~ ");
            }
            if (!StringUtils.isEmpty(ip))
                return ip;
            // 第三种方式
            try {
                ip = getNowIP3();
                ip.trim();
            } catch (Exception e) {
                System.out.println("getPublicIP - getNowIP3 failed ~ ");
            }
            if (!StringUtils.isEmpty(ip))
                return ip;
            // 第四种方式
            try {
                ip = getNowIP4();
                ip.trim();
            } catch (Exception e) {
                System.out.println("getPublicIP - getNowIP4 failed ~ ");
            }
            if (!StringUtils.isEmpty(ip))
                return ip;
            return ip;
        }
    
    }
    
    
  • 封装阿里云DNS-SDK操作,刷新逻辑DdnsClient

    package org.feasy.www.ddns;
    
    import com.alibaba.fastjson.JSON;
    import com.aliyun.alidns20150109.Client;
    import com.aliyun.alidns20150109.models.*;
    import com.aliyun.teaopenapi.models.Config;
    import org.feasy.www.util.WebToolUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @author yangxiaohui
     * @since 2022/4/15 10:10
     */
    @Component
    public class DdnsClient {
        private final Logger logger= LoggerFactory.getLogger(this.getClass());
    
        @Value("${ali.domain}")
        private String domain;
        @Value("${ali.keyword}")
        private String keyWord;
        @Value("${ali.access-key}")
        private String accessKey;
        @Value("${ali.access-key-secret}")
        private String accessSecret;
        @Value("${ali.endpoint}")
        private String endpoint;
    
        private String currentDdnsIp="";
    
        private final Client client;
    
        public DdnsClient() throws Exception {
            this.client = new Client(new Config()
                    // 您的AccessKey ID
                    .setAccessKeyId(accessKey)
                    // 您的AccessKey Secret
                    .setAccessKeySecret(accessSecret)
                    .setEndpoint(endpoint)
            );
            this.refreshDdns();
        }
    
        public void refreshDdns() throws Exception {
            String currentIp = this.getCurrentIp();
            if (!this.currentDdnsIp.equals(currentIp)){
                // 获取解析记录
                DescribeDomainRecordsResponseBody.DescribeDomainRecordsResponseBodyDomainRecordsRecord domainDnsRecord = this.getDomainDnsRecord();
                // 刷新解析记录
                this.updateDomainDnsRecord(domainDnsRecord,currentIp);
            }
            logger.info("无需修改解析记录,当前IP:{}",currentIp);
        }
    
        private String getCurrentIp(){
            return WebToolUtils.getPublicIP();
        }
    
        private DescribeDomainRecordsResponseBody.DescribeDomainRecordsResponseBodyDomainRecordsRecord getDomainDnsRecord() throws Exception {
            DescribeDomainRecordsRequest describeDomainRecordsRequest = new DescribeDomainRecordsRequest()
                    .setDomainName(domain)
                    .setKeyWord(keyWord);
            // 获取记录详情
            DescribeDomainRecordsResponse domainRecordsResponse = client.describeDomainRecords(describeDomainRecordsRequest);
            List<DescribeDomainRecordsResponseBody.DescribeDomainRecordsResponseBodyDomainRecordsRecord> record = domainRecordsResponse.getBody().getDomainRecords().getRecord();
            DescribeDomainRecordsResponseBody.DescribeDomainRecordsResponseBodyDomainRecordsRecord describeDomainRecordsResponseBodyDomainRecordsRecord = record.get(0);
            logger.info("获取解析记录:{}", JSON.toJSONString(describeDomainRecordsResponseBodyDomainRecordsRecord));
            return describeDomainRecordsResponseBodyDomainRecordsRecord;
        }
        private void updateDomainDnsRecord(DescribeDomainRecordsResponseBody.DescribeDomainRecordsResponseBodyDomainRecordsRecord domainDnsRecord,String newIp) throws Exception {
            // 修改记录
            UpdateDomainRecordRequest updateDomainRecordRequest = new UpdateDomainRecordRequest()
                    .setRecordId(domainDnsRecord.getRecordId())
                    .setRR(domainDnsRecord.getRR())
                    .setType(domainDnsRecord.getType())
                    .setValue(newIp);
            // 修改记录
            UpdateDomainRecordResponse updateDomainRecordResponse = client.updateDomainRecord(updateDomainRecordRequest);
            logger.info("修改解析结果:{}",JSON.toJSONString(updateDomainRecordResponse));
        }
    }
    
    
  • 设置定时任务DdnsTask

    package org.feasy.www.ddns;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    /**
     * @author yangxiaohui
     * @since 2022/4/15 10:28
     */
    @Component
    @EnableScheduling
    public class DdnsTask {
        private final Logger logger= LoggerFactory.getLogger(this.getClass());
    
        private final DdnsClient ddnsClient;
    
        public DdnsTask(DdnsClient ddnsClient) {
            this.ddnsClient = ddnsClient;
        }
    
        /**
         * 刷新阿里巴巴DNS解析记录
         */
        @Scheduled(fixedRate=300000)
        public void refreshDdns() throws Exception {
            ddnsClient.refreshDdns();
        }
    }
    
    
    
  • 项目配置application.properties

    server.port=8089
    ali.domain=域名
    ali.keyword=解析主机记录
    ali.endpoint=dns.aliyuncs.com
    ali.access-key=AccessKeyId
    ali.access-key-secret=AccessKeySecretId
    

总结

当前设置是启动项目会执行一次刷新DNS记录,执行频率默认5分钟执行一次,调整频率的话可以调整@Scheduled(fixedRate=300000),单位是毫秒

源码地址:https://gitee.com/yxh-china/alibaba-ddns.git

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

清晨先生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值