本文最后更新于:2025年4月14日 晚上
在DDNS 动态域名服务 中介绍了DDNS的含义,本文记录:使用python语言,基于百度域名解析更新API,封装设计成自动同步本地IP的DDNS工具。
前置条件
具有 DDNS 需求 (IPv4 或 IPv6)
申请了百度云域名 (其他家的域名本文方法不适用)
了解DDNS (DDNS 动态域名服务 )
可以运行python程序
核心实现
将百度 API 中的 DNS 更新模块 封装成一个工程,简单介绍功能和核心实现
功能
动态获取本机指定 IP
自动对比当前本地 IP 与域名指向的IP
当本地 IP 发生变化时自动向远程同步
可以同步 A 记录(IPv4)和 AAAA 记录(IPv6)
可以配置同步频率,同步IP类型
保留较为完整的日志
获取本机 IP
获取本机IP 的核心代码,可以获取 IPv4 或 IPv6 的地址
1 2 3 4 5 6 7 8 9 def getIP (self, ip_type ): assert ip_type in self.IP_TYPE if ip_type == 'ipv4' : res = requests.get('https://checkip.amazonaws.com' ).text.strip() elif ip_type == 'ipv6' : res = requests.get('https://v6.ident.me' ).text else : raise RuntimeError(f"unknown ip type {ip_type} " ) return res.upper()
其中 ip_type
为IP类型,可为 IPv4
或 IPv6
获取当前 DNS 信息
需要获取当前DNS 状态,以判断是否需要更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def get_domain_info (self, domain ): data={ 'domain' :self.url, 'pageNo' :1 , 'pageSize' :100 } url="/v1/domain/resolve/list" res=self.post(url,data) decoded_res = res.decode() json_part = decoded_res[decoded_res.find('\r\n{' ) + 2 : decoded_res.find('}\r\n' ) + 1 ] clean_json_part = json_part.replace('\r' , '' ).replace('\n' , '' ) pattern = r'{"recordId":[^"]+,"domain":"' + domain + r'","view":"[^"]+","rdtype":"[^"]+","ttl":[^"]+,"rdata":"[^"]+","zoneName":"[^"]+","status":"[^"]+"}' searchObj = re.search(pattern, clean_json_part, flags=0 ) assert searchObj is not None , f"get_domain_info failed" domain_str = clean_json_part[searchObj.span()[0 ]:searchObj.span()[1 ]] domain_info = json.loads(domain_str) return domain_info
更新DNS记录
构造更新DNS所需的报文格式
注意 :如果地址为 IPv6,地址中的字母需要大写
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 def SET (self, domain, ip_type, logger ): assert ip_type in self.IP_TYPE logger("ddns ready to update data. " ) try : local_ip = self.getIP(ip_type) logger(f"get local IP: {local_ip} " ) except Exception as e: logger(f"get local IP failed, exception {e} " ) return False if ip_type == 'ipv4' : rd_type = 'A' elif ip_type == 'ipv6' : rd_type = 'AAAA' else : raise RuntimeError(f"unknown ip_type {ip_type} " ) logger(f"ip type {rd_type} " ) try : domain_info=self.get_domain_info(domain) logger(f"get domain info: {domain_info} " ) dns_ip = domain_info['rdata' ].upper() recordId = domain_info['recordId' ] except Exception as e: logger(f"get domain_info failed, exception {e} " ) return False if local_ip!=dns_ip: logger(f"local IP changed, a update will be launched." ) url="/v1/domain/resolve/edit" data={ "domain" : domain, "rdType" : rd_type, "rdata" : local_ip, "ttl" : 60 , "zoneName" : self.url, "recordId" : recordId } res=self.post(url, data) res_str = res.decode() split_lit = res_str.split(' ' ) if int (split_lit[1 ]) != 200 : logger(f"DDNS update failed, error code {split_lit[1 ]} " ) logger(f"http responce: {res_str} " ) else : logger("DDNS update successfully !!!" ) else : logger("local IP is same as reomte IP, skip updating." )
其中 logger
为日志对象
DDNS 配置使用
下载代码
1 git clone git @git.zhlh6.cn:zywvvd/baidu_ddns.git
更改配置
在assets/config.json
中配置域名
、Access Key
、Secret Key
在 main.py
文件中配置检测时间间隔
,二级域名名称
,IP类型
运行程序
示例日志
1 2 3 4 5 6 7 8 9 2022 -01 -02 00 :43 :21 : ************************************************************2022 -01 -02 00 :43 :21 : ****************** Baidu DDNS start !!! ******************2022 -01 -02 00 :43 :22 : ************************************************************2022 -01 -02 00 :43 :22 : ddns ready to update data. 2022 -01 -02 00 :43 :22 : get local IP: 2409 :8 A1E:8 FCA:BB20:F87C:DD68:7 B9D:D3952022 -01 -02 00 :43 :22 : ip type AAAA2022 -01 -02 00 :43 :23 : get domain info: {'recordId': 23134869 , 'domain': 'itest6', 'view': 'DEFAULT', 'rdtype': 'AAAA', 'ttl': 60 , 'rdata': '2409 :8 A1E:8 FCA:BB20:F87C:3568 :739 D:D395', 'zoneName': 'zywvvd.com', 'status': 'RUNNING'}2022 -01 -02 00 :43 :23 : local IP is same as reomte IP, skip updating.
参考资料
文章链接:
https://www.zywvvd.com/notes/coding/python/baidu-ddns/baidu-ddns/