阿里云DDNS Python脚本

前言

不用了不用这个了,用ddns-go了现在
在有公网IP的服务器上部署了服务器之后,IP地址会经常变化,这会影响DNS服务的解析。申请了域名之后阿里云服务提供了DNS服务,并可以利用相关API在多种语言下实现DDNS功能。

设备:Raspberrypi 4B
OS:Debian GNU/Linux 11 (bullseye)

Python库安装

sudo pip install aliyun-python-sdk-alidns

Python脚本

主要参考(chaoxi)这篇博文https://blog.csdn.net/qq_37744229/article/details/125388565
在其基础上把print输出到log文件中,因为需要该脚本在系统启动时运行,输出到log文件方便查看状态。
因为脚本文件第一行是Sha-Bang,这一行的换行符必须为Unix换行符。
根据自己的需要修改是否需要解析ipv4以及ipv6地址,阿里云accessKeyId以及accessSecret在阿里云网站控制台>主账号>AccessKey管理中。

ddns.py:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#! /usr/bin/python3
import sys
from ast import For
from operator import truediv
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.DescribeDomainRecordsRequest import DescribeDomainRecordsRequest
import requests
from urllib.request import urlopen
import json
# import subprocess
from datetime import datetime
from threading import Timer
# import socket

ipv4_flag = 0 # 是否开启ipv4 ddns解析,1为开启,0为关闭
ipv6_flag = 1 # 是否开启ipv6 ddns解析,1为开启,0为关闭
accessKeyId = "xxxxxxxxxx" # 将accessKeyId改成自己的accessKeyId
accessSecret = "xxxxxxxxxx" # 将accessSecret改成自己的accessSecret
domain = "xxxxx.xxx" # 你的主域名
name_ipv4 = "xxx" # 要进行ipv4 ddns解析的子域名
name_ipv6 = "xxx" # 要进行ipv6 ddns解析的子域名

client = AcsClient(accessKeyId, accessSecret, 'cn-hangzhou')

def update(RecordId, RR, Type, Value): # 修改域名解析记录
from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
request = UpdateDomainRecordRequest()
request.set_accept_format('json')
request.set_RecordId(RecordId)
request.set_RR(RR)
request.set_Type(Type)
request.set_Value(Value)
response = client.do_action_with_exception(request)


def add(DomainName, RR, Type, Value): # 添加新的域名解析记录
from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest
request = AddDomainRecordRequest()
request.set_accept_format('json')
request.set_DomainName(DomainName)
request.set_RR(RR)
request.set_Type(Type)
request.set_Value(Value)
response = client.do_action_with_exception(request)

def ping(): #ping百度查看网络状态,断网重新执行方法
try:
html = requests.get("http://www.baidu.com",timeout=2)
except:
return 0
return 1
# return1 = subprocess.call('ping www.baidu.com', shell = False)
# if return1:
# return 0
# else:
# return 1

def setDnsv4():
if ipv4_flag == 1 & ping()==1:
try:
request = DescribeSubDomainRecordsRequest()
request.set_accept_format('json')
request.set_DomainName(domain)
request.set_SubDomain(name_ipv4 + '.' + domain)
request.set_Type("A")
response = client.do_action_with_exception(request) # 获取域名解析记录列表
domain_list = json.loads(response) # 将返回的JSON数据转化为Python能识别的
# 加上timeout参数,可判断阿里云是否阻止访问
ip = urlopen(url='https://api-ipv4.ip.sb/ip',timeout=10.0).read() # 使用IP.SB的接口获取ipv4地址
ipv4 = str(ip, encoding='utf-8')
print("获取到IPv4地址:%s" % ipv4, end="")


