Skip to content
This repository was archived by the owner on Feb 20, 2026. It is now read-only.

Commit 5609f15

Browse files
committed
fix: 修复 .li 和 .ch 域名无法正常检查的问题
1 parent 0efc35f commit 5609f15

File tree

4 files changed

+148
-51
lines changed

4 files changed

+148
-51
lines changed

plugins/async_query/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,27 @@
1212

1313
async def main(domain: str):
1414
try:
15+
if domain.endswith("li") or domain.endswith("ch"):
16+
# https://www.nic.li/whois/domaincheck/#collapse-c25cbf2f-a663-11e6-89db-525400a7a801-2
17+
raw_whois = await whois_request(domain, "whois.nic.ch", port=4343)
18+
if raw_whois[1].startswith("1"):
19+
# Domain name can be registered
20+
return {"code": 200, "raw": raw_whois[1]}
21+
elif raw_whois[1].startswith("0"):
22+
# Domain name cannot be registered
23+
return {"code": 200, "raw": raw_whois[1]}
24+
elif raw_whois[1].startswith("-1"):
25+
# Invalid enquiry (i.e. modify enquiry prior to next attempt)
26+
return {"code": 503, "raw": raw_whois[1]}
27+
elif raw_whois[1].startswith("-95"):
28+
# Access restricted (i.e. wait a while and then try again)
29+
return {"code": 503, "raw": raw_whois[1]}
30+
elif raw_whois[1].startswith("-99"):
31+
# Temporary server error (i.e. wait a while and then try again)
32+
return {"code": 503, "raw": raw_whois[1]}
33+
34+
return {"code": 503, "raw": raw_whois[1]}
35+
1536
root_server = whois_server_dict[get_domain_tld(domain)]
1637
raw_whois = await whois_request(domain, root_server)
1738
if raw_whois[0] == "Socket error":

plugins/sync_query/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,27 @@
1212

1313
def main(domain: str):
1414
try:
15+
if domain.endswith("li") or domain.endswith("ch"):
16+
# https://www.nic.li/whois/domaincheck/#collapse-c25cbf2f-a663-11e6-89db-525400a7a801-2
17+
raw_whois = whois_request(domain, "whois.nic.ch", port=4343)
18+
if raw_whois[1].startswith("1"):
19+
# Domain name can be registered
20+
return {"code": 200, "raw": raw_whois[1]}
21+
elif raw_whois[1].startswith("0"):
22+
# Domain name cannot be registered
23+
return {"code": 200, "raw": raw_whois[1]}
24+
elif raw_whois[1].startswith("-1"):
25+
# Invalid enquiry (i.e. modify enquiry prior to next attempt)
26+
return {"code": 503, "raw": raw_whois[1]}
27+
elif raw_whois[1].startswith("-95"):
28+
# Access restricted (i.e. wait a while and then try again)
29+
return {"code": 503, "raw": raw_whois[1]}
30+
elif raw_whois[1].startswith("-99"):
31+
# Temporary server error (i.e. wait a while and then try again)
32+
return {"code": 503, "raw": raw_whois[1]}
33+
34+
return {"code": 503, "raw": raw_whois[1]}
35+
1536
root_server = whois_server_dict[get_domain_tld(domain)]
1637
raw_whois = whois_request(domain, root_server)
1738
if raw_whois[0] == "Socket error":

src/main.py

