Compare commits

..

7 commits

Author SHA1 Message Date
DHR60
366daef7c5 Fix
Fix raw http ui

Fill xhttp default mode

Fix share uri

Remove RawHost

Fix singbox tcp http path

Fix vmess share uri
2026-03-29 17:22:58 +08:00
DHR60
8de4ba082d Fix 2026-03-29 17:22:58 +08:00
DHR60
0458df7b69 Rename tcp to raw 2026-03-29 17:22:58 +08:00
DHR60
40770dd250 Refactor transport 2026-03-29 17:22:58 +08:00
2dust
1090afd774 up 7.20.0
Some checks are pending
release Linux / build (Release) (push) Waiting to run
release Linux / deb (push) Blocked by required conditions
release Linux / rpm (push) Blocked by required conditions
release macOS / build (Release) (push) Waiting to run
release Windows desktop (Avalonia UI) / build (Release) (push) Waiting to run
release Windows / build (Release) (push) Waiting to run
2026-03-29 15:05:55 +08:00
2dust
c758c5abf9 Update Directory.Packages.props 2026-03-29 15:05:30 +08:00
DHR60
c61b023ab3
Allow enable legacy process name tun protect (#9005) 2026-03-29 14:44:04 +08:00
33 changed files with 331 additions and 177 deletions

View file

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.19.5</Version> <Version>7.20.0</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -6,11 +6,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.4.1" /> <PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.4.1" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.12" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.12" /> <PackageVersion Include="Avalonia.Desktop" Version="11.3.13" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.3.13" />
<PackageVersion Include="ReactiveUI.Avalonia" Version="11.4.12" /> <PackageVersion Include="ReactiveUI.Avalonia" Version="11.4.12" />
<PackageVersion Include="CliWrap" Version="3.10.0" /> <PackageVersion Include="CliWrap" Version="3.10.1" />
<PackageVersion Include="Downloader" Version="5.1.0" /> <PackageVersion Include="Downloader" Version="5.1.0" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" /> <PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
<PackageVersion Include="MaterialDesignThemes" Version="5.3.1" /> <PackageVersion Include="MaterialDesignThemes" Version="5.3.1" />

View file

@ -45,6 +45,8 @@ public class Global
public const string DefaultNetwork = "raw"; public const string DefaultNetwork = "raw";
public const string RawHeaderHttp = "http"; public const string RawHeaderHttp = "http";
public const string None = "none"; public const string None = "none";
public const string RawNetworkAlias = "tcp";
public const string DefaultXhttpMode = "auto";
public const string ProxyTag = "proxy"; public const string ProxyTag = "proxy";
public const string DirectTag = "direct"; public const string DirectTag = "direct";
public const string BlockTag = "block"; public const string BlockTag = "block";

View file

@ -92,6 +92,7 @@ public static class ConfigHandler
EnableTun = false, EnableTun = false,
Mtu = 9000, Mtu = 9000,
IcmpRouting = Global.TunIcmpRoutingPolicies.First(), IcmpRouting = Global.TunIcmpRoutingPolicies.First(),
EnableLegacyProtect = false,
}; };
config.GuiItem ??= new(); config.GuiItem ??= new();
config.MsgUIItem ??= new(); config.MsgUIItem ??= new();
@ -1138,7 +1139,6 @@ public static class ConfigHandler
&& AreEqual(oProtocolExtra.VmessSecurity, nProtocolExtra.VmessSecurity) && AreEqual(oProtocolExtra.VmessSecurity, nProtocolExtra.VmessSecurity)
&& AreEqual(o.Network, n.Network) && AreEqual(o.Network, n.Network)
&& AreEqual(oTransport.RawHeaderType, nTransport.RawHeaderType) && AreEqual(oTransport.RawHeaderType, nTransport.RawHeaderType)
&& AreEqual(oTransport.RawHost, nTransport.RawHost)
&& AreEqual(oTransport.Host, nTransport.Host) && AreEqual(oTransport.Host, nTransport.Host)
&& AreEqual(oTransport.Path, nTransport.Path) && AreEqual(oTransport.Path, nTransport.Path)
&& AreEqual(oTransport.XhttpMode, nTransport.XhttpMode) && AreEqual(oTransport.XhttpMode, nTransport.XhttpMode)
@ -1416,19 +1416,32 @@ public static class ConfigHandler
/// <returns>A SOCKS profile item or null if not needed</returns> /// <returns>A SOCKS profile item or null if not needed</returns>
public static ProfileItem? GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType) public static ProfileItem? GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
{ {
if (node.ConfigType != EConfigType.Custom || !(node.PreSocksPort > 0))
{
return null;
}
ProfileItem? itemSocks = null; ProfileItem? itemSocks = null;
var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray; if (node.ConfigType != EConfigType.Custom
itemSocks = new ProfileItem() && coreType != ECoreType.sing_box
&& config.TunModeItem.EnableTun
&& config.TunModeItem.EnableLegacyProtect)
{ {
CoreType = preCoreType, itemSocks = new ProfileItem()
ConfigType = EConfigType.SOCKS, {
Address = Global.Loopback, CoreType = ECoreType.sing_box,
Port = node.PreSocksPort.Value, ConfigType = EConfigType.SOCKS,
}; Address = Global.Loopback,
Port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks)
};
}
else if (node.ConfigType == EConfigType.Custom
&& node.PreSocksPort is > 0 and <= 65535)
{
var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
itemSocks = new ProfileItem()
{
CoreType = preCoreType,
ConfigType = EConfigType.SOCKS,
Address = Global.Loopback,
Port = node.PreSocksPort.Value,
};
}
return itemSocks; return itemSocks;
} }

