自定义DDNS自动解析脚本

概述

在了解DDNS之前,我们先来了解一下什么DNS。在网络中,我们如果要访问一台主机或网站时,需要先获知其地址,其中IP地址获取记起来总是不那么方便。而DNS就是为了解决这种问题。DNS,也就是域名系统,记录了域名和IP之间的映射关系,主要的作用就是基于访问的域名(也就是网址中的xx.xx.xx)查出对应的IP。

但是在某些实际场景中,我们的IP并不一定会固定,可能会随着某些因素而发生变化,从而导致我们无法正常访问到具体应用或服务。为了解决这种问题,我们可以通过DDNS实现域名的动态解析。DDNS用来动态更新DNS服务器上域名和IP地址之间的映射关系,从而保证通过域名访问到正确的IP地址。

通常情况下,某些路由器或者网络设备会有DDNS功能,但是不一定支持我们域名所在的DNS服务商,所以我们可以基于DNS服务商提供的API接口,自行编写DDNS脚本。

先决条件

Linux操作系统:CentOS7

已开通的公网IP

详细操作

基于腾讯云DNS域名解析实现DDNS

  1. 获取token,登录腾讯云的DNSPod账号中心控制台,右上角依次单击我的账号->API密钥,在DNSPod Token中点击创建密钥即可。(密钥只会显示一次,记得保存好)

    然后LOGIN_TOKEN会以ID+”,”+TOKEN的方式使用,所以也要记得记录一下当前token的ID值。

    将其保存到/usr/local/dnspod-agent目录下,并命名成dnspod-token文件。

1
2
3
mkdir -p /usr/local/dnspod-agent
echo -n "ID,TOKEN" | base64 > /usr/local/dnspod-agent/dnspod-token
LOGIN_TOKEN=`base64 -d /usr/local/dnspod-agent/dnspod-token`
  1. 获取当前主机的公网IP
1
IP=`curl ifconfig.me -s`
  1. 获取Domain ID
1
DOMAIN_ID=`curl -s -X POST https://dnsapi.cn/Domain.List -d "login_token=${LOGIN_TOKEN}&format=json" | jq .domains[0].id`
  1. 获取需要解析的子域名前缀,例如demo.zerchin.xyz`,那么就填写demo
1
SUB_DOMAIN="demo"
  1. 获取record ID,也就是子域名记录的ID
1
RECORD_ID=`curl -s -X POST https://dnsapi.cn/Record.List -d "login_token=${LOGIN_TOKEN}&format=json&domain_id=${DOMAIN_ID}&sub_domain=${SUB_DOMAIN}" | jq -r .records[0].id`
  1. record type

常用的记录类型:

A:用来指定域名的IP地址

CNAME:将域名指向到另一个域名上

1
RECORD_TYPE="A"
  1. 线路类型,我们选择默认就可以了,默认 == "0"
1
RECORD_LINE_ID="0"
  1. 原先记录的IP
1
OLD_IP=`curl -s -X POST https://dnsapi.cn/Record.List -d "login_token=${LOGIN_TOKEN}&format=json&domain_id=${DOMAIN_ID}&sub_domain=${SUB_DOMAIN}" | jq -r .records[0].value`

9. 完整脚本实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#! /bin/bash

LOGIN_TOKEN=`base64 -d /usr/local/dnspod-agent/dnspod-token`

IP=`curl ifconfig.me -s`

DOMAIN_ID=`curl -s -X POST https://dnsapi.cn/Domain.List -d "login_token=${LOGIN_TOKEN}&format=json" | jq .domains[0].id`

SUB_DOMAIN="demo"

RECORD_ID=`curl -s -X POST https://dnsapi.cn/Record.List -d "login_token=${LOGIN_TOKEN}&format=json&domain_id=${DOMAIN_ID}&sub_domain=${SUB_DOMAIN}" | jq -r .records[0].id`

RECORD_TYPE="A"

RECORD_LINE_ID="0"

OLD_IP=`curl -s -X POST https://dnsapi.cn/Record.List -d "login_token=${LOGIN_TOKEN}&format=json&domain_id=${DOMAIN_ID}&sub_domain=${SUB_DOMAIN}" | jq -r .records[0].value`

if [[ $OLD_IP != $IP ]];then
## modify record ip
curl -X POST https://dnsapi.cn/Record.Modify -d "login_token=${LOGIN_TOKEN}&format=json&domain_id=${DOMAIN_ID}&record_id=${RECORD_ID}&sub_domain=${SUB_DOMAIN}&value=${IP}&record_type=${RECORD_TYPE}&record_line_id=${RECORD_LINE_ID}"
echo `date +"%Y-%m-%d %H:%M:%S"` $IP >> /usr/local/dnspod-agent/dnspod_record_ip
fi

为防止频繁访问API被禁,建议DOMAIN_IDRECORD_ID这种不会变动的参数预先获取直接填入。

将上述脚本保存在/usr/local/dnspod-agent目录下,命名为dnspod-agent.sh,然后添加一条每分钟执行的定时任务即可:

1
2
chmod +x /opt/dnspod-agent/dnspod-agent.sh
* * * * * /opt/dnspod-agent/dnspod-agent.sh

基于公云DNS域名解析实现DDNS

公云是一个可以免费解析动态域名服务商,某些路由器集成了公云的DDNS,但是如果没有集成的话,也可以自行实现一个DDNS脚本,如下:

  1. 保存用户名密码到/usr/local/pubyun-agent目录下,命名为pubyun-token
1
2
mkdir -p /opt/pubyun-agent
echo -n "userName:password" | base64 > /opt/pubyun-agent/pubyun-token
  1. 完整脚本实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#! /bin/bash
## 获取当前主机IP
IP=`curl ifconfig.me -s`

PUBYUN_TOKEN=`base64 -d /usr/local/pubyun-agent/pubyun-token`

record_ip(){
curl -X POST -u ${PUBYUN_TOKEN} "http://members.3322.net/dyndns/update?system=dyndns&hostname=zerchin.f3322.net"
echo `date +"%Y-%m-%d %H:%M:%S"` $IP >> /usr/local/pubyun-agent/pubyun_record_ip
}

main() {
if [[ ! -f "/usr/local/pubyun-agent/pubyun_record_ip" ]];then
touch /usr/local/pubyun-agent/pubyun_record_ip
record_ip
else
if [[ `tail -n 1 /usr/local/pubyun-agent/pubyun_record_ip | awk '{print $3}'` != $IP && $IP != "" ]];then
record_ip
fi
fi
}
main

将上述脚本保存在/usr/local/pubyun-agent目录下,命名为pubyun-agent.sh,然后添加一条每分钟执行的定时任务即可:

1
2
chmod +x /opt/pubyun-agent/pubyun-agent.sh
* * * * * /opt/pubyun-agent/pubyun-agent.sh

腾讯云 DNS API 参考:https://docs.dnspod.cn/api/modify-records/

公云 DNS API 参考:https://www.pubyun.com/products/dyndns/download/