First Commit
This commit is contained in:
parent
058045ec95
commit
c7a1fb4141
283
ntp_daemon.py
Normal file
283
ntp_daemon.py
Normal file
@ -0,0 +1,283 @@
|
||||
import socket, struct, threading, time, json, logging
|
||||
|
||||
# flask, requests
|
||||
import flask, requests
|
||||
|
||||
RECORD_UPDATE_SWITCH = True
|
||||
API_LISTEN = ("0.0.0.0", 5000)
|
||||
INTERVAL = 60 * 60
|
||||
DOMAIN = ""
|
||||
A_ID = ""
|
||||
A_KEY = ""
|
||||
|
||||
app = flask.Flask("NTP")
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.disabled = True
|
||||
|
||||
if RECORD_UPDATE_SWITCH:
|
||||
# alibabacloud_alidns20150109==2.0.2
|
||||
from alibabacloud_alidns20150109.client import Client as Alidns20150109Client
|
||||
from alibabacloud_tea_openapi import models as open_api_models
|
||||
from alibabacloud_alidns20150109 import models as alidns_20150109_models
|
||||
from alibabacloud_tea_util import models as util_models
|
||||
|
||||
class Domain:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def create_client(
|
||||
access_key_id: str,
|
||||
access_key_secret: str,
|
||||
) -> Alidns20150109Client:
|
||||
config = open_api_models.Config(
|
||||
access_key_id=access_key_id,
|
||||
access_key_secret=access_key_secret
|
||||
)
|
||||
config.endpoint = f'alidns.cn-hangzhou.aliyuncs.com'
|
||||
return Alidns20150109Client(config)
|
||||
|
||||
@staticmethod
|
||||
def get_records():
|
||||
client = Domain.create_client(A_ID, A_KEY)
|
||||
describe_domain_records_request = alidns_20150109_models.DescribeDomainRecordsRequest(
|
||||
domain_name=DOMAIN
|
||||
)
|
||||
runtime = util_models.RuntimeOptions()
|
||||
try:
|
||||
return True, eval(str(client.describe_domain_records_with_options(describe_domain_records_request, runtime)))["body"]["DomainRecords"]["Record"]
|
||||
except Exception as error:
|
||||
return False, error
|
||||
|
||||
@staticmethod
|
||||
def delete_record(rr) -> None:
|
||||
client = Domain.create_client(A_ID, A_KEY)
|
||||
delete_sub_domain_records_request = alidns_20150109_models.DeleteSubDomainRecordsRequest(
|
||||
domain_name=DOMAIN,
|
||||
rr=rr
|
||||
)
|
||||
runtime = util_models.RuntimeOptions()
|
||||
try:
|
||||
return True, eval(str(client.describe_domain_records_with_options(client.delete_sub_domain_records_with_options(delete_sub_domain_records_request, runtime))))
|
||||
except Exception as error:
|
||||
return False, error
|
||||
|
||||
@staticmethod
|
||||
def add_record(rr, type, value, line) -> None:
|
||||
client = Domain.create_client(A_ID, A_KEY)
|
||||
add_domain_record_request = alidns_20150109_models.AddDomainRecordRequest(
|
||||
domain_name=DOMAIN,
|
||||
rr=rr,
|
||||
type=type,
|
||||
value=value,
|
||||
line=line
|
||||
)
|
||||
runtime = util_models.RuntimeOptions()
|
||||
try:
|
||||
return True, eval(str(client.add_domain_record_with_options(add_domain_record_request, runtime)))
|
||||
except Exception as error:
|
||||
return False, error
|
||||
|
||||
def is_ipv4(ip):
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET, ip)
|
||||
except AttributeError:
|
||||
try:
|
||||
socket.inet_aton(ip)
|
||||
except socket.error:
|
||||
return False
|
||||
return ip.count('.') == 3
|
||||
except socket.error:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_ipv6(ip):
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET6, ip)
|
||||
except socket.error:
|
||||
return False
|
||||
return True
|
||||
|
||||
def ip_type(ip):
|
||||
if is_ipv4(ip) and not is_ipv6(ip):
|
||||
return 4
|
||||
elif is_ipv6(ip) and not is_ipv4(ip):
|
||||
return 6
|
||||
else:
|
||||
return 0
|
||||
|
||||
def ip_area(ip):
|
||||
type = ip_type(ip)
|
||||
if type == 4 or type == 6:
|
||||
info = requests.get(f"https://api.ghink.net/ip/zh_cn/v{type}/{ip}").json()
|
||||
if info["code"] != 20000:
|
||||
return "default"
|
||||
info = info["content"]
|
||||
if type == 4:
|
||||
if info["pro"] == "":
|
||||
return "oversea"
|
||||
elif "教育" in info["addr"] or "学院" in info["addr"] or "大学" in info["addr"]:
|
||||
return "edu"
|
||||
elif "电信" in info["addr"]:
|
||||
return "telecom"
|
||||
elif "移动" in info["addr"] or "移通" in info["addr"]:
|
||||
return "mobile"
|
||||
elif "联通" in info["addr"]:
|
||||
return "unicom"
|
||||
else:
|
||||
return "default"
|
||||
elif type == 6:
|
||||
if info["pro"] == "" and info["city"] == "":
|
||||
return "oversea"
|
||||
elif "教育" in info["addr"] or "学院" in info["addr"] or "大学" in info["addr"]:
|
||||
return "edu"
|
||||
elif "电信" in info["addr"]:
|
||||
return "telecom"
|
||||
elif "移动" in info["addr"] or "移通" in info["addr"]:
|
||||
return "mobile"
|
||||
elif "联通" in info["addr"]:
|
||||
return "unicom"
|
||||
else:
|
||||
return "default"
|
||||
else:
|
||||
return "default"
|
||||
|
||||
def ntp(server):
|
||||
type = ip_type(server)
|
||||
if type == 4:
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
elif type == 6:
|
||||
client = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
else:
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
data = ("\x1b" + 47 * "\0").encode()
|
||||
try:
|
||||
client.sendto(data, (server, 123))
|
||||
except socket.gaierror:
|
||||
return False
|
||||
data, address = client.recvfrom(1024)
|
||||
if data:
|
||||
t = struct.unpack('!12I', data)[10]
|
||||
t -= 2208988800
|
||||
return t
|
||||
else:
|
||||
return False
|
||||
|
||||
def check(server):
|
||||
global active
|
||||
if ntp(server):
|
||||
if server not in active:
|
||||
active.append(server)
|
||||
else:
|
||||
if server in active:
|
||||
del active[active.index(server)]
|
||||
|
||||
def update_status():
|
||||
global active, servers
|
||||
# Read Server Pool
|
||||
servers = []
|
||||
with open("pool.txt", "r") as fb:
|
||||
servers = [s.strip() for s in fb.readlines()]
|
||||
# Duplicate Removal
|
||||
temp = []
|
||||
for s in servers:
|
||||
if s not in temp:
|
||||
temp.append(s)
|
||||
servers = temp
|
||||
with open("pool.txt", "w+") as fb:
|
||||
for s in servers:
|
||||
fb.write(f"{s}\n")
|
||||
# Check
|
||||
for s in active:
|
||||
thread = threading.Thread(target=check, args=(s, ), name=s)
|
||||
thread.start()
|
||||
thread.join(1)
|
||||
with open("pool.txt", "r") as fb:
|
||||
for line in fb.readlines():
|
||||
thread = threading.Thread(target=check, args=(line.strip(), ), name=line.strip())
|
||||
thread.start()
|
||||
thread.join(1)
|
||||
|
||||
def update_status_daemon():
|
||||
while True:
|
||||
update_status()
|
||||
time.sleep(INTERVAL)
|
||||
|
||||
def update_records():
|
||||
ok, records = Domain.get_records()
|
||||
if ok:
|
||||
for r in records:
|
||||
if r["Value"] not in servers:
|
||||
ok, msg = Domain.delete_record(r["Value"])
|
||||
if not ok:
|
||||
print(msg)
|
||||
for s in active:
|
||||
flag = True
|
||||
for r in records:
|
||||
if r["Value"] == s:
|
||||
flag = False
|
||||
if flag:
|
||||
ok, msg = Domain.add_record("@", "A" if ip_type(s) == 4 else "AAAA", s, ip_area(s))
|
||||
if not ok and "The maximum number of 10 records is exceeded" not in str(msg) and "The DNS record already exists." not in str(msg):
|
||||
print(msg)
|
||||
else:
|
||||
print(records)
|
||||
|
||||
def update_records_daemon():
|
||||
while True:
|
||||
update_records()
|
||||
time.sleep(10)
|
||||
|
||||
@app.route("/update")
|
||||
def update_api():
|
||||
update_thread = threading.Thread(target=update_status, name="Update From API For Status")
|
||||
update_thread.daemon = True
|
||||
update_thread.start()
|
||||
if RECORD_UPDATE_SWITCH:
|
||||
update_thread = threading.Thread(target=update_records, name="Update From API For Records")
|
||||
update_thread.daemon = True
|
||||
update_thread.start()
|
||||
return json.dumps(
|
||||
{
|
||||
"message": "Success",
|
||||
"content": None
|
||||
}
|
||||
), 200, {"content-type": "application/json"}
|
||||
|
||||
@app.route("/list")
|
||||
def list_api():
|
||||
return json.dumps(
|
||||
{
|
||||
"message": "Success",
|
||||
"content": active
|
||||
}
|
||||
), 200, {"content-type": "application/json"}
|
||||
|
||||
if __name__ == '__main__':
|
||||
active = []
|
||||
servers = []
|
||||
|
||||
update_status_daemon_thread = threading.Thread(target=update_status_daemon, name="Update Daemon For Status")
|
||||
update_status_daemon_thread.daemon = True
|
||||
update_status_daemon_thread.start()
|
||||
if RECORD_UPDATE_SWITCH:
|
||||
update_status_daemon_thread = threading.Thread(target=update_records_daemon, name="Update Daemon For Records")
|
||||
update_status_daemon_thread.daemon = True
|
||||
update_status_daemon_thread.start()
|
||||
|
||||
api_daemon = threading.Thread(target=app.run, args=API_LISTEN, name="API Daemon")
|
||||
api_daemon.daemon = True
|
||||
api_daemon.start()
|
||||
|
||||
while True:
|
||||
if input() == "exit":
|
||||
break
|
||||
print(f"Report {time.ctime(time.time())}:")
|
||||
print(f"{len(active)} Servers Active, They are:")
|
||||
for i in range(len(active)):
|
||||
if not (i+1) % 5:
|
||||
print(active[i])
|
||||
else:
|
||||
print(active[i], end=" ")
|
||||
print("", end="" if not len(active) % 5 or not len(active) else "\n")
|
123
pool.txt
Normal file
123
pool.txt
Normal file
@ -0,0 +1,123 @@
|
||||
103.11.143.248
|
||||
120.25.115.20
|
||||
116.13.10.10
|
||||
203.107.6.88
|
||||
202.112.29.82
|
||||
120.25.108.11
|
||||
182.92.12.11
|
||||
85.199.214.100
|
||||
101.6.6.172
|
||||
216.218.254.202
|
||||
66.228.42.59
|
||||
211.233.40.78
|
||||
158.69.48.97
|
||||
203.114.74.17
|
||||
2402:f000:1:416:101:6:6:172
|
||||
2001:250:380A:5::10
|
||||
2001:da8:9000::81
|
||||
2001:da8:9000::130
|
||||
185.209.85.222
|
||||
94.130.49.186
|
||||
84.16.67.12
|
||||
78.46.102.180
|
||||
193.182.111.143
|
||||
202.118.1.81
|
||||
108.59.2.24
|
||||
94.237.64.20
|
||||
219.216.128.25
|
||||
119.28.183.184
|
||||
162.159.200.123
|
||||
111.230.189.174
|
||||
178.215.228.24
|
||||
119.28.206.193
|
||||
193.182.111.12
|
||||
193.182.111.142
|
||||
45.77.144.44
|
||||
167.172.70.21
|
||||
192.33.214.47
|
||||
171.66.97.126
|
||||
213.206.184.75
|
||||
104.194.8.227
|
||||
69.197.128.202
|
||||
178.63.9.212
|
||||
135.125.169.44
|
||||
61.239.100.196
|
||||
45.125.1.20
|
||||
142.147.88.111
|
||||
149.202.91.39
|
||||
147.182.158.78
|
||||
185.216.231.84
|
||||
161.53.78.71
|
||||
152.115.59.242
|
||||
192.48.105.15
|
||||
95.215.175.2
|
||||
103.147.22.149
|
||||
168.61.215.74
|
||||
129.250.35.251
|
||||
128.4.24.98
|
||||
202.118.1.130
|
||||
129.250.35.250
|
||||
95.216.192.15
|
||||
133.243.238.243
|
||||
103.104.28.105
|
||||
45.132.84.104
|
||||
103.13.114.65
|
||||
203.99.62.214
|
||||
161.200.192.4
|
||||
58.176.194.96
|
||||
162.159.200.1
|
||||
202.12.97.45
|
||||
110.170.126.102
|
||||
121.174.142.81
|
||||
17.253.116.253
|
||||
202.28.93.5
|
||||
194.0.5.123
|
||||
80.241.0.72
|
||||
192.46.210.39
|
||||
139.199.214.202
|
||||
203.147.59.17
|
||||
23.106.249.200
|
||||
202.28.116.236
|
||||
13.209.84.50
|
||||
203.131.222.11
|
||||
212.138.72.43
|
||||
17.253.84.253
|
||||
212.138.72.41
|
||||
95.216.144.226
|
||||
64.227.167.110
|
||||
202.21.176.62
|
||||
202.65.114.202
|
||||
103.38.215.205
|
||||
212.26.18.43
|
||||
203.113.174.44
|
||||
36.91.114.86
|
||||
223.113.120.195
|
||||
223.113.97.98
|
||||
223.65.211.46
|
||||
36.154.179.82
|
||||
223.113.103.191
|
||||
58.220.133.132
|
||||
114.67.237.130
|
||||
114.67.103.73
|
||||
140.143.99.185
|
||||
111.230.50.201
|
||||
106.75.185.63
|
||||
119.29.26.206
|
||||
120.197.116.202
|
||||
202.112.31.197
|
||||
149.129.123.30
|
||||
106.186.122.232
|
||||
106.187.100.179
|
||||
133.100.11.8
|
||||
106.247.248.106
|
||||
202.73.57.107
|
||||
128.199.134.40
|
||||
218.186.3.36
|
||||
188.166.245.58
|
||||
208.53.158.34
|
||||
131.188.3.220
|
||||
131.188.3.223
|
||||
166.111.8.28
|
||||
166.111.8.29
|
||||
2402:f000:1:801::8:28
|
||||
2402:f000:1:801::8:29
|
3
requirement.txt
Normal file
3
requirement.txt
Normal file
@ -0,0 +1,3 @@
|
||||
flask
|
||||
alibabacloud_alidns20150109==2.0.2
|
||||
requests
|
Reference in New Issue
Block a user