if domain_list['TotalCount'] == 0:
add(domain, name_ipv4, "A", ipv4)
print("新建域名解析成功")
elif domain_list['TotalCount'] == 1:
if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv4.strip():
update(domain_list['DomainRecords']['Record'][0]['RecordId'], name_ipv4, "A", ipv4)
print("修改域名解析成功")
else: # https://blog.zeruns.tech
print("IPv4地址没变")
elif domain_list['TotalCount'] > 1:
from aliyunsdkalidns.request.v20150109.DeleteSubDomainRecordsRequest import DeleteSubDomainRecordsRequest
request = DeleteSubDomainRecordsRequest()
request.set_accept_format('json')
request.set_DomainName(domain)
request.set_RR(name_ipv4)
request.set_Type("A")
response = client.do_action_with_exception(request)
add(domain, name_ipv4, "A", ipv4)
print("修改域名解析成功")
except:
print("联网失败")

else:
print("联网失败")

def setDnsv6():
if ipv6_flag == 1 & ping()==1:
request = DescribeSubDomainRecordsRequest()
request.set_accept_format('json')
request.set_DomainName(domain)
request.set_SubDomain(name_ipv6 + '.' + domain)
request.set_Type("AAAA")
response = client.do_action_with_exception(request) # 获取域名解析记录列表
domain_list = json.loads(response) # 将返回的JSON数据转化为Python能识别的

ip = urlopen('https://api-ipv6.ip.sb/ip').read() # 使用IP.SB的接口获取ipv6地址
ipv6 = str(ip, encoding='utf-8')
print("获取到IPv6地址:%s" % ipv6, end="")

if domain_list['TotalCount'] == 0:
add(domain, name_ipv6, "AAAA", ipv6)
print("新建域名解析成功")
elif domain_list['TotalCount'] == 1:
if domain_list['DomainRecords']['Record'][0]['Value'].strip() != ipv6.strip():
update(domain_list['DomainRecords']['Record'][0]['RecordId'], name_ipv6, "AAAA", ipv6)
print("修改域名解析成功")
else:
print("IPv6地址没变")
elif domain_list['TotalCount'] > 1:
from aliyunsdkalidns.request.v20150109.DeleteSubDomainRecordsRequest import DeleteSubDomainRecordsRequest
request = DeleteSubDomainRecordsRequest()
request.set_accept_format('json')
request.set_DomainName(domain)
request.set_RR(name_ipv6) # https://blog.zeruns.tech
request.set_Type("AAAA")
response = client.do_action_with_exception(request)
add(domain, name_ipv6, "AAAA", ipv6)
print("修改域名解析成功")

# 打印时间函数
def timeSet(inc):
savedStdout = sys.stdout #保存标准输出流
with open('/home/pi/ddns_log', 'ta') as file:
sys.stdout = file #标准输出重定向至文件
print(datetime.now().strftime("[%Y-%m-%d %H:%M:%S]"), end="")
# setDnsv4()
setDnsv6()
sys.stdout = savedStdout #恢复标准输出流
t = Timer(inc, timeSet, (inc,))
t.start()
# 60s
timeSet(60)

chmod +x ddns.py将脚本修改为可执行文件。
可以./ddns.py看一眼是否能够运行,log信息输出在ddns_log中。

1
2
3
4
5
6
7
8
[2022-11-29 16:26:24]获取到IPv6地址:240e:399:f91:xxxx:dea6:32ff:fe2c:8092
IPv6地址没变
[2022-11-29 16:27:27]获取到IPv6地址:240e:399:f91:xxxx:dea6:32ff:fe2c:8092
IPv6地址没变
[2022-11-29 16:28:28]获取到IPv6地址:240e:399:f91:xxxx:dea6:32ff:fe2c:8092
IPv6地址没变
[2022-11-29 16:29:29]获取到IPv6地址:240e:399:f91:xxxx:dea6:32ff:fe2c:8092
IPv6地址没变

可以用cat指令看ddns_log内内容:
cat ddns_log
用echo清空log文件
echo "" > ddns_log

Linux开机运行脚本

修改/etc/下rc.local文件:
sudo vim /etc/rc.local
exit 0前加上/home/pi/ddns.py &
最后给rc.local可执行权限sudo chmod +x /etc/rc.local
重启系统或者执行systemctl restart rc-local即可。