View file

@ -5,6 +5,7 @@ namespace ServiceLib.Handler.Fmt;
public class BaseFmt public class BaseFmt
{ {
private static readonly string[] _allowInsecureArray = new[] { "insecure", "allowInsecure", "allow_insecure" }; private static readonly string[] _allowInsecureArray = new[] { "insecure", "allowInsecure", "allow_insecure" };
private static string UrlEncodeSafe(string? value) => Utils.UrlEncode(value ?? string.Empty);
protected static string GetIpv6(string address) protected static string GetIpv6(string address)
{ {
@ -95,15 +96,20 @@ public class BaseFmt
network = nameof(ETransport.raw); network = nameof(ETransport.raw);
} }
dicQuery.Add("type", network); //dicQuery.Add("type", network);
dicQuery.Add("type", network == nameof(ETransport.raw) ? Global.RawNetworkAlias : network);
switch (network) switch (network)
{ {
case nameof(ETransport.raw): case nameof(ETransport.raw):
dicQuery.Add("headerType", transport.RawHeaderType.IsNotEmpty() ? transport.RawHeaderType : Global.None); dicQuery.Add("headerType", transport.RawHeaderType.IsNotEmpty() ? transport.RawHeaderType : Global.None);
if (transport.RawHost.IsNotEmpty()) if (transport.Host.IsNotEmpty())
{ {
dicQuery.Add("host", Utils.UrlEncode(transport.RawHost)); dicQuery.Add("host", UrlEncodeSafe(transport.Host));
}
if (transport.Path.IsNotEmpty())
{
dicQuery.Add("path", UrlEncodeSafe(transport.Path));
} }
break; break;
@ -111,44 +117,34 @@ public class BaseFmt
dicQuery.Add("headerType", transport.KcpHeaderType.IsNotEmpty() ? transport.KcpHeaderType : Global.None); dicQuery.Add("headerType", transport.KcpHeaderType.IsNotEmpty() ? transport.KcpHeaderType : Global.None);
if (transport.KcpSeed.IsNotEmpty()) if (transport.KcpSeed.IsNotEmpty())
{ {
dicQuery.Add("seed", Utils.UrlEncode(transport.KcpSeed)); dicQuery.Add("seed", UrlEncodeSafe(transport.KcpSeed));
} }
break; break;
case nameof(ETransport.ws): case nameof(ETransport.ws):
if (transport.Host.IsNotEmpty())
{
dicQuery.Add("host", Utils.UrlEncode(transport.Host));
}
if (transport.Path.IsNotEmpty())
{
dicQuery.Add("path", Utils.UrlEncode(transport.Path));
}
break;
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
if (transport.Host.IsNotEmpty()) if (transport.Host.IsNotEmpty())
{ {
dicQuery.Add("host", Utils.UrlEncode(transport.Host)); dicQuery.Add("host", UrlEncodeSafe(transport.Host));
} }
if (transport.Path.IsNotEmpty()) if (transport.Path.IsNotEmpty())
{ {
dicQuery.Add("path", Utils.UrlEncode(transport.Path)); dicQuery.Add("path", UrlEncodeSafe(transport.Path));
} }
break; break;
case nameof(ETransport.xhttp): case nameof(ETransport.xhttp):
if (transport.Host.IsNotEmpty()) if (transport.Host.IsNotEmpty())
{ {
dicQuery.Add("host", Utils.UrlEncode(transport.Host)); dicQuery.Add("host", UrlEncodeSafe(transport.Host));
} }
if (transport.Path.IsNotEmpty()) if (transport.Path.IsNotEmpty())
{ {
dicQuery.Add("path", Utils.UrlEncode(transport.Path)); dicQuery.Add("path", UrlEncodeSafe(transport.Path));
} }
if (transport.XhttpMode.IsNotEmpty() && Global.XhttpMode.Contains(transport.XhttpMode)) if (transport.XhttpMode.IsNotEmpty() && Global.XhttpMode.Contains(transport.XhttpMode))
{ {
dicQuery.Add("mode", Utils.UrlEncode(transport.XhttpMode)); dicQuery.Add("mode", UrlEncodeSafe(transport.XhttpMode));
} }
if (transport.XhttpExtra.IsNotEmpty()) if (transport.XhttpExtra.IsNotEmpty())
{ {
@ -161,18 +157,18 @@ public class BaseFmt
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}) })
: transport.XhttpExtra; : transport.XhttpExtra;
dicQuery.Add("extra", Utils.UrlEncode(extra)); dicQuery.Add("extra", UrlEncodeSafe(extra));
} }
break; break;
case nameof(ETransport.grpc): case nameof(ETransport.grpc):
if (transport.GrpcServiceName.IsNotEmpty()) if (transport.GrpcServiceName.IsNotEmpty())
{ {
dicQuery.Add("authority", Utils.UrlEncode(transport.GrpcAuthority)); dicQuery.Add("authority", UrlEncodeSafe(transport.GrpcAuthority));
dicQuery.Add("serviceName", Utils.UrlEncode(transport.GrpcServiceName)); dicQuery.Add("serviceName", UrlEncodeSafe(transport.GrpcServiceName));
if (transport.GrpcMode is Global.GrpcGunMode or Global.GrpcMultiMode) if (transport.GrpcMode is Global.GrpcGunMode or Global.GrpcMultiMode)
{ {
dicQuery.Add("mode", Utils.UrlEncode(transport.GrpcMode)); dicQuery.Add("mode", UrlEncodeSafe(transport.GrpcMode));
} }
} }
break; break;
@ -260,6 +256,10 @@ public class BaseFmt
} }
var net = GetQueryValue(query, "type", nameof(ETransport.raw)); var net = GetQueryValue(query, "type", nameof(ETransport.raw));
if (net == Global.RawNetworkAlias)
{
net = nameof(ETransport.raw);
}
if (!Global.Networks.Contains(net)) if (!Global.Networks.Contains(net))
{ {
net = nameof(ETransport.raw); net = nameof(ETransport.raw);
@ -272,7 +272,8 @@ public class BaseFmt
transport = transport with transport = transport with
{ {
RawHeaderType = GetQueryValue(query, "headerType", Global.None), RawHeaderType = GetQueryValue(query, "headerType", Global.None),
RawHost = GetQueryDecoded(query, "host"), Host = GetQueryDecoded(query, "host"),
Path = GetQueryDecoded(query, "path"),
}; };
break; break;
@ -286,13 +287,6 @@ public class BaseFmt
break; break;
case nameof(ETransport.ws): case nameof(ETransport.ws):
transport = transport with
{
Host = GetQueryDecoded(query, "host"),
Path = GetQueryDecoded(query, "path", "/"),
};
break;
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
transport = transport with transport = transport with
{ {

View file

@ -51,7 +51,7 @@ public class ShadowsocksFmt : BaseFmt
if (item.Network == nameof(ETransport.raw) && transport.RawHeaderType == Global.RawHeaderHttp) if (item.Network == nameof(ETransport.raw) && transport.RawHeaderType == Global.RawHeaderHttp)
{ {
plugin = "obfs-local"; plugin = "obfs-local";
pluginArgs = $"obfs=http;obfs-host={transport.RawHost};"; pluginArgs = $"obfs=http;obfs-host={transport.Host};";
} }
else else
{ {
@ -213,7 +213,7 @@ public class ShadowsocksFmt : BaseFmt
item.SetTransportExtra(item.GetTransportExtra() with item.SetTransportExtra(item.GetTransportExtra() with
{ {
RawHeaderType = Global.RawHeaderHttp, RawHeaderType = Global.RawHeaderHttp,
RawHost = obfsHost, Host = obfsHost,
}); });
} }
} }

View file

@ -34,7 +34,7 @@ public class VmessFmt : BaseFmt
id = item.Password, id = item.Password,
aid = int.TryParse(item.GetProtocolExtra()?.AlterId, out var result) ? result : 0, aid = int.TryParse(item.GetProtocolExtra()?.AlterId, out var result) ? result : 0,
scy = item.GetProtocolExtra().VmessSecurity ?? "", scy = item.GetProtocolExtra().VmessSecurity ?? "",
net = item.Network, net = item.GetNetwork() == nameof(ETransport.raw) ? Global.RawNetworkAlias : item.Network,
type = item.GetNetwork() switch type = item.GetNetwork() switch
{ {
nameof(ETransport.raw) => item.GetTransportExtra().RawHeaderType, nameof(ETransport.raw) => item.GetTransportExtra().RawHeaderType,
@ -45,7 +45,7 @@ public class VmessFmt : BaseFmt
}, },
host = item.GetNetwork() switch host = item.GetNetwork() switch
{ {
nameof(ETransport.raw) => item.GetTransportExtra().RawHost, nameof(ETransport.raw) => item.GetTransportExtra().Host,
nameof(ETransport.ws) => item.GetTransportExtra().Host, nameof(ETransport.ws) => item.GetTransportExtra().Host,
nameof(ETransport.httpupgrade) => item.GetTransportExtra().Host, nameof(ETransport.httpupgrade) => item.GetTransportExtra().Host,
nameof(ETransport.xhttp) => item.GetTransportExtra().Host, nameof(ETransport.xhttp) => item.GetTransportExtra().Host,
@ -54,6 +54,7 @@ public class VmessFmt : BaseFmt
}, },
path = item.GetNetwork() switch path = item.GetNetwork() switch
{ {
nameof(ETransport.raw) => item.GetTransportExtra().Path,
nameof(ETransport.kcp) => item.GetTransportExtra().KcpSeed, nameof(ETransport.kcp) => item.GetTransportExtra().KcpSeed,
nameof(ETransport.ws) => item.GetTransportExtra().Path, nameof(ETransport.ws) => item.GetTransportExtra().Path,
nameof(ETransport.httpupgrade) => item.GetTransportExtra().Path, nameof(ETransport.httpupgrade) => item.GetTransportExtra().Path,
@ -111,7 +112,7 @@ public class VmessFmt : BaseFmt
}); });
if (vmessQRCode.net.IsNotEmpty()) if (vmessQRCode.net.IsNotEmpty())
{ {
item.Network = vmessQRCode.net; item.Network = vmessQRCode.net == Global.RawNetworkAlias ? nameof(ETransport.raw) : vmessQRCode.net;
} }
if (vmessQRCode.type.IsNotEmpty()) if (vmessQRCode.type.IsNotEmpty())
{ {
@ -126,7 +127,7 @@ public class VmessFmt : BaseFmt
} }
transport = item.GetNetwork() switch transport = item.GetNetwork() switch
{ {
nameof(ETransport.raw) => transport with { RawHost = Utils.ToString(vmessQRCode.host) }, nameof(ETransport.raw) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) },
nameof(ETransport.kcp) => transport with { KcpSeed = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.kcp) => transport with { KcpSeed = Utils.ToString(vmessQRCode.path) },
nameof(ETransport.ws) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.ws) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) },
nameof(ETransport.httpupgrade) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.httpupgrade) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) },
@ -164,7 +165,7 @@ public class VmessFmt : BaseFmt
item.SetProtocolExtra(new ProtocolExtraItem item.SetProtocolExtra(new ProtocolExtraItem
{ {
VmessSecurity = "auto", VmessSecurity = Global.DefaultSecurity,
}); });
var query = Utils.ParseQueryString(url.Query); var query = Utils.ParseQueryString(url.Query);

