fix(diag): host 参数走 base64 避免 GFW 拦明文敏感词诊断请求
控制面跑明文 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 <noreply@anthropic.com>
This commit is contained in:
@@ -111,9 +111,13 @@ def echo_ip(urls):
|
|||||||
def node_egress(host):
|
def node_egress(host):
|
||||||
"""量「节点→目标」出海段。优先走控制面诊断端点(HTTP,无需 SSH),
|
"""量「节点→目标」出海段。优先走控制面诊断端点(HTTP,无需 SSH),
|
||||||
回退到 NODE_SSH(curl)。返回 dict{tls_ms,dns_ms,ttfb_ms} 或 None。"""
|
回退到 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:
|
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:
|
with urllib.request.urlopen(u, timeout=TIMEOUT, context=_ctx()) as resp:
|
||||||
d = json.load(resp)
|
d = json.load(resp)
|
||||||
if d.get("tls_ms") is not None:
|
if d.get("tls_ms") is not None:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package httpapi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -36,17 +37,32 @@ type egressTiming struct {
|
|||||||
Err string `json:"err,omitempty"`
|
Err string `json:"err,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EgressTiming 处理 GET /v1/diag/egress?host=X:量 节点→host 的 DNS/TCP/TLS/TTFB
|
// EgressTiming 处理 GET /v1/diag/egress?host=X 或 ?host_b64=<base64url(host)>:
|
||||||
// 各段独立耗时(出海段),返回 JSON。host 必须在白名单内。
|
// 量 节点→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) {
|
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")
|
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] {
|
if !diagAllowedHosts[host] {
|
||||||
w.WriteHeader(http.StatusForbidden)
|
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
|
return
|
||||||
}
|
}
|
||||||
_ = json.NewEncoder(w).Encode(measureEgress(host))
|
res := measureEgress(host)
|
||||||
|
res.Host = echo // 不在响应里回明文敏感词
|
||||||
|
_ = json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// measureEgress 在本机(节点)上测到 host:443 的分段耗时。各段为该阶段独立耗时。
|
// measureEgress 在本机(节点)上测到 host:443 的分段耗时。各段为该阶段独立耗时。
|
||||||
|
|||||||
Reference in New Issue
Block a user