feat(sub): opt-in dns and sniffer from remote Clash rules (#6868)

Public Mihomo templates ship rules, rule-providers and proxy-groups together
with a dns block those rules depend on (fake-ip ranges, nameserver policy).
Pasting a template inline keeps its dns, but pointing the global routing rules
at its URL dropped it, so URL users had to give up auto-refresh to keep it.

A new switch, subClashRemoteDNS (off by default), also takes the remote dns and
sniffer maps. It is opt-in because a remote dns block decides where clients send
every lookup. A malformed dns or sniffer value is skipped, not the whole template.
The component-test teardown now outlasts AntD Form's 10ms error debounce, which
otherwise fired after jsdom was gone.
This commit is contained in:
Duxxie
2026-10-24 05:21:04 +03:00
committed by GitHub
parent 3acdfd9dea
commit c3394fefed
44 changed files with 355 additions and 46 deletions
+6 -6
View File
@@ -20,12 +20,12 @@ import (
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
)
func mergeRemoteClashRulesYAML(base map[string]any, raw string) error {
func mergeRemoteClashRulesYAML(base map[string]any, raw string, allowClientConfig bool) error {
var remote map[string]any
if err := yaml.Unmarshal([]byte(strings.TrimSpace(raw)), &remote); err != nil {
return err
}
return mergeRemoteClashRules(base, remote)
return mergeRemoteClashRules(base, remote, allowClientConfig)
}
type remoteRoutingRoundTripper func(*http.Request) (*http.Response, error)
@@ -475,7 +475,7 @@ rules:
- RULE-SET,roscom,PROXY
- MATCH,PROXY
`
if err := mergeRemoteClashRulesYAML(base, remote); err != nil {
if err := mergeRemoteClashRulesYAML(base, remote, false); err != nil {
t.Fatalf("merge: %v", err)
}
proxies, ok := base["proxies"].([]map[string]any)
@@ -520,7 +520,7 @@ func TestMergeRemoteClashRulesKeepsBaseProxyGroupWhenRemoteOmitsIt(t *testing.T)
proxies: [PROXY]
rules:
- MATCH,PROXY
`); err != nil {
`, false); err != nil {
t.Fatalf("merge: %v", err)
}
groups, ok := asAnySlice(base["proxy-groups"])
@@ -692,7 +692,7 @@ func TestRemoteClashRouteGraphValidation(t *testing.T) {
}},
"rules": []string{"MATCH,PROXY"},
}
err := mergeRemoteClashRulesYAML(base, tt.remote)
err := mergeRemoteClashRulesYAML(base, tt.remote, false)
if err == nil || !strings.Contains(err.Error(), tt.wantErr) {
t.Fatalf("err=%v, want %q", err, tt.wantErr)
}
@@ -741,7 +741,7 @@ rules:
}},
"rules": []string{"MATCH,PROXY"},
}
if err := mergeRemoteClashRules(base, entry.Clash); err != nil {
if err := mergeRemoteClashRules(base, entry.Clash, false); err != nil {
t.Fatalf("merge cached document: %v", err)
}
if requests.Load() != 1 {