fix(sub): align sing-box export with migration 1.11–1.15

Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
fix(sub): align sing-box export with migration 1.11–1.15
Drop deprecated DNS rule ip_is_private without match_response (1.14/1.16).
Keep typed DNS servers, TUN without stack, route sniff/hijack-dns actions,
and route-level private direct per official migration/deprecated docs.
This commit is contained in:
kazeyukiro committed 2026-09-29 14:28:01 +00:00
1 parent 4e68f45c5d
commit addf8aee32
3 files changed
+25 -13

No files matched your search

+13 -12
View File
@@ -95,10 +95,9 @@ func buildSingboxSubscriptionDoc(outbounds []map[string]interface{}) map[string]
defaultSingboxTUNInbound(),
},
"outbounds": outbounds,
// Route: private traffic stays local; DNS is hijacked into the dns module;
// everything else uses the proxy selector. Domain names of outbounds are
// resolved via local DNS so we do not create a DNS↔proxy dependency loop
// (a common cause of "works but extremely laggy" on SFA).
// Route uses rule actions (sniff / hijack-dns) instead of legacy inbound fields
// (removed in 1.13). ip_is_private on *route* rules is still valid; DNS rules
// must not use bare ip_is_private without match_response (deprecated 1.14).
"route": map[string]interface{}{
"rules": []map[string]interface{}{
{"action": "sniff"},
@@ -122,8 +121,10 @@ func buildSingboxSubscriptionDoc(outbounds []map[string]interface{}) map[string]
}
}
// defaultSingboxDNS: resolve outbound server names via local; general queries via
// DoH through the proxy selector (after the outbound domain is known).
// defaultSingboxDNS uses the post-1.12 server object format (type/tag/server)
// and avoids deprecated DNS rule address filters (ip_is_private / ip_cidr without
// match_response — removed path in 1.16). Private destinations are handled by
// route rules instead. See https://sing-box.sagernet.org/migration/
func defaultSingboxDNS() map[string]interface{} {
return map[string]interface{}{
"servers": []map[string]interface{}{
@@ -139,17 +140,17 @@ func defaultSingboxDNS() map[string]interface{} {
"detour": "proxy",
},
},
"rules": []map[string]interface{}{
// Prefer local for private reverse lookups / plain local names.
{"ip_is_private": true, "action": "route", "server": "local"},
},
"final": "remote",
"strategy": "prefer_ipv4",
}
}
// defaultSingboxTUNInbound mirrors common SFA templates without stack/auto_redirect
// (auto_redirect is Linux-oriented and often hurts mobile clients).
// defaultSingboxTUNInbound follows current Tun schema:
// - address (not inet4_address / inet6_address, removed in 1.12)
// - no stack (deprecated 1.15, removed in 1.17 — client uses sing-tun default)
// - no inbound sniff / domain_strategy (removed in 1.13; use route rule actions)
// - dns_mode hijack (1.14+) with route hijack-dns rules
// https://sing-box.sagernet.org/configuration/inbound/tun/
func defaultSingboxTUNInbound() map[string]interface{} {
return map[string]interface{}{
"type": "tun",
@@ -41,6 +41,17 @@ func TestBuildSingboxSubscriptionDocIncludesTUN(t *testing.T) {
if !ok || dns["final"] != "remote" {
t.Fatalf("dns: %#v", parsed["dns"])
}
// 1.14+: DNS rules must not use legacy address filters without match_response.
if rules, ok := dns["rules"].([]interface{}); ok {
for _, r := range rules {
m, _ := r.(map[string]interface{})
if _, has := m["ip_is_private"]; has {
if match, _ := m["match_response"].(bool); !match {
t.Fatalf("deprecated DNS ip_is_private without match_response: %#v", m)
}
}
}
}
route, ok := parsed["route"].(map[string]interface{})
if !ok {
t.Fatalf("missing route")
+1 -1
View File
@@ -11,7 +11,7 @@ Public token URL (path may use `web_path` / custom sub base):
| *(empty / clash / default)* | Mihomo / Clash Meta YAML |
| `v2ray` / `base64` | **Always** standard Base64 of newline-separated share links (`vless://`, `vmess://`, `tuic://`, …). Independent of HTML page “encrypt URI list”. |
| `uri` / `raw` | Same links; may be plaintext when encrypt is off |
| `singbox` / `sing-box` | sing-box JSON with default **TUN** + **DNS** (remote via proxy) + `route.rules` sniff/hijack-dns + `route.final=proxy` (SFI/SFA mobile-friendly MTU) (SFI/SFM) and node outbounds |
| `singbox` / `sing-box` | sing-box JSON with default **TUN** (no `stack`, `address` only) + **DNS** (typed servers, no legacy address filters) + `route.rules` sniff/hijack-dns + private→direct + `route.final=proxy` (aligned with sing-box migration 1.11–1.15) (SFI/SFM) and node outbounds |
UA auto-detection may choose Clash vs v2ray-style when `target` is omitted.