Fix fragment packet selection for REALITY (#10428)

This commit is contained in:
Wu Shuwen
2026-11-01 20:39:08 +08:00
committed by GitHub
parent 4169c12a1f
commit ad3e24b6b5
2 changed files with 62 additions and 2 deletions
@@ -21,6 +21,61 @@ public class CoreConfigV2rayServiceTests
await v2rayConfig.inbounds.Should().Contain(i => i.protocol == nameof(EInboundProtocol.mixed));
}
[Test]
public async Task GenerateClientConfigContent_RealityFragment_ShouldUsePacketRangeOnlyForReality()
{
static ProfileItem CreateVlessNode(string indexId, string streamSecurity)
{
var node = new ProfileItem
{
IndexId = indexId,
ConfigType = EConfigType.VLESS,
CoreType = ECoreType.Xray,
Remarks = indexId,
Address = "example.com",
Port = 443,
Password = "01234567-89ab-cdef-0123-456789abcdef",
Network = nameof(ETransport.raw),
StreamSecurity = streamSecurity,
PublicKey = "test-public-key",
Sni = "example.com",
Fingerprint = "chrome",
};
node.SetProtocolExtra(new ProtocolExtraItem { VlessEncryption = Global.None });
node.SetTransportExtra(new TransportExtraItem { RawHeaderType = Global.None });
return node;
}
static string GetFragmentPackets(Outbounds4Ray outbound)
{
var finalmask = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings!.finalmask));
return finalmask!["tcp"]![0]!["settings"]!["packets"]!.GetValue<string>();
}
var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray);
config.CoreBasicItem.EnableFragment = true;
CoreConfigTestFactory.BindAppManagerConfig(config);
var tlsNode = CreateVlessNode("tls-node", Global.StreamSecurity);
var realityNode = CreateVlessNode("reality-node", Global.StreamSecurityReality);
var group = CoreConfigTestFactory.CreatePolicyGroupNode(ECoreType.Xray, "group", "group",
[tlsNode.IndexId, realityNode.IndexId]);
var context = CoreConfigTestFactory.CreateContext(config, group, ECoreType.Xray);
context.AllProxiesMap[tlsNode.IndexId] = tlsNode;
context.AllProxiesMap[realityNode.IndexId] = realityNode;
context.AllProxiesMap[group.IndexId] = group;
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
await result.Success.Should().BeTrue();
var cfg = JsonUtils.Deserialize<V2rayConfig>(result.Data!.ToString())!;
var tlsOutbound = cfg.outbounds.Single(o => o.streamSettings?.security == Global.StreamSecurity);
var realityOutbound = cfg.outbounds.Single(o => o.streamSettings?.security == Global.StreamSecurityReality);
await GetFragmentPackets(tlsOutbound).Should().BeEqualTo("tlshello");
await GetFragmentPackets(realityOutbound).Should().BeEqualTo("1-3");
}
[Test]
public async Task GenerateClientConfigContent_HttpOutbound_ShouldEmitHeadersInSettings()
{
@@ -809,8 +809,6 @@ public partial class CoreConfigV2rayService
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
.ToList();
var fragmentMask = BuildFragmentsMasks();
foreach (var outbound in actOutboundWithTlsList)
{
var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject();
@@ -818,6 +816,13 @@ public partial class CoreConfigV2rayService
var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? [];
if (tcpFinalmaskList.Count == 0)
{
var fragmentMask = BuildFragmentsMasks();
// Xray's tlshello fragment is incompatible with REALITY.
if (outbound.streamSettings.security == Global.StreamSecurityReality
&& fragmentMask.settings?.packets == "tlshello")
{
fragmentMask.settings!.packets = "1-3";
}
tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask));
finalMaskJsonObj["tcp"] = tcpFinalmaskList;
}