0x01 前言
阿里云
以下是很久以前的文章:
0x02 准备
阿里云的API已经支持python3,所以我将使用python3编写整个脚本。windows的朋友则需要自行配置python3的环境,以便使用相关命令。
然后使用以下命令安装相关模块:
#安装阿里云SDK核心-v3版本 [root@web ~]# pip3 install aliyun-python-sdk-core-v3 #安装阿里云alidns服务SDK [root@web ~]# pip3 install aliyun-python-sdk-alidns #安装requests模块 [root@web ~]# pip3 install requests
准备好相关模块后,还需要准备阿里云DNS解析的一些信息:
- access key id
- access key secret
- 一级域名
- 子域名
- ttl
其中第3、4项中的内容需要注意,例如我想用“home.ngx.hk”作为DDNS的域名,那么第3、4项应该是这样的:
- 一级域名:ngx.hk
- 子域名:home
而TTL则需要根据你所购买的DNS VIP服务细则内所允许的最小TTL来配置,建议设置为10,这样更符合DDNS服务的及时性与有效性。
最后是下载脚本,通过以下命令从我的私有gitlab中下载脚本:
[root@web ~]# git clone https://gitlab.ngx.hk/aliyun/DDNS.git
或者直接下载压缩包:
[root@web ~]# wget https://gitlab.ngx.hk/aliyun/DDNS/repository/master/archive.zip
0x03 脚本
再继续往下配置之前,我们先来看看脚本的内容。
为了提高安全性,我将需要配置的信息都迁移至外部的配置文件中,所以脚本开始会先检查配置文件是否存在于json格式是否有误:
# 尝试打开配置文件
try:
config_r = open(sys.path[0] + '/config.json', 'r')
except Exception as e:
print('An error occurred, open config file fail! Error MSG: ')
print(e)
print('Script exit!')
sys.exit(0)
else:
config_content = config_r.read()
# 尝试格式化配置文件
try:
config_json = json.loads(config_content)
except Exception as e:
print('Load json fail, please recheck config file! Error MSG: ')
print(e)
print('Script exit!')
sys.exit(0)
else:
pass
配置文件通过检查后,将各种信息分别赋值至变量:
# 定义变量 rc_access_key_id = config_json['access_key_id'] rc_access_Key_secret = config_json['access_Key_secret'] rc_domain = config_json['domain'] rc_sub_domain = config_json['sub_domain'] rc_ttl = config_json['ttl']
以上是配置信息的配置、获取与定义阶段。
紧接着需要定义各类函数,首先是获取本地网络公网的IP:
# 通过淘宝API获取本地公网IP
def my_ip():
get_ip_method = requests.get('http://ip.taobao.com/service/getIpInfo.php?ip=myip').content.decode()
get_ip_value = json.loads(get_ip_method)
get_ip_value = get_ip_value['data']['ip']
return get_ip_value
这里使用requests模块访问阿里云的IP库服务,获取本地IP的相关信息并解析。
因为这个脚本已经去除手动获取子域名ID的部分,所以我需要编写一个模块以便自动检索:
# 获取域名信息
# 输出格式:[RecordId, Value]
def get_record_info():
clt = client.AcsClient(rc_access_key_id, rc_access_Key_secret, 'cn-hangzhou')
request = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
request.set_DomainName(rc_domain)
request.set_accept_format('json')
try:
result = clt.do_action_with_exception(request)
except Exception as f:
return 'An error occurred! Error MSG: ' + str(f)
else:
result = result.decode()
result_dict = json.JSONDecoder().decode(result)
result_list = result_dict['DomainRecords']['Record']
result = []
for i in result_list:
if rc_sub_domain == i['RR']:
result.append(i['RecordId'])
result.append(i['Value'])
break
return result
使用账户信息与域名访问阿里云的API,调取该域名下的所有子域的解析记录,然后循环比对是否存在目标子域,如果是,则返回相关列表,否则返回空列表。
如果子域已经存在,当IP发生变动时,则更新该子域即可,相关模块如下:
# 更新子域名信息
def update_dns(dns_value, dns_record_id):
clt = client.AcsClient(rc_access_key_id, rc_access_Key_secret, 'cn-hangzhou')
request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
request.set_RR(rc_sub_domain)
request.set_Type('A')
request.set_Value(dns_value)
request.set_RecordId(dns_record_id)
request.set_TTL(rc_ttl)
request.set_accept_format('json')
result = clt.do_action_with_exception(request)
return result
需要注意的是,我将解析类型规定为A记录,因为需要写入IP地址,如果需要改为其他解析类型,请手动修改。如果可以,修改为TXT记录可以有效提高安全性。
如果子域不存在,则需要新增解析记录,相关模块如下:
# 新增子域名解析
def add_dns(dns_value):
clt = client.AcsClient(rc_access_key_id, rc_access_Key_secret, 'cn-hangzhou')
request = AddDomainRecordRequest.AddDomainRecordRequest()
request.set_DomainName(rc_domain)
request.set_RR(rc_sub_domain)
request.set_Type('A')
request.set_Value(dns_value)
request.set_TTL(rc_ttl)
result = clt.do_action_with_exception(request)
return result
同样的,默认记录类型为A记录,如有需要请手动修改。
最后是日志写入模块:
# 写入日志
def write_to_file(dns_value, dns_output):
time_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
write = open(sys.path[0] + './aliyun_ddns.log', 'a')
write.write(time_now + ' ' + str(dns_value) + ' ' + dns_output + '\n')
write.close()
一切准备就绪后,就可以开始执行了:
# 运行
if __name__ == '__main__':
result_list = get_record_info()
current_ip = my_ip()
if len(result_list) == 0:
aliyun_output = add_dns(current_ip).decode()
write_to_file(current_ip, aliyun_output)
print(aliyun_output)
else:
result_record_id = result_list[0]
old_ip = result_list[1]
if old_ip == current_ip:
print('The specified value of parameter Value is the same as old')
else:
aliyun_output = update_dns(current_ip, result_record_id).decode()
write_to_file(current_ip, aliyun_output)
print(aliyun_output)
0x04 执行
在执行之前需要将config.json.template这个文件重命名为config.json,然后填写该文件内的信息并再三确认!但请勿修改该文件的格式与符号。
{
"access_key_id": "",
"access_Key_secret": "",
"domain": "",
"sub_domain": "",
"ttl": ""
}
最后通过以下命令调用脚本:
[root@web ~]# python3 /usr/local/services_data/shell/DDNS/aliyun_ddns.py
如果希望可以定时执行,请执行以下命令:
#打开并修改crontab [root@web ~]# vim /etc/crontab #在文件底部粘贴此行 */2 * * * * root python3 /usr/local/services_data/shell/DDNS/aliyun_ddns.py
粘贴完成后保存并退出即可,然后使用以下命令重启crontab:
[root@web ~]# systemctl restart crond.service
上面的计划任务语句的意义为:每2分钟执行一次该DDNS脚本。
至此,所有配置均已结束。每次DNS修改时,都会有新的日志条目增加至日志中,并且阿里云也会发送一封邮件告知账户所有者,DNS解析变更的详细内容。
0x05 结语
请大家持续关注我的私有gitlab,若有更新,恕不另行通知。





















