diff --git a/internal/web/service/node.go b/internal/web/service/node.go index 2d59d0e9e..6fde81f50 100644 --- a/internal/web/service/node.go +++ b/internal/web/service/node.go @@ -533,9 +533,17 @@ func FilterNodeSnapshot(n *model.Node, snap *runtime.TrafficSnapshot) { if n == nil || snap == nil || n.InboundSyncMode != "selected" { return } - allowed := make(map[string]struct{}, len(n.InboundTags)) + prefix := nodeTagPrefix(&n.Id) + allowed := make(map[string]struct{}, len(n.InboundTags)*2) for _, tag := range n.InboundTags { allowed[tag] = struct{}{} + if prefix != "" { + if stripped, found := strings.CutPrefix(tag, prefix); found { + allowed[stripped] = struct{}{} + } else { + allowed[prefix+tag] = struct{}{} + } + } } filtered := make([]*model.Inbound, 0, len(snap.Inbounds)) for _, inbound := range snap.Inbounds { diff --git a/internal/web/service/node_test.go b/internal/web/service/node_test.go index 23f74fc0d..e3f255a26 100644 --- a/internal/web/service/node_test.go +++ b/internal/web/service/node_test.go @@ -212,3 +212,26 @@ func TestFilterNodeSnapshot(t *testing.T) { t.Fatalf("empty selection kept %d inbounds, want 0", len(none.Inbounds)) } } + +func TestFilterNodeSnapshotMatchesPrefixedSelectedTag(t *testing.T) { + snap := &runtime.TrafficSnapshot{Inbounds: []*model.Inbound{ + {Tag: "in-100-tcp"}, + {Tag: "in-443-tcp"}, + }} + FilterNodeSnapshot(&model.Node{ + Id: 5, + InboundSyncMode: "selected", + InboundTags: []string{"in-100-tcp", "n5-in-443-tcp"}, + }, snap) + + kept := make(map[string]bool, len(snap.Inbounds)) + for _, ib := range snap.Inbounds { + kept[ib.Tag] = true + } + if !kept["in-443-tcp"] { + t.Fatalf("node-side tag in-443-tcp filtered out despite the prefixed central tag being selected; kept=%v", kept) + } + if !kept["in-100-tcp"] { + t.Fatalf("bare selected tag in-100-tcp was dropped; kept=%v", kept) + } +}