-
Notifications
You must be signed in to change notification settings - Fork 56
fix: pin real-latency speed test to physical NIC under TUN mode #92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -215,9 +215,7 @@ private static JsonArray BuildOutbounds( | |
| foreach (var outbound in list.OfType<JsonObject>()) | ||
| { | ||
| var tag = outbound["tag"]?.GetValue<string>(); | ||
| var protocol = outbound["protocol"]?.GetValue<string>(); | ||
| if (tag is ProxyOutboundTag or DirectOutboundTag or ChainEntryOutboundTag | ||
| && !string.Equals(protocol, "wireguard", StringComparison.OrdinalIgnoreCase)) | ||
| if (tag is ProxyOutboundTag or DirectOutboundTag or ChainEntryOutboundTag) | ||
| { | ||
| ApplyOutboundInterface(outbound, outboundInterface); | ||
| } | ||
|
|
@@ -227,7 +225,7 @@ private static JsonArray BuildOutbounds( | |
| return list; | ||
| } | ||
|
|
||
| private static string? NormalizeTunOutboundInterface(string? interfaceName) | ||
| internal static string? NormalizeTunOutboundInterface(string? interfaceName) | ||
| { | ||
| if (string.IsNullOrWhiteSpace(interfaceName)) | ||
| return null; | ||
|
|
@@ -280,6 +278,13 @@ private static void ApplyProxySettings(JsonObject outbound, string tag) | |
|
|
||
| private static void ApplyOutboundInterface(JsonObject outbound, string interfaceName) | ||
| { | ||
| // Wireguard outbounds carry no streamSettings, so a sockopt pin cannot apply there — | ||
| // the process-routing rule stays their only cover. Centralized here so every caller | ||
| // gets the exemption without repeating it. | ||
| var protocol = outbound["protocol"]?.GetValue<string>(); | ||
| if (string.Equals(protocol, "wireguard", StringComparison.OrdinalIgnoreCase)) | ||
| return; | ||
|
|
||
| var streamSettings = outbound["streamSettings"] as JsonObject; | ||
| if (streamSettings is null) | ||
| { | ||
|
|
@@ -861,7 +866,9 @@ private static void AppendTunLeadRules(JsonArray rules, AppSettings settings) | |
| { | ||
| ["type"] = "field", | ||
| ["outboundTag"] = DirectOutboundTag, | ||
| ["process"] = CreateStringArray("self/", "xray/") | ||
| // Keep the plain process-name fallback as well as Xray's path sugars. Process | ||
| // attribution for a second helper core can occasionally lack the full path. | ||
| ["process"] = CreateStringArray("self/", "xray/", "xray") | ||
| }); | ||
| } | ||
|
|
||
|
|
@@ -1083,8 +1090,14 @@ private static void AddValue(JsonArray array, string value) | |
| /// the caller must filter them out. | ||
| /// </summary> | ||
| /// <param name="entries">Each server paired with the local socks port it should listen on.</param> | ||
| /// <param name="outboundInterface">Resolved physical interface name to pin every proxy | ||
| /// outbound to (see <see cref="TunService.ResolveOutboundInterface"/>), or null for no | ||
| /// pin. The pin is required when another Xray process owns a full-route TUN, otherwise | ||
| /// this helper core's node connections can be captured and proxy-looped. Taken verbatim — | ||
| /// callers resolve the "auto" sentinel first.</param> | ||
| public static string BuildSpeedtestConfig( | ||
| IReadOnlyList<(ServerEntry server, int port)> entries) | ||
| IReadOnlyList<(ServerEntry server, int port)> entries, | ||
| string? outboundInterface) | ||
| { | ||
| var inbounds = new JsonArray(); | ||
| var outbounds = new JsonArray(); | ||
|
|
@@ -1109,7 +1122,12 @@ public static string BuildSpeedtestConfig( | |
| } | ||
| }); | ||
|
|
||
| AddNode(outbounds, BuildProxyOutbound(server, outTag)); | ||
| var outbound = BuildProxyOutbound(server, outTag); | ||
| if (outboundInterface is not null) | ||
| { | ||
| ApplyOutboundInterface(outbound, outboundInterface); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When TUN is running with FakeDNS enabled and a tested server's host is a domain, pinning only the helper outbound socket still leaves the helper core's hostname lookup on system DNS. The live TUN rules send Useful? React with 👍 / 👎.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested this live rather than reasoning about it further: connected via TUN with FakeDNS enabled, then ran the real-latency test against several domain-hostname nodes (e.g. Checked the actual generated Per Xray's docs, Given that, I don't think the |
||
| } | ||
| AddNode(outbounds, outbound); | ||
|
|
||
| AddNode(rules, new JsonObject | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In auto mode with two up non-TUN adapters that both have default gateways, this tie-break can choose a faster but non-routed/isolated interface instead of the adapter Windows would actually use for the proxy server or test URL. The speed-test config then pins every helper outbound to that wrong NIC and reports timeouts even though the live TUN path works; resolve the interface from the route table/metric for the destination rather than link speed.
Useful? React with 👍 / 👎.