feat: 国内流量直连分流(geoip-cn / geosite-cn)— #5
国内 IP/域名直连(不走隧道)→ 省流量 + 国内访问快;非国内走代理。
- clientconfig.go: BuildClientConfig 加 ClientConfigOpts{SplitCN,RulesBaseURL};
开启时 route 加 {rule_set:[geoip-cn,geosite-cn]→direct} + 定义 rule_set
(remote .srs,download_detour:direct 直连下载)
- rules.go: 控制面静态服务 /v1/rules/{name}.srs(白名单防穿越)——自托管避免
GitHub 在国内被墙的鸡生蛋;客户端反正连控制面,可达性有保证
- nodes.go ConnectNode: 读 ?split_cn → opts;NodeAPI 加 rulesBaseURL
(PANGOLIN_PUBLIC_URL);main.go 挂 /v1/rules 路由 + RulesHandler
- 客户端: connect_api splitCN→?split_cn=1;connection_provider 传 smartRoute 偏好
- deploy/single-node: 拉 geoip-cn/geosite-cn.srs 到 $DATA_DIR/rules +
设 PANGOLIN_PUBLIC_URL/PANGOLIN_RULES_DIR
验证:go test(splitCN 开/关渲染 + RulesHandler 白名单/404)+ flutter analyze +
shellcheck;不需要节点。订阅链接暂用默认 opts、DNS 分流为后续增强。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,15 @@ import (
|
||||
"github.com/wangjia/pangolin/server/internal/nodes"
|
||||
)
|
||||
|
||||
// ClientConfigOpts carries per-request rendering options for BuildClientConfig.
|
||||
type ClientConfigOpts struct {
|
||||
// SplitCN 开启国内分流:命中 geoip-cn/geosite-cn 的 IP/域名直连(不走隧道)。
|
||||
SplitCN bool
|
||||
// RulesBaseURL 是控制面对外公网基址(如 "http://node:8080"),rule_set 的 .srs
|
||||
// 从 <base>/v1/rules/*.srs 下载。SplitCN 生效需此项非空(否则分流静默跳过)。
|
||||
RulesBaseURL string
|
||||
}
|
||||
|
||||
// BuildClientConfig renders a complete sing-box CLIENT configuration JSON that
|
||||
// the client app passes verbatim to the local tunnel kernel.
|
||||
//
|
||||
@@ -19,9 +28,8 @@ import (
|
||||
// - dpUUID: the authenticated user's data-plane UUID (used as VLESS uuid)
|
||||
// - deriveKey: shared HMAC key used by both server and agent to derive the
|
||||
// Hysteria2 password from dp_uuid (must equal PANGOLIN_AGENT_DERIVE_KEY)
|
||||
// - ttlSeconds: credential lifetime hint; not embedded in the config but can
|
||||
// be used by callers to set a session timer
|
||||
func BuildClientConfig(node *nodes.NodeRow, dpUUID, deriveKey string) ([]byte, error) {
|
||||
// - opts: 渲染选项(国内分流等),见 ClientConfigOpts
|
||||
func BuildClientConfig(node *nodes.NodeRow, dpUUID, deriveKey string, opts ClientConfigOpts) ([]byte, error) {
|
||||
// Parse host:port from endpoint; endpoint format is "host:port".
|
||||
host, _ := splitHostPort(node.Endpoint)
|
||||
if host == "" {
|
||||
@@ -118,19 +126,36 @@ func BuildClientConfig(node *nodes.NodeRow, dpUUID, deriveKey string) ([]byte, e
|
||||
"tolerance": 50,
|
||||
}
|
||||
|
||||
// Route: LAN direct, everything else via auto.
|
||||
route := map[string]any{
|
||||
"rules": []any{
|
||||
map[string]any{
|
||||
"ip_cidr": []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "127.0.0.0/8"},
|
||||
"outbound": "direct",
|
||||
},
|
||||
// Route: LAN direct;(可选)国内 IP/域名直连;其余 via auto。
|
||||
routeRules := []any{
|
||||
map[string]any{
|
||||
"ip_cidr": []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "127.0.0.0/8"},
|
||||
"outbound": "direct",
|
||||
},
|
||||
}
|
||||
route := map[string]any{
|
||||
"final": "auto",
|
||||
"auto_detect_interface": true,
|
||||
// sing-box 1.12+ 要求显式声明出站域名用哪个 DNS 解析,缺失即 FATAL。
|
||||
"default_domain_resolver": map[string]any{"server": "local"},
|
||||
}
|
||||
// 国内分流(#5):命中 geoip-cn / geosite-cn → 直连(不走隧道),省流量 + 国内快。
|
||||
// rule_set 走控制面自托管(国内可达,客户端反正连控制面);download_detour:direct
|
||||
// 让 sing-box 直连下载 .srs(不经隧道,启动期隧道还没起)。
|
||||
if opts.SplitCN && opts.RulesBaseURL != "" {
|
||||
base := strings.TrimRight(opts.RulesBaseURL, "/")
|
||||
routeRules = append(routeRules, map[string]any{
|
||||
"rule_set": []string{"geoip-cn", "geosite-cn"},
|
||||
"outbound": "direct",
|
||||
})
|
||||
route["rule_set"] = []any{
|
||||
map[string]any{"tag": "geoip-cn", "type": "remote", "format": "binary",
|
||||
"url": base + "/v1/rules/geoip-cn.srs", "download_detour": "direct"},
|
||||
map[string]any{"tag": "geosite-cn", "type": "remote", "format": "binary",
|
||||
"url": base + "/v1/rules/geosite-cn.srs", "download_detour": "direct"},
|
||||
}
|
||||
}
|
||||
route["rules"] = routeRules
|
||||
|
||||
// DNS: remote over tunnel, local for domestic.
|
||||
// sing-box 1.12+ DNS server format(type+server);旧的 address 串格式在
|
||||
|
||||
Reference in New Issue
Block a user