diff --git a/internal/web/service/xray_setting_routing_sync.go b/internal/web/service/xray_setting_routing_sync.go index 363fcb33c..c230b6f49 100644 --- a/internal/web/service/xray_setting_routing_sync.go +++ b/internal/web/service/xray_setting_routing_sync.go @@ -5,8 +5,8 @@ import ( ) var routingMatcherKeys = []string{ - "domain", "ip", "port", "sourcePort", "localPort", "network", - "sourceIP", "localIP", "user", "vlessRoute", "protocol", "attrs", "process", + "domain", "domains", "ip", "port", "sourcePort", "localPort", "network", + "source", "sourceIP", "localIP", "user", "vlessRoute", "protocol", "attrs", "process", } func readInboundTags(raw any) []string { diff --git a/internal/web/service/xray_setting_routing_sync_test.go b/internal/web/service/xray_setting_routing_sync_test.go index c5ac2b28b..cf3e1b7ec 100644 --- a/internal/web/service/xray_setting_routing_sync_test.go +++ b/internal/web/service/xray_setting_routing_sync_test.go @@ -158,6 +158,39 @@ func TestRemoveInboundTagReferences_KeepsRuleWithOtherMatchers(t *testing.T) { } } +func TestRemoveInboundTagReferences_KeepsSourceScopedRule(t *testing.T) { + setupSettingTestDB(t) + seedXrayTemplate(t, `{ + "routing": { + "rules": [ + { + "type":"field", + "inboundTag":["in-443-tcp"], + "source":["10.0.0.0/8"], + "outboundTag":"blocked" + } + ] + } + }`) + + svc := &XraySettingService{} + if _, err := svc.RemoveInboundTagReferences("in-443-tcp"); err != nil { + t.Fatalf("RemoveInboundTagReferences: %v", err) + } + + got, err := svc.GetXrayConfigTemplate() + if err != nil { + t.Fatalf("GetXrayConfigTemplate: %v", err) + } + rule := findRuleByOutbound(t, got, "blocked") + if _, ok := rule["inboundTag"]; ok { + t.Fatalf("inboundTag should be trimmed, rule = %#v", rule) + } + if src, _ := rule["source"].([]any); len(src) != 1 { + t.Fatalf("source-scoped rule was dropped instead of kept; rule = %#v", rule) + } +} + func TestRemoveInboundTagReferences_RemovesOneTagFromMultiInboundRule(t *testing.T) { setupSettingTestDB(t) seedXrayTemplate(t, `{