ddns 4.1.0b1__py2.py3-none-any.whl → 4.1.0b3__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ddns might be problematic. Click here for more details.
- ddns/__builtins__.pyi +1 -0
- ddns/__init__.py +2 -11
- ddns/__main__.py +91 -138
- ddns/{util/cache.py → cache.py} +42 -11
- ddns/{util/ip.py → ip.py} +11 -11
- ddns/provider/__init__.py +24 -4
- ddns/provider/_base.py +65 -198
- ddns/provider/_signature.py +113 -0
- ddns/provider/alidns.py +35 -17
- ddns/provider/aliesa.py +130 -0
- ddns/provider/callback.py +10 -10
- ddns/provider/cloudflare.py +10 -10
- ddns/provider/debug.py +0 -1
- ddns/provider/dnscom.py +7 -6
- ddns/provider/dnspod.py +4 -7
- ddns/provider/dnspod_com.py +1 -1
- ddns/provider/edgeone.py +83 -0
- ddns/provider/he.py +4 -4
- ddns/provider/huaweidns.py +12 -11
- ddns/provider/namesilo.py +159 -0
- ddns/provider/noip.py +101 -0
- ddns/provider/tencentcloud.py +13 -14
- ddns/util/comment.py +88 -0
- ddns/util/fileio.py +113 -0
- ddns/util/http.py +275 -230
- {ddns-4.1.0b1.dist-info → ddns-4.1.0b3.dist-info}/METADATA +95 -119
- ddns-4.1.0b3.dist-info/RECORD +32 -0
- ddns/util/config.py +0 -314
- ddns-4.1.0b1.dist-info/RECORD +0 -26
- {ddns-4.1.0b1.dist-info → ddns-4.1.0b3.dist-info}/WHEEL +0 -0
- {ddns-4.1.0b1.dist-info → ddns-4.1.0b3.dist-info}/entry_points.txt +0 -0
- {ddns-4.1.0b1.dist-info → ddns-4.1.0b3.dist-info}/licenses/LICENSE +0 -0
- {ddns-4.1.0b1.dist-info → ddns-4.1.0b3.dist-info}/top_level.txt +0 -0
ddns/__builtins__.pyi
CHANGED
ddns/__init__.py
CHANGED
|
@@ -6,16 +6,7 @@ ddns Package
|
|
|
6
6
|
__description__ = "automatically update DNS records to my IP [域名自动指向本机IP]"
|
|
7
7
|
|
|
8
8
|
# 编译时,版本会被替换
|
|
9
|
-
__version__ = "4.1.
|
|
9
|
+
__version__ = "4.1.0b3"
|
|
10
10
|
|
|
11
11
|
# 时间也会被替换掉
|
|
12
|
-
build_date = "2025-
|
|
13
|
-
|
|
14
|
-
__doc__ = """
|
|
15
|
-
ddns [v{}@{}]
|
|
16
|
-
(i) homepage or docs [文档主页]: https://ddns.newfuture.cc/
|
|
17
|
-
(?) issues or bugs [问题和反馈]: https://github.com/NewFuture/DDNS/issues
|
|
18
|
-
Copyright (c) NewFuture (MIT License)
|
|
19
|
-
""".format(
|
|
20
|
-
__version__, build_date
|
|
21
|
-
)
|
|
12
|
+
build_date = "2025-08-11T15:00:49Z"
|
ddns/__main__.py
CHANGED
|
@@ -4,189 +4,142 @@ DDNS
|
|
|
4
4
|
@author: NewFuture, rufengsuixing
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from os import path, environ, name as os_name
|
|
8
7
|
from io import TextIOWrapper
|
|
9
8
|
from subprocess import check_output
|
|
10
|
-
from
|
|
11
|
-
from logging import basicConfig, getLogger, info, error, debug, warning, INFO
|
|
12
|
-
|
|
9
|
+
from logging import getLogger
|
|
13
10
|
import sys
|
|
14
11
|
|
|
15
|
-
from .__init__ import __version__, __description__,
|
|
16
|
-
from .
|
|
17
|
-
from .util.cache import Cache
|
|
18
|
-
from .util.config import init_config, get_config
|
|
12
|
+
from .__init__ import __version__, __description__, build_date
|
|
13
|
+
from .config import load_configs, Config # noqa: F401
|
|
19
14
|
from .provider import get_provider_class, SimpleProvider # noqa: F401
|
|
15
|
+
from . import ip
|
|
16
|
+
from .cache import Cache
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def is_false(value):
|
|
25
|
-
"""
|
|
26
|
-
判断值是否为 False
|
|
27
|
-
字符串 'false', 或者 False, 或者 'none';
|
|
28
|
-
0 不是 False
|
|
29
|
-
"""
|
|
30
|
-
if hasattr(value, "strip"): # 字符串
|
|
31
|
-
return value.strip().lower() in ["false", "none"]
|
|
32
|
-
return value is False
|
|
18
|
+
logger = getLogger()
|
|
33
19
|
|
|
34
20
|
|
|
35
|
-
def get_ip(ip_type,
|
|
21
|
+
def get_ip(ip_type, rules):
|
|
36
22
|
"""
|
|
37
23
|
get IP address
|
|
38
24
|
"""
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
try:
|
|
43
|
-
debug("get_ip(%s, %s)", ip_type, index)
|
|
44
|
-
if is_false(index): # disabled
|
|
45
|
-
return False
|
|
46
|
-
elif isinstance(index, list): # 如果获取到的规则是列表,则依次判断列表中每一个规则,直到获取到IP
|
|
47
|
-
for i in index:
|
|
48
|
-
value = get_ip(ip_type, i)
|
|
49
|
-
if value:
|
|
50
|
-
break
|
|
51
|
-
elif str(index).isdigit(): # 数字 local eth
|
|
52
|
-
value = getattr(ip, "local_v" + ip_type)(index)
|
|
53
|
-
elif index.startswith("cmd:"): # cmd
|
|
54
|
-
value = str(check_output(index[4:]).strip().decode("utf-8"))
|
|
55
|
-
elif index.startswith("shell:"): # shell
|
|
56
|
-
value = str(check_output(index[6:], shell=True).strip().decode("utf-8"))
|
|
57
|
-
elif index.startswith("url:"): # 自定义 url
|
|
58
|
-
value = getattr(ip, "public_v" + ip_type)(index[4:])
|
|
59
|
-
elif index.startswith("regex:"): # 正则 regex
|
|
60
|
-
value = getattr(ip, "regex_v" + ip_type)(index[6:])
|
|
61
|
-
else:
|
|
62
|
-
value = getattr(ip, index + "_v" + ip_type)()
|
|
63
|
-
except Exception as e:
|
|
64
|
-
error("Failed to get %s address: %s", ip_type, e)
|
|
65
|
-
return value
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def change_dns_record(dns, proxy_list, **kw):
|
|
69
|
-
# type: (SimpleProvider, list, **(str)) -> bool
|
|
70
|
-
for proxy in proxy_list:
|
|
71
|
-
if not proxy or (proxy.upper() in ["DIRECT", "NONE"]):
|
|
72
|
-
dns.set_proxy(None)
|
|
73
|
-
else:
|
|
74
|
-
dns.set_proxy(proxy)
|
|
75
|
-
record_type, domain = kw["record_type"], kw["domain"]
|
|
25
|
+
if rules is False: # disabled
|
|
26
|
+
return False
|
|
27
|
+
for i in rules:
|
|
76
28
|
try:
|
|
77
|
-
|
|
29
|
+
logger.debug("get_ip:(%s, %s)", ip_type, i)
|
|
30
|
+
if str(i).isdigit(): # 数字 local eth
|
|
31
|
+
return getattr(ip, "local_v" + ip_type)(i)
|
|
32
|
+
elif i.startswith("cmd:"): # cmd
|
|
33
|
+
return str(check_output(i[4:]).strip().decode("utf-8"))
|
|
34
|
+
elif i.startswith("shell:"): # shell
|
|
35
|
+
return str(check_output(i[6:], shell=True).strip().decode("utf-8"))
|
|
36
|
+
elif i.startswith("url:"): # 自定义 url
|
|
37
|
+
return getattr(ip, "public_v" + ip_type)(i[4:])
|
|
38
|
+
elif i.startswith("regex:"): # 正则 regex
|
|
39
|
+
return getattr(ip, "regex_v" + ip_type)(i[6:])
|
|
40
|
+
else:
|
|
41
|
+
return getattr(ip, i + "_v" + ip_type)()
|
|
78
42
|
except Exception as e:
|
|
79
|
-
error("Failed to
|
|
80
|
-
return
|
|
43
|
+
logger.error("Failed to get %s address: %s", ip_type, e)
|
|
44
|
+
return None
|
|
81
45
|
|
|
82
46
|
|
|
83
|
-
def update_ip(
|
|
84
|
-
# type: (
|
|
47
|
+
def update_ip(dns, cache, index_rule, domains, record_type, config):
|
|
48
|
+
# type: (SimpleProvider, Cache | None, list[str]|bool, list[str], str, Config) -> bool | None
|
|
85
49
|
"""
|
|
86
|
-
更新IP
|
|
50
|
+
更新IP并变更DNS记录
|
|
87
51
|
"""
|
|
88
|
-
ipname = "ipv" + ip_type
|
|
89
|
-
domains = get_config(ipname)
|
|
90
52
|
if not domains:
|
|
91
53
|
return None
|
|
92
|
-
if not isinstance(domains, list):
|
|
93
|
-
domains = domains.strip("; ").replace(",", ";").replace(" ", ";").split(";")
|
|
94
54
|
|
|
95
|
-
|
|
55
|
+
ip_type = "4" if record_type == "A" else "6"
|
|
96
56
|
address = get_ip(ip_type, index_rule)
|
|
97
57
|
if not address:
|
|
98
|
-
error("Fail to get %s address!",
|
|
58
|
+
logger.error("Fail to get %s address!", ip_type)
|
|
99
59
|
return False
|
|
100
60
|
|
|
101
|
-
record_type = "A" if ip_type == "4" else "AAAA"
|
|
102
61
|
update_success = False
|
|
103
62
|
|
|
104
|
-
# Check cache and update each domain individually
|
|
105
63
|
for domain in domains:
|
|
106
64
|
domain = domain.lower()
|
|
107
65
|
cache_key = "{}:{}".format(domain, record_type)
|
|
108
66
|
if cache and cache.get(cache_key) == address:
|
|
109
|
-
info("%s[%s] address not changed, using cache: %s", domain, record_type, address)
|
|
110
|
-
update_success = True
|
|
67
|
+
logger.info("%s[%s] address not changed, using cache: %s", domain, record_type, address)
|
|
68
|
+
update_success = True
|
|
111
69
|
else:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
70
|
+
try:
|
|
71
|
+
result = dns.set_record(domain, address, record_type=record_type, ttl=config.ttl, line=config.line)
|
|
72
|
+
if result:
|
|
73
|
+
logger.warning("set %s[IPv%s]: %s successfully.", domain, ip_type, address)
|
|
74
|
+
update_success = True
|
|
75
|
+
if isinstance(cache, dict):
|
|
76
|
+
cache[cache_key] = address
|
|
77
|
+
else:
|
|
78
|
+
logger.error("Failed to update %s record for %s", record_type, domain)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
logger.exception("Failed to update %s record for %s: %s", record_type, domain, e)
|
|
120
81
|
return update_success
|
|
121
82
|
|
|
122
83
|
|
|
123
|
-
def
|
|
84
|
+
def run(config):
|
|
85
|
+
# type: (Config) -> bool
|
|
124
86
|
"""
|
|
125
|
-
|
|
87
|
+
Run the DDNS update process
|
|
126
88
|
"""
|
|
89
|
+
# 设置IP模块的SSL验证配置
|
|
90
|
+
ip.ssl_verify = config.ssl
|
|
91
|
+
|
|
92
|
+
# dns provider class
|
|
93
|
+
provider_class = get_provider_class(config.dns)
|
|
94
|
+
dns = provider_class(
|
|
95
|
+
config.id, config.token, endpoint=config.endpoint, logger=logger, proxy=config.proxy, ssl=config.ssl
|
|
96
|
+
)
|
|
97
|
+
cache = Cache.new(config.cache, config.md5(), logger)
|
|
98
|
+
return (
|
|
99
|
+
update_ip(dns, cache, config.index4, config.ipv4, "A", config) is not False
|
|
100
|
+
and update_ip(dns, cache, config.index6, config.ipv6, "AAAA", config) is not False
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def main():
|
|
127
105
|
encode = sys.stdout.encoding
|
|
128
106
|
if encode is not None and encode.lower() != "utf-8" and hasattr(sys.stdout, "buffer"):
|
|
129
107
|
# 兼容windows 和部分ASCII编码的老旧系统
|
|
130
108
|
sys.stdout = TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
|
|
131
109
|
sys.stderr = TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
|
|
132
|
-
init_config(__description__, __doc__, __version__, build_date)
|
|
133
|
-
|
|
134
|
-
log_level = get_config("log.level", INFO) # type: int # type: ignore
|
|
135
|
-
log_format = get_config("log.format") # type: str | None # type: ignore
|
|
136
|
-
if log_format:
|
|
137
|
-
# A custom log format is already set; no further action is required.
|
|
138
|
-
pass
|
|
139
|
-
elif log_level < INFO:
|
|
140
|
-
# Override log format in debug mode to include filename and line number for detailed debugging
|
|
141
|
-
log_format = "%(asctime)s %(levelname)s [%(name)s.%(funcName)s](%(filename)s:%(lineno)d): %(message)s"
|
|
142
|
-
elif log_level > INFO:
|
|
143
|
-
log_format = "%(asctime)s %(levelname)s: %(message)s"
|
|
144
|
-
else:
|
|
145
|
-
log_format = "%(asctime)s %(levelname)s [%(name)s]: %(message)s"
|
|
146
|
-
basicConfig(
|
|
147
|
-
level=log_level,
|
|
148
|
-
format=log_format,
|
|
149
|
-
datefmt=get_config("log.datefmt", "%Y-%m-%dT%H:%M:%S"), # type: ignore
|
|
150
|
-
filename=get_config("log.file"), # type: ignore
|
|
151
|
-
)
|
|
152
|
-
logger = getLogger()
|
|
153
110
|
logger.name = "ddns"
|
|
154
111
|
|
|
155
|
-
|
|
112
|
+
# 使用多配置加载器,它会自动处理单个和多个配置
|
|
113
|
+
configs = load_configs(__description__, __version__, build_date)
|
|
156
114
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if get_config("config"):
|
|
164
|
-
info("loaded Config from: %s", path.abspath(get_config("config"))) # type: ignore
|
|
165
|
-
|
|
166
|
-
proxy = get_config("proxy") or "DIRECT"
|
|
167
|
-
proxy_list = proxy if isinstance(proxy, list) else proxy.strip(";").replace(",", ";").split(";")
|
|
168
|
-
|
|
169
|
-
cache_config = get_config("cache", True) # type: bool | str # type: ignore
|
|
170
|
-
if cache_config is False:
|
|
171
|
-
cache = None
|
|
172
|
-
elif cache_config is True:
|
|
173
|
-
cache = Cache(path.join(gettempdir(), "ddns.cache"), logger)
|
|
174
|
-
else:
|
|
175
|
-
cache = Cache(cache_config, logger)
|
|
176
|
-
|
|
177
|
-
if cache is None:
|
|
178
|
-
info("Cache is disabled!")
|
|
179
|
-
elif get_config("config_modified_time", float("inf")) >= cache.time: # type: ignore
|
|
180
|
-
info("Cache file is outdated.")
|
|
181
|
-
cache.clear()
|
|
182
|
-
elif len(cache) == 0:
|
|
183
|
-
debug("Cache is empty.")
|
|
115
|
+
if len(configs) == 1:
|
|
116
|
+
# 单个配置,使用原有逻辑(向后兼容)
|
|
117
|
+
config = configs[0]
|
|
118
|
+
success = run(config)
|
|
119
|
+
if not success:
|
|
120
|
+
sys.exit(1)
|
|
184
121
|
else:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
122
|
+
# 多个配置,使用新的批处理逻辑
|
|
123
|
+
overall_success = True
|
|
124
|
+
for i, config in enumerate(configs):
|
|
125
|
+
# 如果log_level有值则设置setLevel
|
|
126
|
+
if hasattr(config, "log_level") and config.log_level:
|
|
127
|
+
logger.setLevel(config.log_level)
|
|
128
|
+
logger.info("Running configuration %d/%d", i + 1, len(configs))
|
|
129
|
+
# 记录当前provider
|
|
130
|
+
logger.info("Using DNS provider: %s", config.dns)
|
|
131
|
+
success = run(config)
|
|
132
|
+
if not success:
|
|
133
|
+
overall_success = False
|
|
134
|
+
logger.error("Configuration %d failed", i + 1)
|
|
135
|
+
else:
|
|
136
|
+
logger.info("Configuration %d completed successfully", i + 1)
|
|
137
|
+
|
|
138
|
+
if not overall_success:
|
|
139
|
+
logger.error("Some configurations failed")
|
|
140
|
+
sys.exit(1)
|
|
141
|
+
else:
|
|
142
|
+
logger.info("All configurations completed successfully")
|
|
190
143
|
|
|
191
144
|
|
|
192
145
|
if __name__ == "__main__":
|
ddns/{util/cache.py → cache.py}
RENAMED
|
@@ -4,10 +4,11 @@ cache module
|
|
|
4
4
|
文件缓存
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from logging import getLogger, Logger # noqa: F401
|
|
7
8
|
from os import path, stat
|
|
8
|
-
from
|
|
9
|
+
from json import load, dump
|
|
10
|
+
from tempfile import gettempdir
|
|
9
11
|
from time import time
|
|
10
|
-
from logging import getLogger, Logger # noqa: F401
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class Cache(dict):
|
|
@@ -40,18 +41,20 @@ class Cache(dict):
|
|
|
40
41
|
file = self.__filename
|
|
41
42
|
|
|
42
43
|
self.__logger.debug("load cache data from %s", file)
|
|
43
|
-
if file
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
if file:
|
|
45
|
+
try:
|
|
46
|
+
with open(file, "r") as data:
|
|
46
47
|
loaded_data = load(data)
|
|
47
48
|
self.clear()
|
|
48
49
|
self.update(loaded_data)
|
|
49
50
|
self.__time = stat(file).st_mtime
|
|
50
51
|
return self
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
except (IOError, OSError):
|
|
53
|
+
self.__logger.info("cache file not exist or cannot be opened")
|
|
54
|
+
except ValueError:
|
|
55
|
+
pass
|
|
56
|
+
except Exception as e:
|
|
57
|
+
self.__logger.warning(e)
|
|
55
58
|
else:
|
|
56
59
|
self.__logger.info("cache file not exist")
|
|
57
60
|
|
|
@@ -63,10 +66,10 @@ class Cache(dict):
|
|
|
63
66
|
def sync(self):
|
|
64
67
|
"""Sync the write buffer with the cache files and clear the buffer."""
|
|
65
68
|
if self.__changed and self.__filename:
|
|
66
|
-
with open(self.__filename, "
|
|
69
|
+
with open(self.__filename, "w") as data:
|
|
67
70
|
# 只保存非私有字段(不以__开头的字段)
|
|
68
71
|
filtered_data = {k: v for k, v in super(Cache, self).items() if not k.startswith("__")}
|
|
69
|
-
dump(filtered_data, data)
|
|
72
|
+
dump(filtered_data, data, separators=(",", ":"))
|
|
70
73
|
self.__logger.debug("save cache data to %s", self.__filename)
|
|
71
74
|
self.__time = time()
|
|
72
75
|
self.__changed = False
|
|
@@ -150,3 +153,31 @@ class Cache(dict):
|
|
|
150
153
|
|
|
151
154
|
def __del__(self):
|
|
152
155
|
self.close()
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def new(config_cache, hash, logger):
|
|
159
|
+
# type: (str|bool, str, Logger) -> Cache|None
|
|
160
|
+
"""
|
|
161
|
+
new cache from a file path.
|
|
162
|
+
:param path: Path to the cache file.
|
|
163
|
+
:param logger: Optional logger for debug messages.
|
|
164
|
+
:return: Cache instance with loaded data.
|
|
165
|
+
"""
|
|
166
|
+
if config_cache is False:
|
|
167
|
+
cache = None
|
|
168
|
+
elif config_cache is True:
|
|
169
|
+
cache_path = path.join(gettempdir(), "ddns.%s.cache" % hash)
|
|
170
|
+
cache = Cache(cache_path, logger)
|
|
171
|
+
else:
|
|
172
|
+
cache = Cache(config_cache, logger)
|
|
173
|
+
|
|
174
|
+
if cache is None:
|
|
175
|
+
logger.debug("Cache is disabled!")
|
|
176
|
+
elif cache.time + 72 * 3600 < time(): # 72小时有效期
|
|
177
|
+
logger.info("Cache file is outdated.")
|
|
178
|
+
cache.clear()
|
|
179
|
+
elif len(cache) == 0:
|
|
180
|
+
logger.debug("Cache is empty.")
|
|
181
|
+
else:
|
|
182
|
+
logger.debug("Cache loaded with %d entries.", len(cache))
|
|
183
|
+
return cache
|
ddns/{util/ip.py → ip.py}
RENAMED
|
@@ -5,10 +5,10 @@ from os import name as os_name, popen
|
|
|
5
5
|
from socket import socket, getaddrinfo, gethostname, AF_INET, AF_INET6, SOCK_DGRAM
|
|
6
6
|
from logging import debug, error
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
from .util.http import request
|
|
9
|
+
|
|
10
|
+
# 模块级别的SSL验证配置,默认使用auto模式
|
|
11
|
+
ssl_verify = "auto"
|
|
12
12
|
|
|
13
13
|
# IPV4正则
|
|
14
14
|
IPV4_REG = r"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"
|
|
@@ -48,13 +48,14 @@ def local_v4(i=0): # 本地ipv4地址
|
|
|
48
48
|
def _open(url, reg):
|
|
49
49
|
try:
|
|
50
50
|
debug("open: %s", url)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.decode("utf8", "ignore")
|
|
55
|
-
)
|
|
51
|
+
# IP 模块重试3次
|
|
52
|
+
response = request("GET", url, verify=ssl_verify, retries=2)
|
|
53
|
+
res = response.body
|
|
56
54
|
debug("response: %s", res)
|
|
57
|
-
|
|
55
|
+
match = compile(reg).search(res)
|
|
56
|
+
if match:
|
|
57
|
+
return match.group()
|
|
58
|
+
error("No match found in response: %s", res)
|
|
58
59
|
except Exception as e:
|
|
59
60
|
error(e)
|
|
60
61
|
|
|
@@ -68,7 +69,6 @@ def public_v6(url="https://api-ipv6.ip.sb/ip", reg=IPV6_REG): # 公网IPV6地
|
|
|
68
69
|
|
|
69
70
|
|
|
70
71
|
def _ip_regex_match(parrent_regex, match_regex):
|
|
71
|
-
|
|
72
72
|
ip_pattern = compile(parrent_regex)
|
|
73
73
|
matcher = compile(match_regex)
|
|
74
74
|
|
ddns/provider/__init__.py
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
# coding=utf-8
|
|
2
|
-
from ._base import SimpleProvider
|
|
2
|
+
from ._base import SimpleProvider
|
|
3
3
|
from .alidns import AlidnsProvider
|
|
4
|
+
from .aliesa import AliesaProvider
|
|
4
5
|
from .callback import CallbackProvider
|
|
5
6
|
from .cloudflare import CloudflareProvider
|
|
7
|
+
from .debug import DebugProvider
|
|
6
8
|
from .dnscom import DnscomProvider
|
|
7
9
|
from .dnspod import DnspodProvider
|
|
8
10
|
from .dnspod_com import DnspodComProvider
|
|
11
|
+
from .edgeone import EdgeOneProvider
|
|
9
12
|
from .he import HeProvider
|
|
10
13
|
from .huaweidns import HuaweiDNSProvider
|
|
14
|
+
from .namesilo import NamesiloProvider
|
|
15
|
+
from .noip import NoipProvider
|
|
11
16
|
from .tencentcloud import TencentCloudProvider
|
|
12
|
-
|
|
17
|
+
|
|
18
|
+
__all__ = ["SimpleProvider", "get_provider_class"]
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
def get_provider_class(provider_name):
|
|
@@ -32,15 +38,22 @@ def get_provider_class(provider_name):
|
|
|
32
38
|
"tencentcloud": TencentCloudProvider,
|
|
33
39
|
"tencent": TencentCloudProvider, # 兼容tencent
|
|
34
40
|
"qcloud": TencentCloudProvider, # 兼容qcloud
|
|
41
|
+
# tencent cloud edgeone
|
|
42
|
+
"edgeone": EdgeOneProvider,
|
|
43
|
+
"teo": EdgeOneProvider, # 兼容teo (EdgeOne产品的API名称)
|
|
44
|
+
"tencentedgeone": EdgeOneProvider, # 兼容tencentedgeone
|
|
35
45
|
# cloudflare
|
|
36
46
|
"cloudflare": CloudflareProvider,
|
|
37
47
|
# aliyun alidns
|
|
38
48
|
"alidns": AlidnsProvider,
|
|
39
49
|
"aliyun": AlidnsProvider, # 兼容aliyun
|
|
50
|
+
# aliyun esa
|
|
51
|
+
"aliesa": AliesaProvider,
|
|
52
|
+
"esa": AliesaProvider, # 兼容esa
|
|
40
53
|
# dns.com
|
|
41
54
|
"dnscom": DnscomProvider,
|
|
42
|
-
"51dns": DnscomProvider, #
|
|
43
|
-
"dns_com": DnscomProvider, #
|
|
55
|
+
"51dns": DnscomProvider, # 兼容51dns
|
|
56
|
+
"dns_com": DnscomProvider, # 兼容dns_com
|
|
44
57
|
# he.net
|
|
45
58
|
"he": HeProvider,
|
|
46
59
|
"he_net": HeProvider, # 兼容he.net
|
|
@@ -48,6 +61,13 @@ def get_provider_class(provider_name):
|
|
|
48
61
|
"huaweidns": HuaweiDNSProvider,
|
|
49
62
|
"huawei": HuaweiDNSProvider, # 兼容huawei
|
|
50
63
|
"huaweicloud": HuaweiDNSProvider,
|
|
64
|
+
# namesilo
|
|
65
|
+
"namesilo": NamesiloProvider,
|
|
66
|
+
"namesilo_com": NamesiloProvider, # 兼容namesilo.com
|
|
67
|
+
# no-ip
|
|
68
|
+
"noip": NoipProvider,
|
|
69
|
+
"no-ip": NoipProvider, # 兼容no-ip
|
|
70
|
+
"noip_com": NoipProvider, # 兼容noip.com
|
|
51
71
|
# callback
|
|
52
72
|
"callback": CallbackProvider,
|
|
53
73
|
"webhook": CallbackProvider, # 兼容
|