ddns 3.1.6__py2.py3-none-any.whl → 4.0.0__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/__init__.py +19 -0
- ddns/__main__.py +180 -0
- {dns → ddns/provider}/alidns.py +4 -6
- {dns → ddns/provider}/callback.py +4 -6
- {dns → ddns/provider}/cloudflare.py +4 -6
- {dns → ddns/provider}/dnscom.py +4 -7
- {dns → ddns/provider}/dnspod.py +9 -9
- {dns → ddns/provider}/dnspod_com.py +1 -1
- {dns → ddns/provider}/he.py +4 -6
- {dns → ddns/provider}/huaweidns.py +5 -6
- {util → ddns/util}/cache.py +3 -5
- ddns/util/config.py +317 -0
- {util → ddns/util}/ip.py +3 -5
- ddns-4.0.0.dist-info/METADATA +326 -0
- ddns-4.0.0.dist-info/RECORD +21 -0
- ddns-4.0.0.dist-info/entry_points.txt +2 -0
- ddns-4.0.0.dist-info/top_level.txt +1 -0
- ddns-3.1.6.dist-info/METADATA +0 -288
- ddns-3.1.6.dist-info/RECORD +0 -20
- ddns-3.1.6.dist-info/entry_points.txt +0 -2
- ddns-3.1.6.dist-info/top_level.txt +0 -3
- run.py +0 -169
- util/config.py +0 -126
- {dns → ddns/provider}/__init__.py +0 -0
- {util → ddns/util}/__init__.py +0 -0
- {ddns-3.1.6.dist-info → ddns-4.0.0.dist-info}/WHEEL +0 -0
- {ddns-3.1.6.dist-info → ddns-4.0.0.dist-info}/licenses/LICENSE +0 -0
ddns/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- coding:utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
ddns Package
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__description__ = "automatically update DNS records to my IP [域名自动指向本机IP]"
|
|
7
|
+
|
|
8
|
+
# 编译时,版本会被替换
|
|
9
|
+
__version__ = "4.0.0"
|
|
10
|
+
|
|
11
|
+
# 时间也会被替换掉
|
|
12
|
+
build_date = "2025-06-20T15:39:20Z"
|
|
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) New Future (MIT License)
|
|
19
|
+
""".format(__version__, build_date)
|
ddns/__main__.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# -*- coding:utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
DDNS
|
|
4
|
+
@author: New Future
|
|
5
|
+
@modified: rufengsuixing
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from os import path, environ, name as os_name
|
|
9
|
+
from io import TextIOWrapper
|
|
10
|
+
from subprocess import check_output
|
|
11
|
+
from tempfile import gettempdir
|
|
12
|
+
from logging import basicConfig, info, warning, error, debug, DEBUG, NOTSET
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
from .__init__ import __version__, __description__, __doc__, build_date
|
|
17
|
+
from .util import ip
|
|
18
|
+
from .util.cache import Cache
|
|
19
|
+
from .util.config import init_config, get_config
|
|
20
|
+
|
|
21
|
+
environ["DDNS_VERSION"] = __version__
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def is_false(value):
|
|
25
|
+
"""
|
|
26
|
+
判断值是否为 False
|
|
27
|
+
字符串 'false', 或者 False, 或者 'none';
|
|
28
|
+
0 不是 False
|
|
29
|
+
"""
|
|
30
|
+
if isinstance(value, str):
|
|
31
|
+
return value.strip().lower() in ['false', 'none']
|
|
32
|
+
return value is False
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_ip(ip_type, index="default"):
|
|
36
|
+
"""
|
|
37
|
+
get IP address
|
|
38
|
+
"""
|
|
39
|
+
# CN: 捕获异常
|
|
40
|
+
# EN: Catch exceptions
|
|
41
|
+
value = None
|
|
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(
|
|
57
|
+
index[6:], shell=True).strip().decode('utf-8'))
|
|
58
|
+
elif index.startswith('url:'): # 自定义 url
|
|
59
|
+
value = getattr(ip, "public_v" + ip_type)(index[4:])
|
|
60
|
+
elif index.startswith('regex:'): # 正则 regex
|
|
61
|
+
value = getattr(ip, "regex_v" + ip_type)(index[6:])
|
|
62
|
+
else:
|
|
63
|
+
value = getattr(ip, index + "_v" + ip_type)()
|
|
64
|
+
except Exception as e:
|
|
65
|
+
error("Failed to get %s address: %s", ip_type, e)
|
|
66
|
+
return value
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def change_dns_record(dns, proxy_list, **kw):
|
|
70
|
+
for proxy in proxy_list:
|
|
71
|
+
if not proxy or (proxy.upper() in ['DIRECT', 'NONE']):
|
|
72
|
+
dns.Config.PROXY = None
|
|
73
|
+
else:
|
|
74
|
+
dns.Config.PROXY = proxy
|
|
75
|
+
record_type, domain = kw['record_type'], kw['domain']
|
|
76
|
+
info("%s(%s) ==> %s [via %s]", domain, record_type, kw['ip'], proxy)
|
|
77
|
+
try:
|
|
78
|
+
return dns.update_record(domain, kw['ip'], record_type=record_type)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
error("Failed to update %s record for %s: %s", record_type, domain, e)
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def update_ip(ip_type, cache, dns, proxy_list):
|
|
85
|
+
"""
|
|
86
|
+
更新IP
|
|
87
|
+
"""
|
|
88
|
+
ipname = 'ipv' + ip_type
|
|
89
|
+
domains = get_config(ipname)
|
|
90
|
+
if not domains:
|
|
91
|
+
return None
|
|
92
|
+
if not isinstance(domains, list):
|
|
93
|
+
domains = domains.strip('; ').replace(',', ';').replace(' ', ';').split(';')
|
|
94
|
+
|
|
95
|
+
index_rule = get_config('index' + ip_type, "default")
|
|
96
|
+
address = get_ip(ip_type, index_rule)
|
|
97
|
+
if not address:
|
|
98
|
+
error('Fail to get %s address!', ipname)
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
if cache and (address == cache.get(ipname)):
|
|
102
|
+
info('%s address not changed, using cache.', ipname)
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
record_type = 'A' if ip_type == '4' else 'AAAA'
|
|
106
|
+
update_success = False
|
|
107
|
+
for domain in domains:
|
|
108
|
+
domain = domain.lower()
|
|
109
|
+
if change_dns_record(dns, proxy_list, domain=domain, ip=address, record_type=record_type):
|
|
110
|
+
update_success = True
|
|
111
|
+
|
|
112
|
+
if isinstance(cache, dict):
|
|
113
|
+
cache[ipname] = update_success and address
|
|
114
|
+
|
|
115
|
+
return update_success
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def main():
|
|
119
|
+
"""
|
|
120
|
+
更新
|
|
121
|
+
"""
|
|
122
|
+
encode = sys.stdout.encoding
|
|
123
|
+
if encode is not None and encode.lower() != 'utf-8' and hasattr(sys.stdout, 'buffer'):
|
|
124
|
+
# 兼容windows 和部分ASCII编码的老旧系统
|
|
125
|
+
sys.stdout = TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
126
|
+
sys.stderr = TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
|
127
|
+
init_config(__description__, __doc__, __version__, build_date)
|
|
128
|
+
|
|
129
|
+
log_level = get_config('log.level')
|
|
130
|
+
log_format = get_config('log.format', '%(asctime)s %(levelname)s [%(module)s]: %(message)s')
|
|
131
|
+
# Override log format in debug mode to include filename and line number for detailed debugging
|
|
132
|
+
if (log_level == DEBUG or log_level == NOTSET) and not log_format:
|
|
133
|
+
log_format = '%(asctime)s %(levelname)s [%(filename)s:%(lineno)d]: %(message)s'
|
|
134
|
+
basicConfig(
|
|
135
|
+
level=log_level,
|
|
136
|
+
format=log_format,
|
|
137
|
+
datefmt=get_config('log.datefmt', '%Y-%m-%dT%H:%M:%S'),
|
|
138
|
+
filename=get_config('log.file'),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
info("DDNS[ %s ] run: %s %s", __version__, os_name, sys.platform)
|
|
142
|
+
|
|
143
|
+
# Dynamically import the dns module as configuration
|
|
144
|
+
dns_provider = str(get_config('dns', 'dnspod').lower())
|
|
145
|
+
# dns_module = __import__(
|
|
146
|
+
# '.dns', fromlist=[dns_provider], package=__package__)
|
|
147
|
+
dns = getattr(__import__('ddns.provider', fromlist=[dns_provider]), dns_provider)
|
|
148
|
+
# dns = getattr(dns_module, dns_provider)
|
|
149
|
+
dns.Config.ID = get_config('id')
|
|
150
|
+
dns.Config.TOKEN = get_config('token')
|
|
151
|
+
dns.Config.TTL = get_config('ttl')
|
|
152
|
+
|
|
153
|
+
if get_config("config"):
|
|
154
|
+
info('loaded Config from: %s', path.abspath(get_config('config')))
|
|
155
|
+
|
|
156
|
+
proxy = get_config('proxy') or 'DIRECT'
|
|
157
|
+
proxy_list = proxy if isinstance(
|
|
158
|
+
proxy, list) else proxy.strip(';').replace(',', ';').split(';')
|
|
159
|
+
|
|
160
|
+
cache_config = get_config('cache', True)
|
|
161
|
+
if cache_config is False:
|
|
162
|
+
cache = cache_config
|
|
163
|
+
elif cache_config is True:
|
|
164
|
+
cache = Cache(path.join(gettempdir(), 'ddns.cache'))
|
|
165
|
+
else:
|
|
166
|
+
cache = Cache(cache_config)
|
|
167
|
+
|
|
168
|
+
if cache is False:
|
|
169
|
+
info('Cache is disabled!')
|
|
170
|
+
elif not get_config('config_modified_time') or get_config('config_modified_time') >= cache.time:
|
|
171
|
+
warning('Cache file is outdated.')
|
|
172
|
+
cache.clear()
|
|
173
|
+
else:
|
|
174
|
+
debug('Cache is empty.')
|
|
175
|
+
update_ip('4', cache, dns, proxy_list)
|
|
176
|
+
update_ip('6', cache, dns, proxy_list)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
if __name__ == '__main__':
|
|
180
|
+
main()
|
{dns → ddns/provider}/alidns.py
RENAMED
|
@@ -14,14 +14,12 @@ from json import loads as jsondecode
|
|
|
14
14
|
from logging import debug, info, warning
|
|
15
15
|
from datetime import datetime
|
|
16
16
|
|
|
17
|
-
try:
|
|
18
|
-
# python 2
|
|
19
|
-
from httplib import HTTPSConnection
|
|
20
|
-
from urllib import urlencode, quote_plus, quote
|
|
21
|
-
except ImportError:
|
|
22
|
-
# python 3
|
|
17
|
+
try: # python 3
|
|
23
18
|
from http.client import HTTPSConnection
|
|
24
19
|
from urllib.parse import urlencode, quote_plus, quote
|
|
20
|
+
except ImportError: # python 2
|
|
21
|
+
from httplib import HTTPSConnection
|
|
22
|
+
from urllib import urlencode, quote_plus, quote
|
|
25
23
|
|
|
26
24
|
__author__ = 'New Future'
|
|
27
25
|
# __all__ = ["request", "ID", "TOKEN", "PROXY"]
|
|
@@ -10,15 +10,13 @@ from json import loads as jsondecode
|
|
|
10
10
|
from logging import debug, info, warning
|
|
11
11
|
from time import time
|
|
12
12
|
|
|
13
|
-
try:
|
|
14
|
-
|
|
13
|
+
try: # python 3
|
|
14
|
+
from http.client import HTTPSConnection, HTTPConnection
|
|
15
|
+
from urllib.parse import urlencode, urlparse, parse_qsl
|
|
16
|
+
except ImportError: # python 2
|
|
15
17
|
from httplib import HTTPSConnection, HTTPConnection
|
|
16
18
|
from urlparse import urlparse, parse_qsl
|
|
17
19
|
from urllib import urlencode
|
|
18
|
-
except ImportError:
|
|
19
|
-
# python 3
|
|
20
|
-
from http.client import HTTPSConnection, HTTPConnection
|
|
21
|
-
from urllib.parse import urlencode, urlparse, parse_qsl
|
|
22
20
|
|
|
23
21
|
__author__ = '老周部落'
|
|
24
22
|
|
|
@@ -9,14 +9,12 @@ https://api.cloudflare.com/#dns-records-for-a-zone-properties
|
|
|
9
9
|
from json import loads as jsondecode, dumps as jsonencode
|
|
10
10
|
from logging import debug, info, warning
|
|
11
11
|
|
|
12
|
-
try:
|
|
13
|
-
# python 2
|
|
14
|
-
from httplib import HTTPSConnection
|
|
15
|
-
from urllib import urlencode
|
|
16
|
-
except ImportError:
|
|
17
|
-
# python 3
|
|
12
|
+
try: # python 3
|
|
18
13
|
from http.client import HTTPSConnection
|
|
19
14
|
from urllib.parse import urlencode
|
|
15
|
+
except ImportError: # python 2
|
|
16
|
+
from httplib import HTTPSConnection
|
|
17
|
+
from urllib import urlencode
|
|
20
18
|
|
|
21
19
|
__author__ = 'TongYifan'
|
|
22
20
|
|
{dns → ddns/provider}/dnscom.py
RENAMED
|
@@ -13,15 +13,12 @@ from logging import debug, info, warning
|
|
|
13
13
|
from time import mktime
|
|
14
14
|
from datetime import datetime
|
|
15
15
|
|
|
16
|
-
try:
|
|
17
|
-
# python 2
|
|
18
|
-
from httplib import HTTPSConnection
|
|
19
|
-
from urllib import urlencode
|
|
20
|
-
except ImportError:
|
|
21
|
-
# python 3
|
|
16
|
+
try: # python 3
|
|
22
17
|
from http.client import HTTPSConnection
|
|
23
18
|
from urllib.parse import urlencode
|
|
24
|
-
|
|
19
|
+
except ImportError: # python 2
|
|
20
|
+
from httplib import HTTPSConnection
|
|
21
|
+
from urllib import urlencode
|
|
25
22
|
|
|
26
23
|
__author__ = 'Bigjin'
|
|
27
24
|
# __all__ = ["request", "ID", "TOKEN", "PROXY"]
|
{dns → ddns/provider}/dnspod.py
RENAMED
|
@@ -9,14 +9,13 @@ http://www.dnspod.cn/docs/domains.html
|
|
|
9
9
|
from json import loads as jsondecode
|
|
10
10
|
from logging import debug, info, warning
|
|
11
11
|
from os import environ
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from httplib import HTTPSConnection
|
|
15
|
-
from urllib import urlencode
|
|
16
|
-
except ImportError:
|
|
17
|
-
# python 3
|
|
12
|
+
|
|
13
|
+
try: # python 3
|
|
18
14
|
from http.client import HTTPSConnection
|
|
19
15
|
from urllib.parse import urlencode
|
|
16
|
+
except ImportError: # python 2
|
|
17
|
+
from httplib import HTTPSConnection
|
|
18
|
+
from urllib import urlencode
|
|
20
19
|
|
|
21
20
|
__author__ = 'New Future'
|
|
22
21
|
|
|
@@ -107,10 +106,11 @@ def get_domain_id(domain):
|
|
|
107
106
|
return get_domain_id.domain_list[domain]
|
|
108
107
|
else:
|
|
109
108
|
try:
|
|
110
|
-
|
|
111
|
-
except Exception:
|
|
109
|
+
d_info = request('Domain.Info', domain=domain)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
info("get_domain_id(%s) error: %s", domain, e)
|
|
112
112
|
return
|
|
113
|
-
did =
|
|
113
|
+
did = d_info.get("domain", {}).get("id")
|
|
114
114
|
if did:
|
|
115
115
|
get_domain_id.domain_list[domain] = did
|
|
116
116
|
return did
|
{dns → ddns/provider}/he.py
RENAMED
|
@@ -8,14 +8,12 @@ https://dns.he.net/docs.html
|
|
|
8
8
|
|
|
9
9
|
from logging import debug, info, warning
|
|
10
10
|
|
|
11
|
-
try:
|
|
12
|
-
# python 2
|
|
13
|
-
from httplib import HTTPSConnection
|
|
14
|
-
from urllib import urlencode
|
|
15
|
-
except ImportError:
|
|
16
|
-
# python 3
|
|
11
|
+
try: # python 3
|
|
17
12
|
from http.client import HTTPSConnection
|
|
18
13
|
from urllib.parse import urlencode
|
|
14
|
+
except ImportError: # python 2
|
|
15
|
+
from httplib import HTTPSConnection
|
|
16
|
+
from urllib import urlencode
|
|
19
17
|
|
|
20
18
|
__author__ = 'NN708'
|
|
21
19
|
|
|
@@ -14,14 +14,13 @@ from json import loads as jsondecode, dumps as jsonencode
|
|
|
14
14
|
from logging import debug, info, warning
|
|
15
15
|
from datetime import datetime
|
|
16
16
|
|
|
17
|
-
try:
|
|
18
|
-
# python 2
|
|
19
|
-
from httplib import HTTPSConnection
|
|
20
|
-
from urllib import urlencode
|
|
21
|
-
except ImportError:
|
|
22
|
-
# python 3
|
|
17
|
+
try: # python 3
|
|
23
18
|
from http.client import HTTPSConnection
|
|
24
19
|
from urllib.parse import urlencode
|
|
20
|
+
except ImportError: # python 2
|
|
21
|
+
from httplib import HTTPSConnection
|
|
22
|
+
from urllib import urlencode
|
|
23
|
+
|
|
25
24
|
|
|
26
25
|
__author__ = 'New Future'
|
|
27
26
|
BasicDateFormat = "%Y%m%dT%H%M%SZ"
|
{util → ddns/util}/cache.py
RENAMED
|
@@ -11,12 +11,10 @@ from time import time
|
|
|
11
11
|
|
|
12
12
|
from logging import info, debug, warning
|
|
13
13
|
|
|
14
|
-
try:
|
|
15
|
-
# Python 2
|
|
16
|
-
from collections import MutableMapping
|
|
17
|
-
except ImportError:
|
|
18
|
-
# python3
|
|
14
|
+
try: # python 3
|
|
19
15
|
from collections.abc import MutableMapping
|
|
16
|
+
except ImportError: # python 2
|
|
17
|
+
from collections import MutableMapping
|
|
20
18
|
|
|
21
19
|
|
|
22
20
|
class Cache(MutableMapping):
|