Repository navigation
feat(log): add test route rule in log window - #143
Conversation
Add a route tester to the log window's toolbar: enter a domain, IP or URL and it shows whether the live core sends it direct, to the proxy, or blocks it, along with the outbound tag. Rather than re-implement rule matching in C# (geosite/geoip, the domain matchers, domainStrategy DNS resolution, balancers), it asks the running core. Every built config now carries an api section exposing only RoutingService on a fresh loopback port, and the tester calls RoutingService.TestRoute, which runs the same PickRoute real connections use. gRPC is spoken over HttpClient h2c with the protobuf hand-encoded in RouteTestProtocol, so no Grpc/Protobuf packages are added under AOT. The inbound tag the test claims, and the default outbound reported when no rule matches, are both read back from the built config, like the system proxy port, so custom config profiles with their own tags get correct answers. A profile that declares its own api section is left alone and the tester reports it is unavailable. URLs without a port use their scheme's default port so port rules see what a real connection would. The free-port helper moves from RealLatencyProbeService to Helpers/LoopbackPort so both users share it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e92e6e2d45
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (target.Ip is { } ip) | ||
| WriteBytes(context, CtxTargetIps, ip.GetAddressBytes()); | ||
| WriteVarintField(context, CtxTargetPort, (ulong)target.Port); | ||
| if (!string.IsNullOrEmpty(target.Domain)) | ||
| WriteString(context, CtxTargetDomain, target.Domain); |
There was a problem hiding this comment.
Mark route results as ambiguous for process-based rules
When smart routing contains a GUI or Advanced Edit process rule, an actual connection from the matching executable may be sent direct or blocked, but this synthetic context contains only network, destination, port, and inbound-tag data, so the process rule cannot match and the UI reports a later destination rule or the default outbound instead. This is a supported configuration path (XrayConfigBuilder.BuildSmartRules explicitly installs process rules), so the tester should either accept the relevant process context or warn that no definitive result is available when process-dependent rules are active.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Won't fix; documented under Known limits instead. xray resolves process rules from the OS socket table, so a synthetic TestRoute request can't carry a process. The result is exact for apps no process rule covers, and the per-connection verdicts in the same log window show the real outcome for a specific app.
What
A route tester in the log window: a new toolbar button (magnifier) opens a flyout where you type a domain, IP or URL. It shows whether the running core would send it direct / proxy / block, plus the outbound tag. It is only available while connected.
How
It asks the live core instead of re-implementing xray's rule matching in C#.
XrayConfigBuilder.Buildaddsapi: { tag: "api", listen: "127.0.0.1:<fresh port>", services: ["RoutingService"] }to every config.api.listenopens the gRPC listener directly, with no extra inbound or routing rule. A config profile that declares its ownapiis left untouched, and the tester reports that it is unavailable.RouteTestServicecallsRoutingService.TestRouteusing gRPC overHttpClienth2c (Version20+RequestVersionExact).RouteTestProtocolhand-encodes the protobuf (one request, one response field), so no Grpc/Protobuf packages are added under AOT.TestRouteruns the router's ownPickRoute, the same one real connections use. Results therefore includedomainStrategyDNS resolution (IPIfNonMatch) and balancer picks, and cover every rule source: built-in template, GUI rules, Advanced Edit, TUN lead rules, and config profiles.inboundTagrules in custom profiles match);host:port, or a full URL. A URL without a port uses its scheme's default (http/ws→ 80).XrayService.StartAsync(BuiltXrayConfig)publishesXrayService.RouteTestwhile the core runs and clears it on stop or exit. The log window drops a stale result whenever the core restarts (reapply picks a new port).RealLatencyProbeServicetoHelpers/LoopbackPortand is shared by both.Reviewer notes
RoutingContexthas no rule tag.processrules never match: a synthetic request has no originating process (xray resolves it from the OS socket table), so results describe apps no process rule covers.RoutingServiceon loopback. It includesAddRule/RemoveRule, so a local process could alter live routing. The effect is limited to routing, and only local processes can reach it.Testing
dotnet test XrayUI.Tests/XrayUI.Tests.csproj -c Release: 209 passed. New tests cover protobuf encode/decode, input parsing and scheme default ports, andFindRouteTestInboundTag.inboundTagand port rules match;IPIfNonMatch:dotnet publishwith AOT succeeds without trim warnings.api" path in the UI.