Lines changed: 67 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -153,60 +153,77 @@ async def main_async(
153153
await f.write(result_domain + "\n")
154154
continue
155155

156-
# 为了保险,再检查下时间是否是过期的。
157-
# 检查“是否为赎回期”可能有缺漏,但是可以明确的是赎回期的特征:有域名过期时间但是时间过期了
158-
159-
# 查询时间
160-
match parsed_whois_data["registry_expiry_date"]:
161-
case Err(datetime_paser_error):
162-
# 时间解析失败
163-
if datetime_paser_error["msg"] == "Error Parsing Date":
164-
info(
165-
f"{INFO_ERROR_PARSING_DATE} err:{datetime_paser_error['err']} raw:{datetime_paser_error['raw']}".format(
166-
domain=result_domain
156+
STRICT_MODE: bool = True
157+
158+
def is_pass_strict_mode(domain: str) -> bool:
159+
"""有些域名不提供域名信息,所以无法进行严格检查。检查这个域名是否允许跳过检查。
160+
161+
Args:
162+
domain (str): 干净的域名如 a.li
163+
164+
Returns:
165+
bool: 可跳过返回 True,不可跳过返回 False
166+
"""
167+
# 有些域名不提供域名信息,所以无法进行严格检查
168+
if domain.endswith(".li") or domain.endswith(".ch"):
169+
return True
170+
return False
171+
172+
if STRICT_MODE and not is_pass_strict_mode(domain=result_domain):
173+
# 严格检查
174+
# 为了保险,再检查下时间是否是过期的。
175+
# 检查“是否为赎回期”可能有缺漏,但是可以明确的是赎回期的特征:有域名过期时间但是时间过期了
176+
# 查询时间
177+
match parsed_whois_data["registry_expiry_date"]:
178+
case Err(datetime_paser_error):
179+
# 时间解析失败
180+
if datetime_paser_error["msg"] == "Error Parsing Date":
181+
info(
182+
f"{INFO_ERROR_PARSING_DATE} err:{datetime_paser_error['err']} raw:{datetime_paser_error['raw']}".format(
183+
domain=result_domain
184+
)
167185
)
168-
)
169-
elif datetime_paser_error["msg"] == "Date not found":
170-
info(
171-
f"{INFO_DATE_NOT_FOUND} raw:{datetime_paser_error['raw']}".format(
172-
domain=result_domain
186+
elif datetime_paser_error["msg"] == "Date not found":
187+
info(
188+
f"{INFO_DATE_NOT_FOUND} raw:{datetime_paser_error['raw']}".format(
189+
domain=result_domain
190+
)
173191
)
174-
)
175-
else:
176-
raise ValueError("Invaid Data") # 不可能的路径
177-
178-
# 解析失败的写入 error.txt 文件
179-
if error_file is not None:
180-
async with aiofiles.open(error_file, "a", encoding="utf-8") as f:
192+
else:
193+
raise ValueError("Invaid Data") # 不可能的路径
194+
195+
# 解析失败的写入 error.txt 文件
196+
if error_file is not None:
197+
async with aiofiles.open(error_file, "a", encoding="utf-8") as f:
198+
await f.write(result_domain + "\n")
199+
continue
200+
case Ok(expired_date):
201+
pass
202+
case _:
203+
exit(-1)
204+
205+
# 计算查到的时间是否过期
206+
is_expired_result: Result[bool, Exception] = is_datetime_expired(expired_date)
207+
match is_expired_result:
208+
case Err(e):
209+
# 在检查时间是否过期的时候出现错误
210+
info(f"{INFO_CHECKING_DATE_EXPIRED} {e}".format(domain=result_domain))
211+
# 解析失败的写入 error.txt 文件
212+
if error_file is not None:
213+
async with aiofiles.open(error_file, "a", encoding="utf-8") as f:
214+
await f.write(result_domain + "\n")
215+
continue
216+
case Ok(is_expired):
217+
pass
218+
219+
# 判断是否过期
220+
if is_expired:
221+
info(INFO_EXPIRED.format(domain=result_domain))
222+
# 已过期的写入 output.txt 文件
223+
if output_file is not None:
224+
async with aiofiles.open(output_file, "a", encoding="utf-8") as f:
181225
await f.write(result_domain + "\n")
182226
continue
183-
case Ok(expired_date):
184-
pass
185-
case _:
186-
exit(-1)
187-
188-
# 计算查到的时间是否过期
189-
is_expired_result: Result[bool, Exception] = is_datetime_expired(expired_date)
190-
match is_expired_result:
191-
case Err(e):
192-
# 在检查时间是否过期的时候出现错误
193-
info(f"{INFO_CHECKING_DATE_EXPIRED} {e}".format(domain=result_domain))
194-
# 解析失败的写入 error.txt 文件
195-
if error_file is not None:
196-
async with aiofiles.open(error_file, "a", encoding="utf-8") as f:
197-
await f.write(result_domain + "\n")
198-
continue
199-
case Ok(is_expired):
200-
pass
201-
202-
# 判断是否过期
203-
if is_expired:
204-
info(INFO_EXPIRED.format(domain=result_domain))
205-
# 已过期的写入 output.txt 文件
206-
if output_file is not None:
207-
async with aiofiles.open(output_file, "a", encoding="utf-8") as f:
208-
await f.write(result_domain + "\n")
209-
continue
210227

211228
# 输出未过期的
212229
info(INFO_NOT_EXPIRED.format(domain=result_domain))

src/utils/whois_parser/_whois_parser.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,41 @@ def whois_parser(raw_whois: str) -> ParsedWhoisData:
1616
Returns:
1717
ParsedWhoisData: 解析后的结构化 whois 数据
1818
"""
19+
domain_status = _check_domain_status(raw_whois)
20+
if not domain_status[0]:
21+
return {
22+
"domain": "",
23+
"status": domain_status,
24+
"raw": raw_whois,
25+
"registry_expiry_date": Err(
26+
{
27+
"msg": "Date not found",
28+
"err": ValueError("Date not found"),
29+
"raw": raw_whois,
30+
}
31+
),
32+
}
33+
34+
if raw_whois.startswith("1") or raw_whois.startswith("0"):
35+
# .ch .li 特殊规定 不提供可用的域数据
36+
# https://www.nic.li/whois/domaincheck/#collapse-c25cbf2f-a663-11e6-89db-525400a7a801-2
37+
return {
38+
"domain": "",
39+
"status": domain_status,
40+
"raw": raw_whois,
41+
"registry_expiry_date": Err(
42+
{
43+
"msg": "Date not found",
44+
"err": ValueError("Date not found"),
45+
"raw": raw_whois,
46+
}
47+
),
48+
}
49+
50+
# 已注册 or 赎回期
1951
return {
2052
"domain": "",
21-
"status": _check_domain_status(raw_whois),
53+
"status": domain_status,
2254
"raw": raw_whois,
2355
"registry_expiry_date": _whois_registry_expiry_date_parser(raw_whois),
2456
}
@@ -36,6 +68,12 @@ def _check_domain_status(
3668
Returns:
3769
Tuple[bool, str]: 返回一个元组,第一个元素表示是否为未注册状态,未注册则为 False。第二个元素表示状态("registered", "redemption", "unregistered")。
3870
"""
71+
# .ch .li 特殊规定
72+
if raw_whois.startswith("1"):
73+
return (False, "unregistered")
74+
elif raw_whois.startswith("0"):
75+
return (True, "registered")
76+
3977
if "Domain Status: redemptionPeriod" in raw_whois:
4078
return (True, "redemption")
4179
elif any(

0 commit comments

Comments
 (0)