fix(server): 补 #5 国内分流的 DNS 面 + 链路诊断端点(#12)

#5 只分了数据面(geoip/geosite-cn 路由 direct),DNS 仍 final:remote 全量经隧道
解析 → 国内域名解析到非 CN IP、漏过 geoip-cn 又走隧道(白盒实测国内 TLS
1000-1660ms;修后 ~50ms)。

- clientconfig.go: 开分流时 dns.rules 加 {rule_set:[geosite-cn]→local},国内域名
  用 local(223.5.5.5)直连解析 → 拿到真 CN IP → geoip-cn 命中直连
- main.go: PANGOLIN_PUBLIC_URL 缺失时启动告警(空则分流静默跳过,是隐蔽坑)
- nodes.go: connect 渲染加可观测日志(split_cn/rules_base/split_active/bytes)
- diag.go: 新增只读端点 GET /v1/diag/egress?host=X,节点侧量出海段耗时(白名单
  防 SSRF、只回耗时数字),供白盒拆「接入段 vs 出海段」

验证:go test(splitCN 开渲染 dns.rules→local、关无 dns.rules)+ go vet;cara
实测国内 TLS 1000ms+→~50ms、接入段占 TLS 握手 ~98%。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-22 14:12:31 +08:00
parent 43b25c8aa0
commit bc890974c0
5 changed files with 146 additions and 4 deletions
+13 -1
View File
@@ -296,7 +296,15 @@ func mountV1(r chi.Router, sqlDB *sql.DB, rdb *redis.Client, nodeSvc *nodes.Serv
var nodeStore nodes.NodeStore
if nodeSvc != nil {
nodeStore = nodeSvc.Store()
nodeAPI = httpapi.NewNodeAPI(nodeStore, nodeSvc.Hub(), os.Getenv("NODE_DERIVE_KEY"), os.Getenv("PANGOLIN_PUBLIC_URL"))
publicURL := os.Getenv("PANGOLIN_PUBLIC_URL")
if publicURL == "" {
// 没设 PANGOLIN_PUBLIC_URL → BuildClientConfig 会静默跳过国内分流
// (rule_set 没有公网基址可下载),客户端 split_cn=1 也无效、全量走隧道。
// 这是个隐蔽坑(国内流量绕道出海、变慢),启动期显式告警。
slog.Warn("PANGOLIN_PUBLIC_URL 未设置:国内分流(split_cn)将被静默跳过,客户端全量走隧道。" +
"如需国内直连,设为控制面对外公网基址(如 http://<公网IP>:8080)")
}
nodeAPI = httpapi.NewNodeAPI(nodeStore, nodeSvc.Hub(), os.Getenv("NODE_DERIVE_KEY"), publicURL)
}
// 国内分流(#5)的 rule-set 静态服务:GET /v1/rules/{name}.srs(自托管,
@@ -317,6 +325,10 @@ func mountV1(r chi.Router, sqlDB *sql.DB, rdb *redis.Client, nodeSvc *nodes.Serv
// Public (no auth): 国内分流 rule-set 下载(sing-box 不带 token)。
v1.Get("/rules/{name}", rulesHandler.Serve)
// Public (no auth): 诊断端点,量节点→目标出海段耗时(白名单限定,防 SSRF),
// 供白盒拆「接入段 vs 出海段」。只返回耗时数字,不传业务数据。
v1.Get("/diag/egress", httpapi.NewDiagHandler().EgressTiming)
// Public (no auth): auth endpoints.
if authHandler != nil {
v1.Post("/auth/code", authHandler.SendCode)