From 5ea9b4ea28ccecb3dc04d58f79d017413fda640b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A2=A8=E9=9B=AA?= Date: Fri, 28 Aug 2026 00:26:00 +0800 Subject: [PATCH] fix: unique listener names; ignore listeners in custom config fragments --- backend/internal/mihomo/config/generator.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backend/internal/mihomo/config/generator.go b/backend/internal/mihomo/config/generator.go index 67fa5fb..94144e8 100644 --- a/backend/internal/mihomo/config/generator.go +++ b/backend/internal/mihomo/config/generator.go @@ -42,6 +42,9 @@ func (ce *ConfigEngine) GenerateFinalConfig() (string, error) { if err := yaml.Unmarshal([]byte(fragment.Content), &fragMap); err != nil { return "", fmt.Errorf("invalid custom config %q: %w", fragment.Name, err) } + // Listeners are owned by the panel DB; fragments must not inject them + // or Mihomo will report duplicate listener names after merge. + delete(fragMap, "listeners") for k, v := range fragMap { merged[k] = v } @@ -73,10 +76,19 @@ func (ce *ConfigEngine) GenerateFinalConfig() (string, error) { } func validateListenerEndpoints(listeners []models.Listener) error { + seenNames := make(map[string]struct{}, len(listeners)) for i := range listeners { if err := validateListenerEndpoint(&listeners[i]); err != nil { return err } + name := strings.TrimSpace(listeners[i].Name) + if name == "" { + return fmt.Errorf("listener id=%d has empty name", listeners[i].ID) + } + if _, ok := seenNames[name]; ok { + return fmt.Errorf("duplicate listener name %q — rename or delete the extra entry in 节点管理", name) + } + seenNames[name] = struct{}{} for j := i + 1; j < len(listeners); j++ { if !portsOverlap(listeners[i].Port, listeners[j].Port) { continue