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,若有更新,恕不另行通知。