醉卧草庐听风雨

君子藏器于身,待时而动

0%

shell实现dnspod的ddns

年初时在家远程办公时安装了电信的宽带,实际使用中发现居然是分配了一个公网IP。于是一个想要干点什么的想法就冒出来了,为此我特意买了一块类似树莓派的开发版当服务器,虽然性能不是很强但是用来折腾一二还是够了。但是问题是IP是变化的需要使用ddns的技术注册对应IP地址。之前一直使用的是cloudflare来实现,但是后面发现它丫的免费用户不支持tk、gq、cf、ml这类免费域名使用API了,只能另寻它法,后来瞄准了dnspod,它有成熟的API文档对免费用户也足够友好,目前网上是有很多关于dnspod的ddns脚本,然而不折腾一下自己写一个心有不甘,于是就有了下面这些内容。

实现思路

  • 比对dns服务器中记录的IP值与实际IP值是否一致,一致则退出
  • 对比dnpod中的值与实际IP值是否一致,一致则退出
  • 全部不一致则表示需要更新,提取相关记录信息,调用API进行更新

网上很多脚本实际上是缺少第一步的,即直接请求了dnspod中的记录值进行对比更新。但如果先向dns服务器查询的话就可以大大的减少对dnspod的API访问,毕竟在API说明中是有频次限制的。但是在某些情况下dns的传播是需要时间的,这时就有可在第二步被挡下,毕竟dnspod的记录值是一致的了就不必更新了。关于记录值的更新官方是这么讲的,

如果1小时之内,提交了超过5次没有任何变动的记录修改请求,该记录会被系统锁定1小时,不允许再次修改。比如原记录值已经是 1.1.1.1,新的请求还要求修改为 1.1.1.1

不过用了两层保护机制被锁定的几率还是很低的。

如何使用

准备一个待使用的域名,将其NS的管理接入dnspod中,添加一个a记录名字任意,这里就使用的是ddns,在dnspod的密钥控制台创建密钥,按提示保存密钥的ID和Token。下面就是脚本的全貌:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#/bin/bash

getRecord(){
echo $1 | tr ',' '\n' | grep -P "^$2:" | cut -d: -f2
}
# 密钥ID
API_ID=xxxxxxx
# 密钥Token
API_TOKEN=xxxxxxxxxxxxxxxxxxxxx
# 域名
DOMAIN=xxxxx.xxx
# 二级域名
SUB_DOMAIN=xxxx

# 获取DNS记录中的IP
REMOTE_IP=`dig +short $SUB_DOMAIN.$DOMAIN`
echo $REMOTE_IP
# 获取本地外网IP
LOCAL_IP=`dig +short myip.opendns.com @resolver1.opendns.com`
echo $LOCAL_IP
if test $REMOTE_IP = $LOCAL_IP
then
echo 'No change in IP'
# 于dns中的值一致,退出
exit 0
fi

echo 'Start to modify IP'

# 查询dnspod中记录值
DNSPOD_PARAM="login_token=$API_ID,$API_TOKEN&format=json&domain=$DOMAIN"
DNSPOD_VALUE=`curl -s -X POST https://dnsapi.cn/Record.List -d $DNSPOD_PARAM`
echo $DNSPOD_VALUE

RECORD_VALUE=`echo $DNSPOD_VALUE | tr '{' '\n' | grep "\"$SUB_DOMAIN\"" | sed 's/"//g'`
echo "$SUB_DOMAIN dnspod value $RECORD_VALUE"

# 提取记录中的相关参数
RECORD_ID=`getRecord "$RECORD_VALUE" 'id'`
RECORD_IP=`getRecord "$RECORD_VALUE" 'value'`
RECORD_TYPE=`getRecord "$RECORD_VALUE" 'type'`
RECORD_LINE_ID=`getRecord "$RECORD_VALUE" 'line_id'`

if test $LOCAL_IP = $RECORD_IP
then
echo 'dnspod ip is same with local ip'
# 与记录中的值一致,退出
exit
fi
# 填充参数更新
RECORD_PARAM="record_id=$RECORD_ID&sub_domain=$SUB_DOMAIN&value=$LOCAL_IP&record_type=$RECORD_TYPE&record_line_id=$RECORD_LINE_ID"
echo $RECORD_PARAM
curl -X POST https://dnsapi.cn/Record.Modify -d "$DNSPOD_PARAM&$RECORD_PARAM"

将上述shell脚本保存在文件中,替换其中开始的xxxxxx参数,接着利用linux本身自带的cron定时执行器*/1 * * * * /data/bin/ddns/ddns.sh > /dev/null来实现自动更新的目的。

写在最后

当然这个脚本可以扩充改进的地方其实还有很多,比如:二级域名可以使用数组 达到批量更新多个二级域名的目的,当然目前这个脚本对于我来讲已经是足够使用的了,希望这个ddns的脚本可以帮助你。