View file

@ -361,7 +361,7 @@ public sealed class AppManager
{ {
try try
{ {
if (item.Network == "tcp") if (item.Network == Global.RawNetworkAlias)
{ {
item.Network = nameof(ETransport.raw); item.Network = nameof(ETransport.raw);
} }
@ -375,7 +375,8 @@ public sealed class AppManager
transport = transport with transport = transport with
{ {
RawHeaderType = item.HeaderType.NullIfEmpty(), RawHeaderType = item.HeaderType.NullIfEmpty(),
RawHost = item.RequestHost.NullIfEmpty(), Host = item.RequestHost.NullIfEmpty(),
Path = item.Path.NullIfEmpty(),
}; };
break; break;
@ -420,7 +421,7 @@ public sealed class AppManager
transport = transport with transport = transport with
{ {
RawHeaderType = item.HeaderType.NullIfEmpty(), RawHeaderType = item.HeaderType.NullIfEmpty(),
RawHost = item.RequestHost.NullIfEmpty(), Host = item.RequestHost.NullIfEmpty(),
}; };
break; break;
} }

View file

@ -145,6 +145,7 @@ public class TunModeItem
public int Mtu { get; set; } public int Mtu { get; set; }
public bool EnableIPv6Address { get; set; } public bool EnableIPv6Address { get; set; }
public string IcmpRouting { get; set; } public string IcmpRouting { get; set; }
public bool EnableLegacyProtect { get; set; }
} }
[Serializable] [Serializable]

