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

DDNS 简介

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

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

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

一些可能用到的库

pip install aliyun-python-sdk-core pip install aliyun-python-sdk-alidns pip install pyyaml 

获取和缓存 IP 地址

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

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

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

from urllib.request import urlopen import logging class IPManager: def __init__(self, file_cache=".ipbuffer"): self.ip = "" self.file_cache = file_cache def get_current_ip(self):  with urlopen('http://www.3322.org/dyndns/getip') as response: self.ip = str(response.read(), encoding='utf-8').replace("\n", "") logging.info("current ip: " + self.ip) return self.ip def sync_cache(self):  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 os def 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("") 
def main():  ip_manager = IPManager()  current_ip = ip_manager.get_current_ip()  if ip_manager.get_cache() == current_ip: return  ip_manager.sync_cache() 

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

获取 accessKeyId 和 accessKeySecret

创建连接阿里云的客户端

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

把上一步的 accessKeyIdaccessKeySecret 填进去。

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

域名解析记录查询

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

from aliyunsdkalidns.request.v20150109.DescribeDomainRecordsRequest import DescribeDomainRecordsRequest import json import logging def 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.v20150109.AddDomainRecordRequest import AddDomainRecordRequest import logging import json def 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.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest import logging import json def 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
  • 把查询、更新、添加域名解析记录封装成一个类

获取完整的代码

原文链接:https://blog.csdn.net/qq_33384402/article/details/109272008?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168510975416800211594719%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=168510975416800211594719&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-21-109272008-null-null.268%5Ev1%5Econtrol&utm_term=NAS%E3%80%81%E7%BE%A4%E6%99%96%E3%80%81%E9%98%BF%E9%87%8C%E4%BA%91%E3%80%81%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90%E3%80%81%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E3%80%81ipv6%E3%80%81ddns%E3%80%81%E8%BD%BB%E9%87%8F%E7%BA%A7%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%81%E9%93%81%E5%A8%81%E9%A9%AC%E3%80%81%E5%A8%81%E8%81%94%E9%80%9A%E3%80%81DSM%E3%80%81DSM6.0%E3%80%81%E7%BE%A4%E6%99%96nas%E3%80%81%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%81%E8%9C%97%E7%89%9B%E6%98%9F%E9%99%85%E3%80%81%E9%BB%91%E7%BE%A4%E6%99%96%E3%80%81docker%E3%80%81%E5%AE%B9%E5%99%A8%E9%95%9C%E5%83%8F%E3%80%81%E5%9F%9F%E5%90%8D%E6%B3%A8%E5%86%8C%E3%80%81%E5%AE%9D%E5%A1%94%E3%80%81%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E3%80%81nginx%E3%80%81frp%E3%80%81%E5%8A%A8%E6%80%81%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享