mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 17:10:43 +00:00
被控端 - 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%) - 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败) - 每分钟回头找局域网,自动切回快 400 倍的路径 - 画面心跳帧:静止时省流量,客户端仍知道流是活的 - 锁屏时给出可操作的提示 手表端 - 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException - 连接错误翻译成人话(证书/时间/解析/超时分别提示) - 经中转连上后用服务器报的地址刷新已配对记录 - 新增局域网连接页面、服务器延迟检测 服务器端 - 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502) - 网络调优脚本 net-tune.sh(开机自动应用) - 管理页:批量删除、网络体检、下载区 - 隧道改 HTTP/2 + 双连接 文档 - 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
144 lines
5.8 KiB
Python
144 lines
5.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""三个修复:
|
||
|
||
1. 【关键】被控端发请求要带 User-Agent
|
||
Cloudflare 的 Browser Integrity Check 把 Python 默认 UA
|
||
(Python-urllib/3.11)当成可疑客户端,返回 403 + error code 1010。
|
||
实测 LanRemote/1.4.0 能过。
|
||
不修的话:固定域名上线后,被控端根本连不上。
|
||
(手表端 Java 已经带了 LanRemote-Watch/1.4,没问题)
|
||
|
||
2. setup_named_tunnel.sh 写的 public_url.txt 少了 https://
|
||
导致 /url 接口和 status 显示"还没有地址"。
|
||
|
||
3. install.sh 里钉的 Cloudflare API IP 是错的
|
||
我之前猜的 104.16.132.229 返回的是错误页(error code 1034),
|
||
不是 API。真实地址要用公共 DNS 查(104.19.192.174 等)。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||
RELAY = ROOT / "windows" / "lanremote" / "relay.py"
|
||
SETUP = ROOT / "_build" / "setup_named_tunnel.sh"
|
||
INSTALL = ROOT / "relay" / "install.sh"
|
||
|
||
# ---------------- 1. relay.py 加 UA ----------------
|
||
|
||
UA_CONST_ANCHOR = '''# 私有网段 + 回环 + mDNS 名字'''
|
||
|
||
UA_CONST = '''# 请求头。**必须带 User-Agent**:
|
||
# Cloudflare 的 Browser Integrity Check 会把 Python 默认 UA
|
||
# (Python-urllib/3.11)判为可疑客户端,返回 403 + error code 1010。
|
||
# 实测 LanRemote/1.4.0 能过,用自家标识比伪装浏览器合适。
|
||
USER_AGENT = "LanRemote/1.4.0"
|
||
|
||
|
||
# 私有网段 + 回环 + mDNS 名字'''
|
||
|
||
UA_PROBE_OLD = ''' request = urllib.request.Request(base + "/v1/health")'''
|
||
UA_PROBE_NEW = ''' request = urllib.request.Request(
|
||
base + "/v1/health", headers={"User-Agent": USER_AGENT})'''
|
||
|
||
# ---------------- 2. setup_named_tunnel.sh 补 https:// ----------------
|
||
|
||
SETUP_OLD = '''echo "$HOSTNAME_FULL" > "$RELAY_DIR/public_url.txt"'''
|
||
SETUP_NEW = '''# 一定要带 https:// —— public_url() 只认以 http 开头的,
|
||
# 少了协议头 /url 接口会显示"还没有地址"。
|
||
echo "https://$HOSTNAME_FULL" > "$RELAY_DIR/public_url.txt"'''
|
||
|
||
# ---------------- 3. install.sh 换真实 IP ----------------
|
||
|
||
INSTALL_OLD = ''' echo "104.16.132.229 api.cloudflare.com"
|
||
echo "104.16.133.229 api.cloudflare.com"'''
|
||
INSTALL_NEW = ''' # 这几个是用公共 DNS(1.1.1.1 / 8.8.8.8 / 223.5.5.5)查出来的
|
||
# 真实地址。之前随手挑的 104.16.132.229 是错的 ——
|
||
# 它返回 Cloudflare 错误页(error code: 1034)而不是 API,
|
||
# 会导致 cloudflared tunnel create 报 unauthorized。
|
||
echo "104.19.192.174 api.cloudflare.com"
|
||
echo "104.19.192.175 api.cloudflare.com"
|
||
echo "104.19.192.176 api.cloudflare.com"
|
||
echo "104.19.192.177 api.cloudflare.com"
|
||
echo "104.17.0.1 api.cloudflare.com"
|
||
echo "104.18.0.1 api.cloudflare.com"'''
|
||
|
||
# 检查逻辑也要跟着改:现在该看响应是不是 API JSON,不是只看状态码
|
||
INSTALL_CHECK_OLD = '''if is_real_cf "$CF_IP" && { [ "$CF_CODE" = "403" ] || [ "$CF_CODE" = "200" ]; }; then
|
||
echo " ✓ 正常(没被劫持)"'''
|
||
INSTALL_CHECK_NEW = '''CF_BODY=$(timeout 12 curl -4 -s https://api.cloudflare.com/client/v4/user 2>/dev/null | head -c 200)
|
||
if is_real_cf "$CF_IP" && echo "$CF_BODY" | grep -q '"success"'; then
|
||
echo " ✓ 正常(返回的是真正的 API JSON)"'''
|
||
INSTALL_CHECK2_OLD = ''' if [ "$CF_CODE2" = "403" ] || [ "$CF_CODE2" = "200" ]; then
|
||
echo " ✓ 修好了"'''
|
||
INSTALL_CHECK2_NEW = ''' CF_BODY2=$(timeout 12 curl -4 -s https://api.cloudflare.com/client/v4/user 2>/dev/null | head -c 200)
|
||
if echo "$CF_BODY2" | grep -q '"success"'; then
|
||
echo " ✓ 修好了(返回的是真正的 API JSON)"'''
|
||
|
||
|
||
def patch(path: Path, pairs, label: str) -> bool:
|
||
text = path.read_text(encoding="utf-8")
|
||
ok = True
|
||
for old, new, tag in pairs:
|
||
if old not in text:
|
||
print(f" [{label}] [跳过] {tag} —— 锚点没找到")
|
||
ok = False
|
||
continue
|
||
text = text.replace(old, new, 1)
|
||
print(f" [{label}] {tag}")
|
||
path.write_text(text, encoding="utf-8", newline="\n")
|
||
raw = path.read_bytes()
|
||
if b"\r\n" in raw and path.suffix == ".sh":
|
||
path.write_bytes(raw.replace(b"\r\n", b"\n"))
|
||
print(f" [{label}] 顺手修了 CRLF")
|
||
return ok
|
||
|
||
|
||
def main() -> int:
|
||
ok = True
|
||
|
||
ok &= patch(RELAY, [
|
||
(UA_CONST_ANCHOR, UA_CONST, "加 USER_AGENT 常量"),
|
||
(UA_PROBE_OLD, UA_PROBE_NEW, "_probe 带 UA"),
|
||
], "relay.py")
|
||
|
||
# _post 那处:把 headers 里补上 UA
|
||
text = RELAY.read_text(encoding="utf-8")
|
||
post_old = ''' request = urllib.request.Request(self.url + path, data=body,'''
|
||
if post_old in text:
|
||
# 找 _post 里构造 headers 的地方,统一并入 UA
|
||
text = text.replace(
|
||
post_old,
|
||
''' headers = dict(headers or {})
|
||
headers.setdefault("User-Agent", USER_AGENT)
|
||
request = urllib.request.Request(self.url + path, data=body,''',
|
||
1)
|
||
RELAY.write_text(text, encoding="utf-8", newline="\n")
|
||
print(" [relay.py] _post 带 UA")
|
||
else:
|
||
print(" [relay.py] [跳过] _post 锚点没找到")
|
||
|
||
ok &= patch(SETUP, [(SETUP_OLD, SETUP_NEW, "public_url.txt 补 https://")],
|
||
"setup_named_tunnel.sh")
|
||
|
||
ok &= patch(INSTALL, [
|
||
(INSTALL_OLD, INSTALL_NEW, "换成真实 IP"),
|
||
(INSTALL_CHECK_OLD, INSTALL_CHECK_NEW, "判断改成看 JSON"),
|
||
(INSTALL_CHECK2_OLD, INSTALL_CHECK2_NEW, "第二处判断"),
|
||
], "install.sh")
|
||
|
||
import ast
|
||
try:
|
||
ast.parse(RELAY.read_text(encoding="utf-8"))
|
||
print(" relay.py 语法 OK")
|
||
except SyntaxError as exc:
|
||
print(f" relay.py 语法错误: {exc}")
|
||
ok = False
|
||
|
||
return 0 if ok else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|