#20211007 更新

python2 版本太古老了,又弄了一个 golang 版本的,移植性更强:https://github.com/onns/ddns

主要用到两个 api:

#20210215 更新

大概写这个脚本的人也不知道原来会有一个个人用户的域名解析记录会有几十个,导致代码找不到解析记录…
修改了脚本,使得每次获取的记录数更多,如果还是找不到,自己去看一下翻页的方法吧,阿里云的文档压根儿没有,我也是醉了。

#前言

宿舍放着一台换下来的旧手机 Mi5,平时除了双开好像就没用过,抱着闲置物品再利用的原则,在上面装了个 centos 系统,但由于宿舍的宽带是动态 ip 的,如果每次都要手动重新解析域名,那也太麻烦了。于是想设定定时任务自动解析,折腾一番,记录之。

#安装环境

#pip

因为是最小化安装所以 pip 都没装…
直接官网安装即可

1
2
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py

#gcc

是的 gcc 也没有,要自己装。

1
yum install gcc -y

#aliyun-sdk

阿里云已经把框架写好了,我们直接调用就行,省去了自己造轮子的麻烦。

1
pip install aliyun-python-sdk-alidns

#代码

阿里云已经把框架写好了,我们直接调用就行,省去了自己造轮子的麻烦。

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

import json
import os
import re
import urllib2
from datetime import datetime

from aliyunsdkcore import client
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordInfoRequest
from aliyunsdkalidns.request.v20150109 import UpdateDomainRecordRequest

# 阿里云 Access Key ID
access_key_id = ""
# 阿里云 Access Key Secret
access_key_secret = ""
# 阿里云 一级域名
rc_domain = 'onns.xyz'
# 阿里云 二级域名前缀
rc_subdomain = 'xm'
# 返回内容格式
rc_format = 'json'


def check_records(dns_domain):
"""
获取域名的解析信息
"""
clt = client.AcsClient(access_key_id, access_key_secret, 'cn-hangzhou')
request = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
request.set_DomainName(dns_domain)
request.set_accept_format(rc_format)
request.set_PageSize(100)
result = clt.do_action(request)
result = json.JSONDecoder().decode(result)
return result


def get_old_ip(record_id):
"""
根据域名解析记录ID查询上一次的IP记录
"""
clt = client.AcsClient(access_key_id, access_key_secret, 'cn-hangzhou')
request = DescribeDomainRecordInfoRequest.DescribeDomainRecordInfoRequest()
request.set_RecordId(record_id)
request.set_accept_format(rc_format)
result = clt.do_action(request)
result = json.JSONDecoder().decode(result)
result = result['Value']
return result


def update_dns(dns_rr, dns_type, dns_value, dns_record_id, dns_ttl, dns_format):
"""
更新阿里云域名解析记录信息
"""
clt = client.AcsClient(access_key_id, access_key_secret, 'cn-hangzhou')
request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
request.set_RR(dns_rr)
request.set_Type(dns_type)
request.set_Value(dns_value)
request.set_RecordId(dns_record_id)
request.set_TTL(dns_ttl)
request.set_accept_format(dns_format)
result = clt.do_action(request)
return result


def get_my_publick_ip():
"""
获取当前主机的外网IP
"""
try:
u = urllib2.urlopen('http://members.3322.org/dyndns/getip')
return u.read().strip('\n')
except HTTPError as e:
print('getMyIp:', e)
return None


def write_to_file(new_ip):
time_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
write_log = open('aliyun_ddns.txt', 'a')
write_log.write(time_now + ' ' + str(new_ip) + '\n')
return


if __name__ == '__main__':
# 之前的解析记录
old_ip = ""
record_id = ""
dns_records = check_records(rc_domain)
for record in dns_records["DomainRecords"]["Record"]:
if record["Type"] == 'A' and record["RR"] == rc_subdomain:
record_id = record["RecordId"]
print "%s.%s recordID is %s" % (rc_subdomain, rc_domain, record_id)
if record_id != "":
old_ip = get_old_ip(record_id)

if record_id == "":
exit("Record ID error!")
old_ip = get_old_ip(record_id)
# 获取主机当前的IP
now_ip = get_my_publick_ip()
print "now host ip is %s, dns ip is %s" % (now_ip, old_ip)

if old_ip == now_ip:
print "The specified value of parameter Value is the same as old"
else:
rc_rr = rc_subdomain # 解析记录
rc_type = 'a' # 记录类型, DDNS填写A记录
rc_value = now_ip # 新的解析记录值
rc_record_id = record_id # 记录ID
rc_ttl = '600' # 解析记录有效生存时间TTL,单位:秒

print update_dns(rc_rr, rc_type, rc_value, rc_record_id, rc_ttl, rc_format)

write_to_file(now_ip)

代码拷贝自:阿里云 DNS 动态解析,略作修改。
这里只需要改前几行(15-22 行)的值即可,阿里云的accesskey这里获取。

#执行

可以手动先执行一下命令看下结果。

1
2
3
4
5
$ python ddns.py

xm.onns.xyz recordID is XXXXXXXXXXXXXXX
now host ip is XXXXXXXXXXXXXXX, dns ip is XXXXXXXXXXXXXXX
{"RecordId":"XXXXXXXXXXXXXXX","RequestId":"XXXXXXXXXXXXXXX"}

接着设置 crontab 定时任务:

1
2
3
4
crontab -e

# 添加如下一条记录,为了避免错误,写绝对地址。
*/10 * * * * /usr/bin/python /home/android/ddns.py /dev/null 1>/dev/null

很尴尬的是,不仅仅是最小化安装,连一些 service 的服务都没有写入,所以要手动打开…crontab

1
sudo /usr/sbin/crond -s

然后就可以愉快的使(wan)用(shua)了。

#参考文档