700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Python实现阿里云DDNS动态域名解析

Python实现阿里云DDNS动态域名解析

时间:2019-05-12 07:51:45

相关推荐

Python实现阿里云DDNS动态域名解析

想要更好的阅读体验,可以转我的个人博客。

DDNS 简介

DDNS(Dynamic Domain Name Server),它的作用是将用户的动态IP绑定到一个域名上去。

这样就算你的服务器IP发生了变化,用户仍然可以使用你的域名找到你的服务器。

阿里云提供了一套API,可以让你用编程的方式实现 DDNS,但是需要你的域名是在阿里云上申请的。

感谢我的室友借用给我测试用的域名。

一些可能用到的库

pip install aliyun-python-sdk-corepip install aliyun-python-sdk-alidnspip install pyyaml

获取和缓存 IP 地址

先写一个简单的工具类,可以获取当前电脑的公网IP地址,有很多提供这类服务的网站,本例程采用/dyndns/getip。

获取 IP 之后最好再把它缓存在一个文件中。

之所以需要缓存是因为阿里云更新两条一样的IP时会报错,我们可以提前缓存,然后下次调用更新服务之前借用缓存的内容,判断当前的 IP 是否无变化。

定义 IPManager 类

定义一个IPManager类,可以获取本机的公网IP地址,并使用文件进行缓存。

from urllib.request import urlopenimport loggingclass IPManager:def __init__(self, file_cache=".ipbuffer"):self.ip = ""self.file_cache = file_cachedef get_current_ip(self):# 获取当前的 IPwith urlopen('/dyndns/getip') as response:self.ip = str(response.read(), encoding='utf-8').replace("\n", "")logging.info("current ip: " + self.ip)return self.ipdef sync_cache(self):# 同步当前的 IP 到缓存with open(self.file_cache, "w") as f:f.write(self.ip)logging.info("sync cache ip: " + self.ip)def get_cache(self):# 获取缓存的内容with open(self.file_cache, "r") as f:old_ip = f.read()logging.info("get cache ip: " + self.ip)return old_ip

程序默认使用.ipbuffer文件存储 IP,我觉得我们还需要先创建这个文件,不然运行的时候可能会报错

可以使用下面的函数检查和创建一个文件,支持递归创建:

import osdef check_file(filename):# 获取父文件夹dirname = os.path.dirname(filename)if not os.path.exists(dirname) and dirname != "":# 递归创建父文件夹os.makedirs(dirname)# 创建文件with open(filename, "w") as f:f.write("")

IPManager 的简单使用

def main():# 创建一个 IPManagerip_manager = IPManager()# 获取当前的 IPcurrent_ip = ip_manager.get_current_ip()# 如果 IP 已经缓存就返回if ip_manager.get_cache() == current_ip:return# 更新 IP 缓存ip_manager.sync_cache()

这个程序可以获取IP并且在IP无缓存或者IP更新的时候更新缓存。

获取 accessKeyId 和 accessKeySecret

云账号登录RAM控制台。在左侧导航栏的人员管理菜单下,单击用户。在用户登录名称/显示名称列表下,单击目标RAM用户名称。在用户AccessKey区域下,单击创建新的AccessKey

摘抄自 阿里云文档

创建连接阿里云的客户端

from aliyunsdkcore.client import AcsClientprofile = {"accessKeyId": "xxx","accessKeySecret": "xxx","regionId": "cn-hangzhou"}client = AcsClient(profile["accessKeyId"], profile["accessKeySecret"], profile["regionId"])

把上一步的accessKeyIdaccessKeySecret填进去。

regionId填写你的区域号,关于regionId的说明,可以见 阿里云官方文档。

我们需要借助client.do_action_with_exception这个函数来发送请求到阿里云。

域名解析记录查询

之所以需要加一步域名解析记录查询是为了校验我们的域名是否已经被其他的 IP 绑定了。

from aliyunsdkalidns.request.v0109.DescribeDomainRecordsRequest import DescribeDomainRecordsRequestimport jsonimport loggingdef describe_domain_records(client, record_type, subdomain):logging.info("域名解析记录查询")request = DescribeDomainRecordsRequest()request.set_accept_format('json')request.set_Type(record_type)request.set_DomainName(subdomain)response = client.do_action_with_exception(request)response = str(response, encoding='utf-8')result = json.loads(response)logging.debug(result)return result

client是上一步创建的客户端。

record_type比较复杂,简单来说是DNS域名解析的解析类型。我们这里使用A记录就好了。

{% note info %}

常见的 DNS解析类型

A: 将主机名(或域名)指向一个 IPv4 地址

AAAA: 将主机名(或域名)指向一个 IPv6 地址

CNAME: 将域名指向另一个域名

{% endnote %}

subdomain填你的域名就好了。

# 调用举例describe_domain_records(client, "A", "tuenity.xyz")

添加域名解析记录

from aliyunsdkalidns.request.v0109.AddDomainRecordRequest import AddDomainRecordRequestimport loggingimport jsondef add_record(client, priority, ttl, record_type, value, rr, domain_name):logging.info("添加域名解析记录")request = AddDomainRecordRequest()request.set_accept_format('json')request.set_Priority(priority)request.set_TTL(ttl)request.set_Value(value)request.set_Type(record_type)request.set_RR(rr)request.set_DomainName(domain_name)response = client.do_action_with_exception(request)response = str(response, encoding='utf-8')result = json.loads(response)logging.debug(result)return result

priority告诉域名解析服务,按照priority从小到大的顺序对记录搜索,搜索到匹配的记录后,就停止搜索priority值更大的记录,对于拥有相同priority的记录将通过weight再次选择

虽然阿里云并不提供weight的设置接口,但是你要知道它是个什么东西。

对于拥有相同priority的多条记录,weight给出了选择某条记录的几率,值越大,被选中的概率就越大,合理的取值范围为0-65535

ttl( Time to live ),当用户在访问一个域名的时候,并不是每次都需要去解析一遍的,DNS服务器会在用户当地的递归DNS服务器上缓存一次,在ttl的时间长度内失效。一般设置 “600”。

record_type同上一步。

value就是你的IP地址

rr,阿里云的rr是主机头的意思,一般设置 “www”。

domain_name就是你的域名。

更新域名解析记录

from aliyunsdkalidns.request.v0109.UpdateDomainRecordRequest import UpdateDomainRecordRequestimport loggingimport jsondef update_record(client, priority, ttl, record_type, value, rr, record_id):logging.info("更新域名解析记录")request = UpdateDomainRecordRequest()request.set_accept_format('json')request.set_Priority(priority)request.set_TTL(ttl)request.set_Value(value)request.set_Type(record_type)request.set_RR(rr)request.set_RecordId(record_id)response = client.do_action_with_exception(request)response = str(response, encoding='utf-8')logging.debug(response)return response

和上一步的函数接口几乎一摸一样,不过多解释了。

需要注意,不一样的是record_id。这个需要describe_domain_records函数的返回值。

des_result = describe_domain_records(client, "A", "tuenity.xyz")

使用des_result["TotalCount"]就可以查处现在有多少条记录绑定在这个域名上了。

如果没有,我们就需要调用add_record,否则就调用update_record

record_id可以通过des_result["DomainRecords"]["Record"][0]["RecordId"]获取。

改造、封装建议

使用 yaml 来作为配置文件使用 python 自带的日志 logging把查询、更新、添加域名解析记录封装成一个类

获取完整的代码

Github 项目地址

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。