From 7a4d0cf7cd329a0d847b033a7bc5e528bfb569dc Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Mon, 22 Jun 2026 14:34:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(diag):=20host=20=E5=8F=82=E6=95=B0=E8=B5=B0?= =?UTF-8?q?=20base64=20=E9=81=BF=E5=85=8D=20GFW=20=E6=8B=A6=E6=98=8E?= =?UTF-8?q?=E6=96=87=E6=95=8F=E6=84=9F=E8=AF=8D=E8=AF=8A=E6=96=AD=E8=AF=B7?= =?UTF-8?q?=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 控制面跑明文 HTTP 在国外 IP 上,白盒诊断请求 URL 里出现 google/youtube 等 GFW 敏感词时被墙重置(返回空)→ 出海段拿不到、报告显示「—」。改:host 用 base64url 传(host_b64),响应也回 b64、不回明文,明文里无敏感词(不影响真实加密隧道流量)。 - diag.go: EgressTiming 支持 ?host_b64=,解码后查白名单,响应 echo b64 - vpn_whitebox.py: node_egress 用 base64url 编码 host 验证:cara(墙内)google/youtube 出海段从 None → 8-9ms,与 github/cloudflare 一致。 Co-Authored-By: Claude Opus 4.8 --- scripts/vpn_whitebox.py | 8 ++++++-- server/internal/httpapi/diag.go | 26 +++++++++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/scripts/vpn_whitebox.py b/scripts/vpn_whitebox.py index a61dbfd..0f3d0b2 100644 --- a/scripts/vpn_whitebox.py +++ b/scripts/vpn_whitebox.py @@ -111,9 +111,13 @@ def echo_ip(urls): def node_egress(host): """量「节点→目标」出海段。优先走控制面诊断端点(HTTP,无需 SSH), 回退到 NODE_SSH(curl)。返回 dict{tls_ms,dns_ms,ttfb_ms} 或 None。""" - # 1) 控制面诊断端点 /v1/diag/egress(节点本机量出海段) + # 1) 控制面诊断端点 /v1/diag/egress(节点本机量出海段)。 + # host 用 base64url 传(host_b64):控制面是国外 IP 上的明文 HTTP,URL 里出现 + # google/youtube 等敏感词会被 GFW 重置;base64 后明文不含敏感词,避免诊断被拦。 + import base64 + hb = base64.urlsafe_b64encode(host.encode()).rstrip(b"=").decode() try: - u = CONTROL_PLANE.rstrip("/") + "/v1/diag/egress?host=" + host + u = CONTROL_PLANE.rstrip("/") + "/v1/diag/egress?host_b64=" + hb with urllib.request.urlopen(u, timeout=TIMEOUT, context=_ctx()) as resp: d = json.load(resp) if d.get("tls_ms") is not None: diff --git a/server/internal/httpapi/diag.go b/server/internal/httpapi/diag.go index f15f05a..223732b 100644 --- a/server/internal/httpapi/diag.go +++ b/server/internal/httpapi/diag.go @@ -2,6 +2,7 @@ package httpapi import ( "crypto/tls" + "encoding/base64" "encoding/json" "net" "net/http" @@ -36,17 +37,32 @@ type egressTiming struct { Err string `json:"err,omitempty"` } -// EgressTiming 处理 GET /v1/diag/egress?host=X:量 节点→host 的 DNS/TCP/TLS/TTFB -// 各段独立耗时(出海段),返回 JSON。host 必须在白名单内。 +// EgressTiming 处理 GET /v1/diag/egress?host=X 或 ?host_b64=: +// 量 节点→host 的 DNS/TCP/TLS/TTFB 各段独立耗时(出海段),返回 JSON。 +// host_b64 用途:控制面跑明文 HTTP 在国外 IP 上,URL/响应里若出现 google/youtube +// 等 GFW 敏感词会被墙重置;客户端改传 base64、服务端解码并在响应里回 base64(echo), +// 明文里不出现敏感词,避免诊断请求被 GFW 拦(不影响真实加密隧道流量)。 func (h *DiagHandler) EgressTiming(w http.ResponseWriter, r *http.Request) { - host := r.URL.Query().Get("host") w.Header().Set("Content-Type", "application/json; charset=utf-8") + host := r.URL.Query().Get("host") + echo := host // 响应里回显的标识;用 b64 时回 b64(不回明文敏感词) + if b := r.URL.Query().Get("host_b64"); b != "" { + dec, err := base64.RawURLEncoding.DecodeString(b) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + _ = json.NewEncoder(w).Encode(egressTiming{Err: "bad host_b64"}) + return + } + host, echo = string(dec), b + } if !diagAllowedHosts[host] { w.WriteHeader(http.StatusForbidden) - _ = json.NewEncoder(w).Encode(egressTiming{Host: host, Err: "host not allowed"}) + _ = json.NewEncoder(w).Encode(egressTiming{Host: echo, Err: "host not allowed"}) return } - _ = json.NewEncoder(w).Encode(measureEgress(host)) + res := measureEgress(host) + res.Host = echo // 不在响应里回明文敏感词 + _ = json.NewEncoder(w).Encode(res) } // measureEgress 在本机(节点)上测到 host:443 的分段耗时。各段为该阶段独立耗时。