ddns的用处自然不用多说了。凡是在家里跑的什么盒子啊,板子啊的,都希望给他们一个域名,这样从外网就能直接访问机器上的各种服务和资源了。家里面的网络,一般都是动态分配IP的,ISP会不定期的改变分配给我们的IP,那么这就需要机器定期的向ddns服务器更新家里面的实时的IP,从而保证域名能够解析到正确的IP地址上。
有很多的ddns的服务都可以使用,花生壳,3322,还有国外的一大堆如no-ip这样的免费ddns的服务可以使用。但是有一个限制就是如果使用他们的免费的服务的话,分配给你的域名一般是服务商自己的二级域名,比如使用3322的服务的话,分配给我的域名就是像”proudj.3322.net”这样的域名。如果想给家里的机器分配一个自己手上拥有自己的域名的二级域名,比如我想给家里的路由器分配一个我自己的proudj.com这个域名的二级域名home.proudj.com,那么一般的服务商要么不支持,要么要收费。
有没有免费的方案呢?我的proudj.com这个域名是在DNSPod做解析的,Google了一下发现,实际上DNSPod是开放了ddns的API的。也就是说是支持ddns的功能的。但是我对如何使用DNSPod的API根本不了解,所以就开始搜搜看有没有一些现成的客户端。网上有不少客户端,基于各种语言实现的都有,但是因为我是想用在WR720N上,就想用shell脚本模式的,一来openwrt上本来就自带shell环境,二来如果是Python这样的客户端,不知道运行起来,WR720N这样的32M内存是不是吃得消。于是在网上搜索shell脚本的实现,实际上网上也有不少版本的shell脚本,但是跑在我的openwrt上,总是会有各种各样的问题。之前因为脚本内容比较长,根本就没看怎么实现,这几天大概看了一下别人的脚本的实现,发现要实现一个简单的DNSPod的ddns的客户端,实际上很简单。
需求:
给家里的openwrt路由器分配一个叫做”home.proud.com”的域名。这样,以后访问路由器的服务和资源的时候,就不需要知道路由器当时的IP地址了,可以直接通过域名进行操作。
实现原理:
在openwrt本机访问链接“https://dnsapi.cn/Record.Ddns”,DNSPod服务器端在收到这个连接请求后会记下访问者的IP地址并用它来更新域名的IP地址。
使用工具:
命令行的curl工具。
curl可以作为http的客户端,去访问链接,还能够返回服务器的相应内容。是很方便的一个命令,在Openwrt上需要单独安装。
所以,实际上DNSPod上使用ddns是非常简单的。只要访问指定的链接就OK了!仅此而已,其他什么事情都不用做了!!
但是,什么都有个但是。这件事情说来确实简单,不过在使用上面的链接的时候,我们还得输入几个参数。这是很容易理解的,既然原理是通过访问api提供的链接,而DNSPod服务器通过解析发送者的IP来确定我们的IP。如此而已,那么我们显然要在访问这个链接的带上上指明了这个解析出来的IP是给哪个域名使用的,不是么?要不然DNSPod是解析出来了我们的IP,但是它哪里知道这个IP是用来更新哪个域名的呢?
那么,查一下DNSPod的API,就会发现实际上访问上面的链接的完整的格式是如下:
curl -X POST https://dnsapi.cn/Record.Ddns -d ‘login_email=api@dnspod.com&login_password=password&format=json&domain_id=2317346&record_id=16894439&record_line=默认&sub_domain=www’
上面的链接中有几个重要的参数:
login_email/login_password:
DNSPod的账户的用户名和密码,访问上面的链接,是需要做验证的,你必须要证明自己是某个域名的拥有着才行,要不然的话,大家可以随便随便更新,那有人恶性的想篡改别人的域名咋办呢。
domain_id/record_id:
如果我想访问上面的链接,目的是home.proudj.com这个域名更新IP。那么能想到的最简单的方法就是在链接里面把这个域名作为一个参数直接带上。但是,API没有采用这个方式,而是采用了domain_id/record_id的方式。我们在DNSPod可能托管了好多个域名解析,那么每一个域名都有一个唯一的数字,就是domain_id(代表proudj.com)。那对于某个域名,我们可能设置了好多的二级域名。那么对于每一个二级域名都有一个唯一的数字,就是record_id(代表home)。所以实际上可以看出来,domain_id+record_id就能够代表上面的”home.proudj.com”这个完整的二级域名了。
那么,怎么获取domain_id和record_id呢,其实也很简单,还是需要访问API提供的链接就行了,不过是不同的链接。
简单的流程就是,通过获取用户的域名列表能够得到属于你的所有的域名,同时也就能得到每个域名的id,查找到目标域名的domain_id之后,通过另外一个链接查找目的域名的record,能够找到所有的record。得到目的record_id之后就能够调用上面的链接更新IP啦!
下面的这个脚本就是简单的一个实现(这个脚本是 别人抄来的,但是找不到作者了):
#!/bin/sh # usage: ./dnspod.sh ddns.conf #contents of file "ddns.conf" defines some variables which is like below: #ACCOUNT="XXX" #PASSWORD="XXX" #DOMAIN="XXX" #RECORD_LINE="默认" if [ "$#" != 1 ];then echo "param error." exit 0 fi #从配置文件里面读出用户名/密码以及需要做ddns的域名等等信息 dnspod_load_config(){ cfg=$1; content=`cat ${cfg}`; ACCOUNT=`echo "${content}" |grep 'ACCOUNT'| sed 's/^ACCOUNT=[\"]\(.*\)[\"]/\1/'`; PASSWORD=`echo "${content}" |grep 'PASSWORD'| sed 's/^PASSWORD=[\"]\(.*\)[\"]/\1/'`; DOMAIN=`echo "${content}" |grep 'DOMAIN='| sed 's/^DOMAIN=[\"]\(.*\)[\"]/\1/'`; RECORD_LINE=`echo "${content}" |grep 'RECORD_LINE'| sed 's/^RECORD_LINE=[\"]\(.*\)[\"]/\1/'`; SUBDOMAIN=${DOMAIN%%.*} DOMAIN=${DOMAIN#*.} } #通过DNSPOD的api得到需要做ddns的域名的 record id dnspod_domain_get_id(){ #调用API查找domain_id(比如我的proudj.com的id) options="login_email=${ACCOUNT}&login_password=${PASSWORD}"; out=$(curl -s -k https://dnsapi.cn/Domain.List -d ${options}); for line in $out;do if [ $(echo $line|grep '' |wc -l) != 0 ];then DOMAIN_ID=${line%<*}; DOMAIN_ID=${DOMAIN_ID#*>}; fi if [ $(echo $line|grep '' |wc -l) != 0 ];then DOMAIN_NAME=${line%<*}; DOMAIN_NAME=${DOMAIN_NAME#*>}; if [ "$DOMAIN_NAME" = "$DOMAIN" ];then break; fi fi done #查找record_id,也就是子域名home.proudj.com的id out=$(curl -s https://dnsapi.cn/Record.List -d "${options}&domain_id=${DOMAIN_ID}") for line in $out;do if [ $(echo $line|grep '' |wc -l) != 0 ];then RECORD_ID=${line%<*}; RECORD_ID=${RECORD_ID#*>}; #echo "record id: $RECORD_ID"; fi if [ $(echo $line|grep '' |wc -l) != 0 ];then RECORD_NAME=${line%<*}; RECORD_NAME=${RECORD_NAME#*>}; if [ "$RECORD_NAME" = "$SUBDOMAIN" ];then break; fi fi done } #更新域名的ip地址 dnspod_update_record_ip(){ options="login_email=${ACCOUNT}&login_password=${PASSWORD}"; curl -k -s https://dnsapi.cn/Record.Ddns -d "${options}&domain_id=${DOMAIN_ID}&record_id=${RECORD_ID}&sub_domain=${RECORD_NAME}&record_line=${RECORD_LINE}" } #主函数 main(){ dnspod_load_config $1 dnspod_domain_get_id dnspod_update_record_ip } main $1
有了上面的脚本,我们所需要做的就是定期的运行这个脚本就行了。一般放到crontab里面去定期的执行,我一般是15分钟更新一次。