View file

@ -169,7 +169,7 @@ public class ProfileItem
public string Network { get; set; } public string Network { get; set; }
[Obsolete("Use TransportExtra.RawHeaderType/XhttpMode/GrpcMode/KcpHeaderType instead.")] [Obsolete("Use TransportExtra.RawHeaderType/XhttpMode/GrpcMode/KcpHeaderType instead.")]
public string HeaderType { get; set; } public string HeaderType { get; set; }
[Obsolete("Use TransportExtra.RawHost/Host/GrpcAuthority instead.")] [Obsolete("Use TransportExtra.Host/GrpcAuthority instead.")]
public string RequestHost { get; set; } public string RequestHost { get; set; }
[Obsolete("Use TransportExtra.Path/GrpcServiceName/KcpSeed instead.")] [Obsolete("Use TransportExtra.Path/GrpcServiceName/KcpSeed instead.")]
public string Path { get; set; } public string Path { get; set; }

View file

@ -3,7 +3,6 @@ namespace ServiceLib.Models;
public record TransportExtra public record TransportExtra
{ {
public string? RawHeaderType { get; init; } public string? RawHeaderType { get; init; }
public string? RawHost { get; init; }
public string? Host { get; init; } public string? Host { get; init; }
public string? Path { get; init; } public string? Path { get; init; }

View file

@ -3150,6 +3150,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Legacy TUN Protect 的本地化字符串。
/// </summary>
public static string TbLegacyProtect {
get {
return ResourceManager.GetString("TbLegacyProtect", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Address (IPv4, IPv6) 的本地化字符串。 /// 查找类似 Address (IPv4, IPv6) 的本地化字符串。
/// </summary> /// </summary>

View file

@ -1695,4 +1695,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbIcmpRoutingPolicy" xml:space="preserve"> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</value> <value>ICMP routing policy</value>
</data> </data>
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
</root> </root>

View file

@ -1692,4 +1692,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbIcmpRoutingPolicy" xml:space="preserve"> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</value> <value>ICMP routing policy</value>
</data> </data>
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
</root> </root>

View file

@ -1695,4 +1695,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbIcmpRoutingPolicy" xml:space="preserve"> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</value> <value>ICMP routing policy</value>
</data> </data>
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
</root> </root>

View file

@ -1695,4 +1695,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbIcmpRoutingPolicy" xml:space="preserve"> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</value> <value>ICMP routing policy</value>
</data> </data>
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
</root> </root>

View file

@ -1695,4 +1695,7 @@
<data name="TbIcmpRoutingPolicy" xml:space="preserve"> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</value> <value>ICMP routing policy</value>
</data> </data>
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
</root> </root>

View file

@ -1692,4 +1692,7 @@
<data name="TbIcmpRoutingPolicy" xml:space="preserve"> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP 路由策略</value> <value>ICMP 路由策略</value>
</data> </data>
<data name="TbLegacyProtect" xml:space="preserve">
<value>旧版 TUN 保护</value>
</data>
</root> </root>

View file

@ -1692,4 +1692,7 @@
<data name="TbIcmpRoutingPolicy" xml:space="preserve"> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP 路由策略</value> <value>ICMP 路由策略</value>
</data> </data>
<data name="TbLegacyProtect" xml:space="preserve">
<value>Legacy TUN Protect</value>
</data>
</root> </root>

View file

@ -61,7 +61,8 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
ret.Success = true; ret.Success = true;
ret.Data = ApplyFullConfigTemplate(); ret.Data = ApplyFullConfigTemplate();
if (context.TunProtectSsPort is > 0 and <= 65535) if (!context.AppConfig.TunModeItem.EnableLegacyProtect
&& context.TunProtectSsPort is > 0 and <= 65535)
{ {
var ssInbound = new var ssInbound = new
{ {

View file

@ -119,7 +119,7 @@ public partial class CoreConfigSingboxService
if (network == nameof(ETransport.raw) && transportExtra.RawHeaderType == Global.RawHeaderHttp) if (network == nameof(ETransport.raw) && transportExtra.RawHeaderType == Global.RawHeaderHttp)
{ {
outbound.plugin = "obfs-local"; outbound.plugin = "obfs-local";
outbound.plugin_opts = $"obfs=http;obfs-host={transportExtra.RawHost};"; outbound.plugin_opts = $"obfs=http;obfs-host={transportExtra.Host};";
} }
else else
{ {
@ -383,7 +383,7 @@ public partial class CoreConfigSingboxService
{ {
var host = _node.GetNetwork() switch var host = _node.GetNetwork() switch
{ {
nameof(ETransport.raw) => _node.GetTransportExtra().RawHost, nameof(ETransport.raw) => _node.GetTransportExtra().Host,
nameof(ETransport.ws) => _node.GetTransportExtra().Host, nameof(ETransport.ws) => _node.GetTransportExtra().Host,
nameof(ETransport.httpupgrade) => _node.GetTransportExtra().Host, nameof(ETransport.httpupgrade) => _node.GetTransportExtra().Host,
nameof(ETransport.xhttp) => _node.GetTransportExtra().Host, nameof(ETransport.xhttp) => _node.GetTransportExtra().Host,
@ -453,7 +453,8 @@ public partial class CoreConfigSingboxService
if (transportExtra.RawHeaderType == Global.RawHeaderHttp) if (transportExtra.RawHeaderType == Global.RawHeaderHttp)
{ {
transport.type = nameof(ETransport.http); transport.type = nameof(ETransport.http);
transport.host = transportExtra.RawHost.IsNullOrEmpty() ? null : Utils.String2List(transportExtra.RawHost); transport.host = transportExtra.Host.IsNullOrEmpty() ? null : Utils.String2List(transportExtra.Host);
transport.path = transportExtra.Path.NullIfEmpty();
} }
break; break;

View file

@ -15,7 +15,10 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
var ret = new RetResult(); var ret = new RetResult();
try try
{ {
if (context.IsTunEnabled && context.TunProtectSsPort > 0 && context.ProxyRelaySsPort > 0) if (!context.AppConfig.TunModeItem.EnableLegacyProtect
&& context.IsTunEnabled
&& context.TunProtectSsPort is > 0 and <= 65535
&& context.ProxyRelaySsPort is > 0 and <= 65535)
{ {
return GenerateClientProxyRelayConfig(); return GenerateClientProxyRelayConfig();
} }

View file

@ -357,7 +357,8 @@ public partial class CoreConfigV2rayService
switch (network) switch (network)
{ {
case nameof(ETransport.raw): case nameof(ETransport.raw):
host = transport.RawHost?.TrimEx() ?? string.Empty; host = transport.Host?.TrimEx() ?? string.Empty;
path = transport.Path?.TrimEx() ?? string.Empty;
headerType = transport.RawHeaderType?.TrimEx() ?? string.Empty; headerType = transport.RawHeaderType?.TrimEx() ?? string.Empty;
break; break;

View file

@ -76,9 +76,6 @@ public class AddServerViewModel : MyReactiveObject
[Reactive] [Reactive]
public string RawHeaderType { get; set; } public string RawHeaderType { get; set; }
[Reactive]
public string RawHost { get; set; }
[Reactive] [Reactive]
public string Host { get; set; } public string Host { get; set; }
@ -141,7 +138,7 @@ public class AddServerViewModel : MyReactiveObject
{ {
get => SelectedSource.GetNetwork() switch get => SelectedSource.GetNetwork() switch
{ {
nameof(ETransport.raw) => RawHost, nameof(ETransport.raw) => Host,
nameof(ETransport.ws) => Host, nameof(ETransport.ws) => Host,
nameof(ETransport.httpupgrade) => Host, nameof(ETransport.httpupgrade) => Host,
nameof(ETransport.xhttp) => Host, nameof(ETransport.xhttp) => Host,
@ -153,7 +150,7 @@ public class AddServerViewModel : MyReactiveObject
switch (SelectedSource.GetNetwork()) switch (SelectedSource.GetNetwork())
{ {
case nameof(ETransport.raw): case nameof(ETransport.raw):
RawHost = value; Host = value;
break; break;
case nameof(ETransport.ws): case nameof(ETransport.ws):
Host = value; Host = value;
@ -298,10 +295,9 @@ public class AddServerViewModel : MyReactiveObject
NaiveQuic = protocolExtra?.NaiveQuic ?? false; NaiveQuic = protocolExtra?.NaiveQuic ?? false;
RawHeaderType = transport.RawHeaderType ?? Global.None; RawHeaderType = transport.RawHeaderType ?? Global.None;
RawHost = transport.RawHost ?? string.Empty;
Host = transport.Host ?? string.Empty; Host = transport.Host ?? string.Empty;
Path = transport.Path ?? string.Empty; Path = transport.Path ?? string.Empty;
XhttpMode = transport.XhttpMode ?? string.Empty; XhttpMode = transport.XhttpMode ?? Global.DefaultXhttpMode;
XhttpExtra = transport.XhttpExtra ?? string.Empty; XhttpExtra = transport.XhttpExtra ?? string.Empty;
GrpcAuthority = transport.GrpcAuthority ?? string.Empty; GrpcAuthority = transport.GrpcAuthority ?? string.Empty;
GrpcServiceName = transport.GrpcServiceName ?? string.Empty; GrpcServiceName = transport.GrpcServiceName ?? string.Empty;
@ -363,7 +359,6 @@ public class AddServerViewModel : MyReactiveObject
var transport = new TransportExtra var transport = new TransportExtra
{ {
RawHeaderType = RawHeaderType.NullIfEmpty(), RawHeaderType = RawHeaderType.NullIfEmpty(),
RawHost = RawHost.NullIfEmpty(),
Host = Host.NullIfEmpty(), Host = Host.NullIfEmpty(),
Path = Path.NullIfEmpty(), Path = Path.NullIfEmpty(),
XhttpMode = XhttpMode.NullIfEmpty(), XhttpMode = XhttpMode.NullIfEmpty(),
@ -497,7 +492,7 @@ public class AddServerViewModel : MyReactiveObject
{ {
return SelectedSource.GetNetwork() switch return SelectedSource.GetNetwork() switch
{ {
nameof(ETransport.raw) => RawHost, nameof(ETransport.raw) => Host,
nameof(ETransport.ws) => Host, nameof(ETransport.ws) => Host,
nameof(ETransport.httpupgrade) => Host, nameof(ETransport.httpupgrade) => Host,
nameof(ETransport.xhttp) => Host, nameof(ETransport.xhttp) => Host,

View file

@ -96,6 +96,7 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; } [Reactive] public bool TunEnableIPv6Address { get; set; }
[Reactive] public string TunIcmpRouting { get; set; } [Reactive] public string TunIcmpRouting { get; set; }
[Reactive] public bool TunEnableLegacyProtect { get; set; }
#endregion Tun mode #endregion Tun mode
@ -220,6 +221,7 @@ public class OptionSettingViewModel : MyReactiveObject
TunMtu = _config.TunModeItem.Mtu; TunMtu = _config.TunModeItem.Mtu;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address; TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunIcmpRouting = _config.TunModeItem.IcmpRouting; TunIcmpRouting = _config.TunModeItem.IcmpRouting;
TunEnableLegacyProtect = _config.TunModeItem.EnableLegacyProtect;
#endregion Tun mode #endregion Tun mode
@ -379,6 +381,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.TunModeItem.Mtu = TunMtu; _config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address; _config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
_config.TunModeItem.IcmpRouting = TunIcmpRouting; _config.TunModeItem.IcmpRouting = TunIcmpRouting;
_config.TunModeItem.EnableLegacyProtect = TunEnableLegacyProtect;
//coreType //coreType
await SaveCoreType(); await SaveCoreType();

View file

@ -718,33 +718,54 @@
<Grid Grid.Row="2"> <Grid Grid.Row="2">
<Grid <Grid
x:Name="gridTransportRaw" x:Name="gridTransportRaw"
ColumnDefinitions="300,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto"> RowDefinitions="Auto,Auto">
<TextBlock <Grid Grid.Row="0" ColumnDefinitions="300,Auto">
Grid.Row="0" <TextBlock
Grid.Column="0" Grid.Row="0"
Margin="{StaticResource Margin4}" Grid.Column="0"
VerticalAlignment="Center" Margin="{StaticResource Margin4}"
Text="{x:Static resx:ResUI.TbHeaderType}" /> VerticalAlignment="Center"
<ComboBox Text="{x:Static resx:ResUI.TbHeaderType}" />
x:Name="cmbHeaderTypeRaw" <ComboBox
Grid.Row="0" x:Name="cmbHeaderTypeRaw"
Grid.Column="1" Grid.Row="0"
Width="200" Grid.Column="1"
Margin="{StaticResource Margin4}" /> Width="200"
<TextBlock Margin="{StaticResource Margin4}" />
</Grid>
<Grid
x:Name="gridTransportRawHttp"
Grid.Row="1" Grid.Row="1"
Grid.Column="0" ColumnDefinitions="300,Auto"
Margin="{StaticResource Margin4}" IsVisible="False"
VerticalAlignment="Center" RowDefinitions="Auto,Auto">
Text="{x:Static resx:ResUI.TbRequestHost}" /> <TextBlock
<TextBox Grid.Row="0"
x:Name="txtRequestHostRaw" Grid.Column="0"
Grid.Row="1" Margin="{StaticResource Margin4}"
Grid.Column="1" VerticalAlignment="Center"
Width="400" Text="{x:Static resx:ResUI.TbRequestHost}" />
Margin="{StaticResource Margin4}" /> <TextBox
x:Name="txtRequestHostRaw"
Grid.Row="0"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbPath}" />
<TextBox
x:Name="txtPathRaw"
Grid.Row="1"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}" />
</Grid>
</Grid> </Grid>
<Grid <Grid

View file

@ -16,6 +16,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
Loaded += Window_Loaded; Loaded += Window_Loaded;
btnCancel.Click += (s, e) => Close(); btnCancel.Click += (s, e) => Close();
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged; cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
cmbHeaderTypeRaw.SelectionChanged += CmbHeaderTypeRaw_SelectionChanged;
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged; cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
btnGUID.Click += btnGUID_Click; btnGUID.Click += btnGUID_Click;
btnGUID5.Click += btnGUID_Click; btnGUID5.Click += btnGUID_Click;
@ -24,6 +25,16 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
cmbCoreType.ItemsSource = Global.CoreTypes.AppendEmpty(); cmbCoreType.ItemsSource = Global.CoreTypes.AppendEmpty();
cmbNetwork.ItemsSource = Global.Networks; cmbNetwork.ItemsSource = Global.Networks;
cmbHeaderTypeRaw.ItemsSource = new List<string> { Global.None, Global.RawHeaderHttp };
var kcpHeaderTypes = new List<string> { Global.None };
kcpHeaderTypes.AddRange(Global.KcpHeaderTypes);
cmbHeaderTypeKcp.ItemsSource = kcpHeaderTypes;
cmbHeaderTypeXhttp.ItemsSource = Global.XhttpMode;
cmbHeaderTypeGrpc.ItemsSource = new List<string> { Global.GrpcGunMode, Global.GrpcMultiMode };
cmbFingerprint.ItemsSource = Global.Fingerprints; cmbFingerprint.ItemsSource = Global.Fingerprints;
cmbFingerprint2.ItemsSource = Global.Fingerprints; cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure; cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
@ -202,7 +213,8 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
} }
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RawHeaderType, v => v.cmbHeaderTypeRaw.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RawHeaderType, v => v.cmbHeaderTypeRaw.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RawHost, v => v.txtRequestHostRaw.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Host, v => v.txtRequestHostRaw.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Path, v => v.txtPathRaw.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.KcpHeaderType, v => v.cmbHeaderTypeKcp.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.KcpHeaderType, v => v.cmbHeaderTypeKcp.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.KcpSeed, v => v.txtKcpSeed.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.KcpSeed, v => v.txtKcpSeed.Text).DisposeWith(disposables);
@ -269,8 +281,12 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
private void CmbNetwork_SelectionChanged(object? sender, SelectionChangedEventArgs e) private void CmbNetwork_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{ {
SetHeaderType(); SetTransportGridVisibility();
SetTips(); }
private void CmbHeaderTypeRaw_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
SetRawHttpFieldsVisibility();
} }
private void CmbStreamSecurity_SelectionChanged(object? sender, SelectionChangedEventArgs e) private void CmbStreamSecurity_SelectionChanged(object? sender, SelectionChangedEventArgs e)
@ -299,25 +315,6 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
txtId5.Text = Utils.GetGuid(); txtId5.Text = Utils.GetGuid();
} }
private void SetHeaderType()
{
cmbHeaderTypeRaw.ItemsSource = new List<string> { Global.None, Global.RawHeaderHttp };
var kcpHeaderTypes = new List<string> { Global.None };
kcpHeaderTypes.AddRange(Global.KcpHeaderTypes);
cmbHeaderTypeKcp.ItemsSource = kcpHeaderTypes;
cmbHeaderTypeXhttp.ItemsSource = Global.XhttpMode;
cmbHeaderTypeGrpc.ItemsSource = new List<string> { Global.GrpcGunMode, Global.GrpcMultiMode };
SetTransportGridVisibility();
}
private void SetTips()
{
SetTransportGridVisibility();
}
private void SetTransportGridVisibility() private void SetTransportGridVisibility()
{ {
var network = cmbNetwork.SelectedItem?.ToString(); var network = cmbNetwork.SelectedItem?.ToString();
@ -357,5 +354,21 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
gridTransportRaw.IsVisible = true; gridTransportRaw.IsVisible = true;
break; break;
} }
SetRawHttpFieldsVisibility();
}
private void SetRawHttpFieldsVisibility()
{
var network = cmbNetwork.SelectedItem?.ToString();
if (network.IsNullOrEmpty())
{
network = Global.DefaultNetwork;
}
var rawHeaderType = cmbHeaderTypeRaw.SelectedItem?.ToString();
var showRawHttpFields = network == nameof(ETransport.raw)
&& rawHeaderType == Global.RawHeaderHttp;
gridTransportRawHttp.IsVisible = showRawHttpFields;
} }
} }

View file

@ -768,7 +768,7 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,Auto" ColumnDefinitions="Auto,Auto,Auto"
DockPanel.Dock="Top" DockPanel.Dock="Top"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@ -851,6 +851,18 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbLegacyProtect}" />
<ToggleSwitch
x:Name="togEnableLegacyProtect"
Grid.Row="8"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</Grid> </Grid>
</TabItem> </TabItem>

View file

@ -116,6 +116,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);

View file

@ -944,42 +944,73 @@
<Grid Grid.Row="2"> <Grid Grid.Row="2">
<Grid x:Name="gridTransportRaw" Visibility="Collapsed"> <Grid x:Name="gridTransportRaw" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock
Grid.Row="0" <Grid Grid.Row="0">
Grid.Column="0" <Grid.ColumnDefinitions>
Margin="{StaticResource Margin4}" <ColumnDefinition Width="300" />
VerticalAlignment="Center" <ColumnDefinition Width="Auto" />
Style="{StaticResource ToolbarTextBlock}" </Grid.ColumnDefinitions>
Text="{x:Static resx:ResUI.TbHeaderType}" /> <TextBlock
<ComboBox Grid.Row="0"
x:Name="cmbHeaderTypeRaw" Grid.Column="0"
Grid.Row="0" Margin="{StaticResource Margin4}"
Grid.Column="1" VerticalAlignment="Center"
Width="200" Style="{StaticResource ToolbarTextBlock}"
Margin="{StaticResource Margin4}" Text="{x:Static resx:ResUI.TbHeaderType}" />
Style="{StaticResource DefComboBox}" /> <ComboBox
<TextBlock x:Name="cmbHeaderTypeRaw"
Grid.Row="0"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
</Grid>
<Grid
x:Name="gridTransportRawHttp"
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Visibility="Collapsed">
Margin="{StaticResource Margin4}" <Grid.ColumnDefinitions>
VerticalAlignment="Center" <ColumnDefinition Width="300" />
Style="{StaticResource ToolbarTextBlock}" <ColumnDefinition Width="Auto" />
Text="{x:Static resx:ResUI.TbRequestHost}" /> </Grid.ColumnDefinitions>
<TextBox <Grid.RowDefinitions>
x:Name="txtRequestHostRaw" <RowDefinition Height="Auto" />
Grid.Row="1" <RowDefinition Height="Auto" />
Grid.Column="1" </Grid.RowDefinitions>
Width="400" <TextBlock
Margin="{StaticResource Margin4}" Grid.Row="0"
Style="{StaticResource DefTextBox}" /> Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRequestHost}" />
<TextBox
x:Name="txtRequestHostRaw"
Grid.Row="0"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPath}" />
<TextBox
x:Name="txtPathRaw"
Grid.Row="1"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefTextBox}" />
</Grid>
</Grid> </Grid>
<Grid x:Name="gridTransportXhttp" Visibility="Collapsed"> <Grid x:Name="gridTransportXhttp" Visibility="Collapsed">

View file

@ -11,6 +11,7 @@ public partial class AddServerWindow
Owner = Application.Current.MainWindow; Owner = Application.Current.MainWindow;
Loaded += Window_Loaded; Loaded += Window_Loaded;
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged; cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
cmbHeaderTypeRaw.SelectionChanged += CmbHeaderTypeRaw_SelectionChanged;
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged; cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
btnGUID.Click += btnGUID_Click; btnGUID.Click += btnGUID_Click;
btnGUID5.Click += btnGUID_Click; btnGUID5.Click += btnGUID_Click;
@ -23,6 +24,16 @@ public partial class AddServerWindow
{ {
ViewModel.SelectedSource.Network = Global.DefaultNetwork; ViewModel.SelectedSource.Network = Global.DefaultNetwork;
} }
cmbHeaderTypeRaw.ItemsSource = new List<string> { Global.None, Global.RawHeaderHttp };
var kcpHeaderTypes = new List<string> { Global.None };
kcpHeaderTypes.AddRange(Global.KcpHeaderTypes);
cmbHeaderTypeKcp.ItemsSource = kcpHeaderTypes;
cmbHeaderTypeXhttp.ItemsSource = Global.XhttpMode;
cmbHeaderTypeGrpc.ItemsSource = new List<string> { Global.GrpcGunMode, Global.GrpcMultiMode };
cmbFingerprint.ItemsSource = Global.Fingerprints; cmbFingerprint.ItemsSource = Global.Fingerprints;
cmbFingerprint2.ItemsSource = Global.Fingerprints; cmbFingerprint2.ItemsSource = Global.Fingerprints;
cmbAllowInsecure.ItemsSource = Global.AllowInsecure; cmbAllowInsecure.ItemsSource = Global.AllowInsecure;
@ -200,7 +211,8 @@ public partial class AddServerWindow
} }
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RawHeaderType, v => v.cmbHeaderTypeRaw.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RawHeaderType, v => v.cmbHeaderTypeRaw.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RawHost, v => v.txtRequestHostRaw.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Host, v => v.txtRequestHostRaw.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Path, v => v.txtPathRaw.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.KcpHeaderType, v => v.cmbHeaderTypeKcp.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.KcpHeaderType, v => v.cmbHeaderTypeKcp.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.KcpSeed, v => v.txtKcpSeed.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.KcpSeed, v => v.txtKcpSeed.Text).DisposeWith(disposables);
@ -269,8 +281,12 @@ public partial class AddServerWindow
private void CmbNetwork_SelectionChanged(object sender, SelectionChangedEventArgs e) private void CmbNetwork_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
SetHeaderType(); SetTransportGridVisibility();
SetTips(); }
private void CmbHeaderTypeRaw_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SetRawHttpFieldsVisibility();
} }
private void CmbStreamSecurity_SelectionChanged(object sender, SelectionChangedEventArgs e) private void CmbStreamSecurity_SelectionChanged(object sender, SelectionChangedEventArgs e)
@ -299,25 +315,6 @@ public partial class AddServerWindow
txtId5.Text = Utils.GetGuid(); txtId5.Text = Utils.GetGuid();
} }
private void SetHeaderType()
{
cmbHeaderTypeRaw.ItemsSource = new List<string> { Global.None, Global.RawHeaderHttp };
var kcpHeaderTypes = new List<string> { Global.None };
kcpHeaderTypes.AddRange(Global.KcpHeaderTypes);
cmbHeaderTypeKcp.ItemsSource = kcpHeaderTypes;
cmbHeaderTypeXhttp.ItemsSource = Global.XhttpMode;
cmbHeaderTypeGrpc.ItemsSource = new List<string> { Global.GrpcGunMode, Global.GrpcMultiMode };
SetTransportGridVisibility();
}
private void SetTips()
{
SetTransportGridVisibility();
}
private void SetTransportGridVisibility() private void SetTransportGridVisibility()
{ {
var network = cmbNetwork.SelectedItem?.ToString(); var network = cmbNetwork.SelectedItem?.ToString();
@ -357,5 +354,23 @@ public partial class AddServerWindow
gridTransportRaw.Visibility = Visibility.Visible; gridTransportRaw.Visibility = Visibility.Visible;
break; break;
} }
SetRawHttpFieldsVisibility();
}
private void SetRawHttpFieldsVisibility()
{
var network = cmbNetwork.SelectedItem?.ToString();
if (network.IsNullOrEmpty())
{
network = Global.DefaultNetwork;
}
var rawHeaderType = cmbHeaderTypeRaw.SelectedItem?.ToString();
var showRawHttpFields = network == nameof(ETransport.raw)
&& rawHeaderType == Global.RawHeaderHttp;
gridTransportRawHttp.Visibility = showRawHttpFields
? Visibility.Visible
: Visibility.Collapsed;
} }
} }

View file

@ -1009,6 +1009,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@ -1105,6 +1106,20 @@
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbLegacyProtect}" />
<ToggleButton
x:Name="togEnableLegacyProtect"
Grid.Row="8"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
</Grid> </Grid>
</TabItem> </TabItem>

View file

@ -121,6 +121,7 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables);