mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 18:20:43 +00:00
ykxmz 1.5.0:修复手表端 TLS 证书校验 + MTU 修复网络稳定性
被控端 - 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%) - 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败) - 每分钟回头找局域网,自动切回快 400 倍的路径 - 画面心跳帧:静止时省流量,客户端仍知道流是活的 - 锁屏时给出可操作的提示 手表端 - 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException - 连接错误翻译成人话(证书/时间/解析/超时分别提示) - 经中转连上后用服务器报的地址刷新已配对记录 - 新增局域网连接页面、服务器延迟检测 服务器端 - 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502) - 网络调优脚本 net-tune.sh(开机自动应用) - 管理页:批量删除、网络体检、下载区 - 隧道改 HTTP/2 + 双连接 文档 - 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""防火墙检测与修复脚本测试。
|
||||
|
||||
背景(真机踩到的坑):
|
||||
Windows 防火墙的「阻止」规则**优先级高于「放行」规则**。
|
||||
当系统弹「是否允许此应用通过防火墙」而用户点了取消时,
|
||||
系统会自动建一条 Block 规则,之后加多少 Allow 都不管用。
|
||||
|
||||
而且规则是按**程序完整路径**建的,换个目录解压就多一条。
|
||||
|
||||
又因为防火墙不过滤回环(127.0.0.1),本地自测全绿、真机永远超时。
|
||||
|
||||
这里验证:
|
||||
1. netsh 输出解析(中英文两种语言都要认)
|
||||
2. 阻止规则识别
|
||||
3. 修复脚本内容正确(先删阻止、再建放行)
|
||||
|
||||
不需要管理员权限:不实际执行提权,只验证解析与脚本生成。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "windows"))
|
||||
|
||||
from lanremote import firewall # noqa: E402
|
||||
|
||||
PASSED = 0
|
||||
FAILED = 0
|
||||
|
||||
|
||||
def check(name: str, ok: bool, detail: str = "") -> None:
|
||||
global PASSED, FAILED
|
||||
if ok:
|
||||
PASSED += 1
|
||||
print(f" [PASS] {name}")
|
||||
else:
|
||||
FAILED += 1
|
||||
print(f" [FAIL] {name} {detail}")
|
||||
|
||||
|
||||
# 中文系统的 netsh 输出样例(字段名是中文的)
|
||||
ZH_RULE = """规则名称: ykxmz.exe
|
||||
----------------------------------------------------------------------
|
||||
已启用: 是
|
||||
方向: 入
|
||||
配置文件: 公用
|
||||
分组:
|
||||
本地 IP: 任何
|
||||
远程 IP: 任何
|
||||
协议: TCP
|
||||
本地端口: 任何
|
||||
远程端口: 任何
|
||||
边缘遍历: 否
|
||||
程序: C:\\Users\\shu\\Desktop\\LanRemote\\dist_exe\\ykxmz\\ykxmz.exe
|
||||
操作: 阻止
|
||||
"""
|
||||
|
||||
EN_RULE = """Rule Name: ykxmz.exe
|
||||
----------------------------------------------------------------------
|
||||
Enabled: Yes
|
||||
Direction: In
|
||||
Profiles: Public
|
||||
Grouping:
|
||||
LocalIP: Any
|
||||
RemoteIP: Any
|
||||
Protocol: UDP
|
||||
LocalPort: Any
|
||||
RemotePort: Any
|
||||
Edge traversal: No
|
||||
Program: C:\\test\\ykxmz.exe
|
||||
Action: Block
|
||||
"""
|
||||
|
||||
ALLOW_RULE = """规则名称: LAN Remote TCP
|
||||
----------------------------------------------------------------------
|
||||
已启用: 是
|
||||
方向: 入
|
||||
配置文件: 域,专用,公用
|
||||
协议: TCP
|
||||
本地端口: 8765
|
||||
程序:
|
||||
操作: 允许
|
||||
"""
|
||||
|
||||
|
||||
def main() -> int:
|
||||
print("=" * 68)
|
||||
print("一、netsh 输出解析(中英文都要认)")
|
||||
print("=" * 68)
|
||||
|
||||
zh = firewall._parse_fields(ZH_RULE)
|
||||
check("中文输出: 规则名解析正确",
|
||||
zh.get("RuleName") == "ykxmz.exe", str(zh.get("RuleName")))
|
||||
check("中文输出: 操作解析为「阻止」",
|
||||
zh.get("Action") == "阻止", str(zh.get("Action")))
|
||||
check("中文输出: 协议解析正确", zh.get("Protocol") == "TCP", str(zh.get("Protocol")))
|
||||
check("中文输出: 程序路径解析正确",
|
||||
(zh.get("Program") or "").lower().endswith("ykxmz.exe"),
|
||||
str(zh.get("Program")))
|
||||
|
||||
en = firewall._parse_fields(EN_RULE)
|
||||
check("英文输出: 规则名解析正确",
|
||||
en.get("RuleName") == "ykxmz.exe", str(en.get("RuleName")))
|
||||
check("英文输出: 操作解析为 Block", en.get("Action") == "Block", str(en.get("Action")))
|
||||
check("英文输出: 协议解析正确", en.get("Protocol") == "UDP", str(en.get("Protocol")))
|
||||
|
||||
allow = firewall._parse_fields(ALLOW_RULE)
|
||||
check("放行规则不会被误判为阻止",
|
||||
(allow.get("Action") or "").lower() not in firewall._BLOCK_VALUES,
|
||||
str(allow.get("Action")))
|
||||
|
||||
print()
|
||||
print("=" * 68)
|
||||
print("二、规则切分与阻止规则识别(模拟完整 netsh 输出)")
|
||||
print("=" * 68)
|
||||
|
||||
combined = ZH_RULE + "\n" + ALLOW_RULE + "\n" + EN_RULE
|
||||
rules = firewall._split_rules(combined)
|
||||
check("切分出 3 条规则", len(rules) == 3, f"得到 {len(rules)}")
|
||||
|
||||
blocks = [r for r in rules
|
||||
if (r.get("Action") or "").lower() in firewall._BLOCK_VALUES]
|
||||
check("其中 2 条是阻止规则", len(blocks) == 2, f"得到 {len(blocks)}")
|
||||
|
||||
names = {firewall.os.path.basename((r.get("Program") or "").strip('"')).lower()
|
||||
for r in blocks}
|
||||
check("阻止规则都指向本程序",
|
||||
names == {"ykxmz.exe"}, str(names))
|
||||
|
||||
print()
|
||||
print("=" * 68)
|
||||
print("三、修复脚本内容(先删阻止,再建放行)")
|
||||
print("=" * 68)
|
||||
|
||||
script = firewall.build_script(8765, 8766)
|
||||
check("脚本删除了 ykxmz.exe 的规则",
|
||||
'delete rule name="ykxmz.exe" dir=in' in script)
|
||||
check("脚本删除了 python.exe 的规则(源码模式遗留)",
|
||||
'delete rule name="python.exe" dir=in' in script)
|
||||
check("脚本重建 TCP 放行规则",
|
||||
'add rule name="LAN Remote TCP"' in script
|
||||
and "protocol=TCP localport=8765" in script)
|
||||
check("脚本重建 UDP 放行规则",
|
||||
'add rule name="LAN Remote UDP"' in script
|
||||
and "protocol=UDP localport=8766" in script)
|
||||
# 端口放行 2 条 + 程序级放行 2 条 = 4 条,全部覆盖域/专用/公用
|
||||
check("脚本使用 profile=any(公用/专用/域都放行)",
|
||||
script.count("profile=any") == 4, f"出现 {script.count('profile=any')} 次")
|
||||
# 源码模式下不能把打包版的程序级规则冲掉(真机事故)
|
||||
target = firewall.target_executable()
|
||||
check("修复目标是一个真实的可执行文件",
|
||||
bool(target) and target.lower().endswith(".exe"), str(target))
|
||||
if not getattr(sys, "frozen", False):
|
||||
existing = firewall.app_rule_program()
|
||||
# 注意还要看那个路径**现在还在不在** ——
|
||||
# 规则指向一个已经删掉的旧副本时,target_executable 会(正确地)
|
||||
# 退回 python.exe。测试条件漏了这一点就会假失败(改名后就踩了)。
|
||||
if (existing and "python" not in existing.lower()
|
||||
and __import__("os").path.isfile(existing)):
|
||||
check("源码模式下沿用已有的打包版目标,不写 python.exe",
|
||||
"python" not in target.lower(), f"target={target}")
|
||||
elif existing:
|
||||
print(f" (已有规则指向 {existing},但那个文件不在了,"
|
||||
f"所以退回 python.exe —— 这是对的)")
|
||||
print(f" 修复将放行: {target}")
|
||||
|
||||
check("删除动作在添加动作之前",
|
||||
script.index("delete rule") < script.index("add rule"))
|
||||
|
||||
# 真机上踩到的坑:裸 LF 换行会让 cmd 把整个脚本解析成一堆无效命令
|
||||
lone_lf = script.count("\n") - script.count("\r\n")
|
||||
check("脚本全部使用 CRLF 换行(裸 LF 会让 cmd 解析错乱)",
|
||||
lone_lf == 0, f"发现 {lone_lf} 处裸 LF")
|
||||
check("脚本以 chcp 936 开头(配合 GBK 存盘)",
|
||||
script.splitlines()[1].strip() == "chcp 936 >nul",
|
||||
script.splitlines()[1].strip() if len(script.splitlines()) > 1 else "?")
|
||||
check("脚本编码声明可用 GBK 编码",
|
||||
isinstance(script.encode("gbk", errors="replace"), bytes))
|
||||
|
||||
# 只删阻止规则治标不治本:必须补程序级放行,否则系统会再生成阻止规则
|
||||
check("脚本添加了程序级放行规则(治本)",
|
||||
"LAN Remote App TCP" in script and "LAN Remote App UDP" in script)
|
||||
check("程序级放行规则指向真实可执行文件",
|
||||
'program="' in script and ".exe" in script.lower(),
|
||||
"未找到 program= 指向")
|
||||
check("程序级规则 enable=yes 且 profile=any",
|
||||
script.count("enable=yes protocol=") == 2
|
||||
and script.count("profile=any") >= 4,
|
||||
f"enable=yes 出现 {script.count('enable=yes protocol=')} 次")
|
||||
|
||||
print()
|
||||
print("=" * 68)
|
||||
print("四、真实状态查询(本机)")
|
||||
print("=" * 68)
|
||||
|
||||
status = firewall.check(8765, 8766)
|
||||
for key in ("supported", "ok", "tcp", "udp", "blocked", "blocked_count",
|
||||
"elevated", "message", "tcp_port", "udp_port"):
|
||||
check(f"状态包含字段 {key}", key in status)
|
||||
|
||||
check("字段类型正确",
|
||||
isinstance(status["blocked"], list)
|
||||
and isinstance(status["blocked_count"], int)
|
||||
and isinstance(status["ok"], bool))
|
||||
|
||||
check("状态包含 app_rule(程序级放行)字段", "app_rule" in status)
|
||||
check("状态包含 blocked_others(其他副本的阻止规则数)",
|
||||
"blocked_others" in status)
|
||||
|
||||
# 阻止规则按程序路径生效:别的副本被阻止不该影响本安装的判定
|
||||
print()
|
||||
print(" —— 作用域检查:只统计当前程序 ——")
|
||||
live = r"C:\Users\shu\Desktop\deepseekagent\ykxmz\ykxmz.exe"
|
||||
original = firewall.executable_path
|
||||
try:
|
||||
firewall.executable_path = lambda: live
|
||||
scoped = firewall.check(8765, 8766)
|
||||
print(f" 以「实际安装」视角: 本程序阻止规则={scoped['blocked_count']} 条, "
|
||||
f"其他副本={scoped['blocked_others']} 条, ok={scoped['ok']}")
|
||||
check("其他副本的阻止规则不影响本安装判定",
|
||||
scoped["ok"] is True or scoped["blocked_count"] > 0,
|
||||
f"blocked={scoped['blocked_count']} others={scoped['blocked_others']}")
|
||||
check("blocked 只包含当前程序的规则",
|
||||
all((b.get("Program") or "").lower() == live.lower()
|
||||
for b in scoped["blocked"]),
|
||||
str([b.get("Program") for b in scoped["blocked"]]))
|
||||
check("blocked_count + blocked_others 等于全部阻止规则数",
|
||||
scoped["blocked_count"] + scoped["blocked_others"]
|
||||
== len(firewall.list_block_rules()),
|
||||
f"{scoped['blocked_count']}+{scoped['blocked_others']} "
|
||||
f"vs {len(firewall.list_block_rules())}")
|
||||
finally:
|
||||
firewall.executable_path = original
|
||||
check("有阻止规则时 ok 必为 False",
|
||||
status["blocked_count"] == 0 or status["ok"] is False)
|
||||
|
||||
print(f" 本机结果: ok={status['ok']} 阻止规则={status['blocked_count']} 条")
|
||||
print(f" 说明: {status['message']}")
|
||||
for item in status["blocked"][:3]:
|
||||
print(f" - {item.get('ProgramBase')} {item.get('Protocol')} "
|
||||
f"{(item.get('Program') or '')[-48:]}")
|
||||
|
||||
if status["blocked_count"] > 0:
|
||||
check("有阻止规则时 ok 必须为 False(阻止压过放行)",
|
||||
status["ok"] is False)
|
||||
check("阻止规则条数与列表长度一致",
|
||||
status["blocked_count"] == len(status["blocked"]))
|
||||
|
||||
print()
|
||||
print("=" * 68)
|
||||
print(f"通过 {PASSED} 项,失败 {FAILED} 项")
|
||||
print("=" * 68)
|
||||
return 1 if FAILED else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user