Add NaiveProxy support

This commit is contained in:
DHR60 2026-02-18 22:28:43 +08:00
parent f11c2214be
commit 9824bb12ed
27 changed files with 518 additions and 36 deletions

View file

@ -13,6 +13,7 @@ public enum EConfigType
WireGuard = 9, WireGuard = 9,
HTTP = 10, HTTP = 10,
Anytls = 11, Anytls = 11,
Naive = 12,
PolicyGroup = 101, PolicyGroup = 101,
ProxyChain = 102, ProxyChain = 102,
} }

View file

@ -176,6 +176,10 @@ public class Global
public const string Hysteria2ProtocolShare = "hy2://"; public const string Hysteria2ProtocolShare = "hy2://";
public const string NaiveHttpsProtocolShare = "naive+https://";
public const string NaiveQuicProtocolShare = "naive+quic://";
public static readonly Dictionary<EConfigType, string> ProtocolShares = new() public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
{ {
{ EConfigType.VMess, "vmess://" }, { EConfigType.VMess, "vmess://" },
@ -186,7 +190,8 @@ public class Global
{ EConfigType.Hysteria2, "hysteria2://" }, { EConfigType.Hysteria2, "hysteria2://" },
{ EConfigType.TUIC, "tuic://" }, { EConfigType.TUIC, "tuic://" },
{ EConfigType.WireGuard, "wireguard://" }, { EConfigType.WireGuard, "wireguard://" },
{ EConfigType.Anytls, "anytls://" } { EConfigType.Anytls, "anytls://" },
{ EConfigType.Naive, "naive://" }
}; };
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new() public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
@ -200,7 +205,8 @@ public class Global
{ EConfigType.Hysteria2, "hysteria2" }, { EConfigType.Hysteria2, "hysteria2" },
{ EConfigType.TUIC, "tuic" }, { EConfigType.TUIC, "tuic" },
{ EConfigType.WireGuard, "wireguard" }, { EConfigType.WireGuard, "wireguard" },
{ EConfigType.Anytls, "anytls" } { EConfigType.Anytls, "anytls" },
{ EConfigType.Naive, "naive" }
}; };
public static readonly List<string> VmessSecurities = public static readonly List<string> VmessSecurities =
@ -325,6 +331,7 @@ public class Global
EConfigType.Hysteria2, EConfigType.Hysteria2,
EConfigType.TUIC, EConfigType.TUIC,
EConfigType.Anytls, EConfigType.Anytls,
EConfigType.Naive,
EConfigType.WireGuard, EConfigType.WireGuard,
EConfigType.SOCKS, EConfigType.SOCKS,
EConfigType.HTTP, EConfigType.HTTP,
@ -541,6 +548,14 @@ public class Global
"bbr" "bbr"
]; ];
public static readonly List<string> NaiveCongestionControls =
[
"bbr",
"bbr2",
"cubic",
"reno"
];
public static readonly List<string> allowSelectType = public static readonly List<string> allowSelectType =
[ [
"selector", "selector",

View file

@ -270,6 +270,7 @@ public static class ConfigHandler
EConfigType.TUIC => await AddTuicServer(config, item), EConfigType.TUIC => await AddTuicServer(config, item),
EConfigType.WireGuard => await AddWireguardServer(config, item), EConfigType.WireGuard => await AddWireguardServer(config, item),
EConfigType.Anytls => await AddAnytlsServer(config, item), EConfigType.Anytls => await AddAnytlsServer(config, item),
EConfigType.Naive => await AddNaiveServer(config, item),
_ => -1, _ => -1,
}; };
return ret; return ret;
@ -807,7 +808,7 @@ public static class ConfigHandler
} }
/// <summary> /// <summary>
/// Add or edit a Anytls server /// Add or edit an Anytls server
/// Validates and processes Anytls-specific settings /// Validates and processes Anytls-specific settings
/// </summary> /// </summary>
/// <param name="config">Current configuration</param> /// <param name="config">Current configuration</param>
@ -834,6 +835,35 @@ public static class ConfigHandler
return 0; return 0;
} }
/// <summary>
/// Add or edit a Naive server
/// Validates and processes Naive-specific settings
/// </summary>
/// <param name="config">Current configuration</param>
/// <param name="profileItem">Naive profile to add</param>
/// <param name="toFile">Whether to save to file</param>
/// <returns>0 if successful, -1 if failed</returns>
public static async Task<int> AddNaiveServer(Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.ConfigType = EConfigType.Naive;
profileItem.CoreType = ECoreType.sing_box;
profileItem.Address = profileItem.Address.TrimEx();
profileItem.Username = profileItem.Username.TrimEx();
profileItem.Password = profileItem.Password.TrimEx();
profileItem.Network = profileItem.Network == "quic" ? "quic" : string.Empty;
if (profileItem.StreamSecurity.IsNullOrEmpty())
{
profileItem.StreamSecurity = Global.StreamSecurity;
}
if (profileItem.Password.IsNullOrEmpty())
{
return -1;
}
await AddServerCommon(config, profileItem, toFile);
return 0;
}
/// <summary> /// <summary>
/// Sort the server list by the specified column /// Sort the server list by the specified column
/// Updates the sort order in the profile extension data /// Updates the sort order in the profile extension data
@ -1391,6 +1421,7 @@ public static class ConfigHandler
EConfigType.TUIC => await AddTuicServer(config, profileItem, false), EConfigType.TUIC => await AddTuicServer(config, profileItem, false),
EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false), EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false),
EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false), EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false),
EConfigType.Naive => await AddNaiveServer(config, profileItem, false),
_ => -1, _ => -1,
}; };

View file

@ -19,6 +19,7 @@ public class FmtHandler
EConfigType.TUIC => TuicFmt.ToUri(item), EConfigType.TUIC => TuicFmt.ToUri(item),
EConfigType.WireGuard => WireguardFmt.ToUri(item), EConfigType.WireGuard => WireguardFmt.ToUri(item),
EConfigType.Anytls => AnytlsFmt.ToUri(item), EConfigType.Anytls => AnytlsFmt.ToUri(item),
EConfigType.Naive => NaiveFmt.ToUri(item),
_ => null, _ => null,
}; };
@ -80,6 +81,12 @@ public class FmtHandler
{ {
return AnytlsFmt.Resolve(str, out msg); return AnytlsFmt.Resolve(str, out msg);
} }
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Naive])
|| str.StartsWith(Global.NaiveHttpsProtocolShare)
|| str.StartsWith(Global.NaiveQuicProtocolShare))
{
return NaiveFmt.Resolve(str, out msg);
}
else else
{ {
msg = ResUI.NonvmessOrssProtocol; msg = ResUI.NonvmessOrssProtocol;

View file

@ -0,0 +1,85 @@
namespace ServiceLib.Handler.Fmt;
public class NaiveFmt : BaseFmt
{
public static ProfileItem? Resolve(string str, out string msg)
{
msg = ResUI.ConfigurationFormatIncorrect;
var parsedUrl = Utils.TryUri(str);
if (parsedUrl == null)
{
return null;
}
ProfileItem item = new()
{
ConfigType = EConfigType.Naive,
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
Address = parsedUrl.IdnHost,
Port = parsedUrl.Port,
};
if (parsedUrl.Scheme.Contains("quic"))
{
item.Network = "quic";
}
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
if (rawUserInfo.Contains(':'))
{
var split = rawUserInfo.Split(':', 2);
item.Username = split[0];
item.Password = split[1];
}
else
{
item.Password = rawUserInfo;
}
var query = Utils.ParseQueryString(parsedUrl.Query);
ResolveUriQuery(query, ref item);
var insecureConcurrency = int.TryParse(GetQueryValue(query, "insecure-concurrency"), out var ic) ? ic : 0;
if (insecureConcurrency > 0)
{
item.SetProtocolExtra(item.GetProtocolExtra() with
{
InsecureConcurrency = insecureConcurrency,
});
}
return item;
}
public static string? ToUri(ProfileItem? item)
{
if (item == null)
{
return null;
}
var remark = string.Empty;
if (item.Remarks.IsNotEmpty())
{
remark = "#" + Utils.UrlEncode(item.Remarks);
}
var userInfo = item.Username.IsNotEmpty() ? $"{Utils.UrlEncode(item.Username)}:{Utils.UrlEncode(item.Password)}" : Utils.UrlEncode(item.Password);
var dicQuery = new Dictionary<string, string>();
ToUriQuery(item, Global.None, ref dicQuery);
if (item.GetProtocolExtra().InsecureConcurrency > 0)
{
dicQuery.Add("insecure-concurrency", item.GetProtocolExtra()?.InsecureConcurrency.ToString());
}
var query = dicQuery.Count > 0
? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()))
: string.Empty;
var url = $"{userInfo}@{GetIpv6(item.Address)}:{item.Port}";
if (item.Network == "quic")
{
return $"{Global.NaiveQuicProtocolShare}{url}{query}{remark}";
}
else
{
return $"{Global.NaiveHttpsProtocolShare}{url}{query}{remark}";
}
}
}

View file

@ -243,6 +243,11 @@ public class ActionPrecheckManager
return string.Format(ResUI.CoreNotSupportNetwork, nameof(ECoreType.sing_box), net); return string.Format(ResUI.CoreNotSupportNetwork, nameof(ECoreType.sing_box), net);
} }
if (configType == EConfigType.Naive && net == "quic")
{
return null;
}
// sing-box does not support non-tcp transports for protocols other than vmess/trojan/vless/shadowsocks // sing-box does not support non-tcp transports for protocols other than vmess/trojan/vless/shadowsocks
if (!SingboxTransportSupportedProtocols.Contains(configType) && net != nameof(ETransport.tcp)) if (!SingboxTransportSupportedProtocols.Contains(configType) && net != nameof(ETransport.tcp))
{ {

View file

@ -32,6 +32,9 @@ public record ProtocolExtraItem
public string? Ports { get; init; } public string? Ports { get; init; }
public string? HopInterval { get; init; } public string? HopInterval { get; init; }
// naiveproxy
public int? InsecureConcurrency { get; init; }
// group profile // group profile
public string? GroupType { get; init; } public string? GroupType { get; init; }
public string? ChildItems { get; init; } public string? ChildItems { get; init; }

View file

@ -133,11 +133,14 @@ public class Outbound4Sbox : BaseServer4Sbox
public int? recv_window_conn { get; set; } public int? recv_window_conn { get; set; }
public int? recv_window { get; set; } public int? recv_window { get; set; }
public bool? disable_mtu_discovery { get; set; } public bool? disable_mtu_discovery { get; set; }
public int? insecure_concurrency { get; set; }
public bool? udp_over_tcp { get; set; } public bool? udp_over_tcp { get; set; }
public string? method { get; set; } public string? method { get; set; }
public string? username { get; set; } public string? username { get; set; }
public string? password { get; set; } public string? password { get; set; }
public string? congestion_control { get; set; } public string? congestion_control { get; set; }
public bool? quic { get; set; }
public string? quic_congestion_control { get; set; }
public string? version { get; set; } public string? version { get; set; }
public string? network { get; set; } public string? network { get; set; }
public string? packet_encoding { get; set; } public string? packet_encoding { get; set; }

View file

@ -780,6 +780,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Add [NaïveProxy] 的本地化字符串。
/// </summary>
public static string menuAddNaiveServer {
get {
return ResourceManager.GetString("menuAddNaiveServer", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Add Policy Group 的本地化字符串。 /// 查找类似 Add Policy Group 的本地化字符串。
/// </summary> /// </summary>
@ -3060,6 +3069,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Insecure Concurrency 的本地化字符串。
/// </summary>
public static string TbInsecureConcurrency {
get {
return ResourceManager.GetString("TbInsecureConcurrency", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Most Stable 的本地化字符串。 /// 查找类似 Most Stable 的本地化字符串。
/// </summary> /// </summary>
@ -4464,6 +4482,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Username 的本地化字符串。
/// </summary>
public static string TbUsername {
get {
return ResourceManager.GetString("TbUsername", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Validate Regional Domain IPs 的本地化字符串。 /// 查找类似 Validate Regional Domain IPs 的本地化字符串。
/// </summary> /// </summary>

View file

@ -1671,4 +1671,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>
<data name="menuAddNaiveServer" xml:space="preserve">
<value>Add NaïveProxy</value>
</data>
<data name="TbInsecureConcurrency" xml:space="preserve">
<value>Insecure Concurrency</value>
</data>
<data name="TbUsername" xml:space="preserve">
<value>Username</value>
</data>
</root> </root>

View file

@ -1668,4 +1668,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>
<data name="menuAddNaiveServer" xml:space="preserve">
<value>Ajouter [NaïveProxy]</value>
</data>
<data name="TbInsecureConcurrency" xml:space="preserve">
<value>Insecure Concurrency</value>
</data>
<data name="TbUsername" xml:space="preserve">
<value>Username</value>
</data>
</root> </root>

View file

@ -1671,4 +1671,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>
<data name="menuAddNaiveServer" xml:space="preserve">
<value>[NaïveProxy] konfiguráció hozzáadása</value>
</data>
<data name="TbInsecureConcurrency" xml:space="preserve">
<value>Insecure Concurrency</value>
</data>
<data name="TbUsername" xml:space="preserve">
<value>Username</value>
</data>
</root> </root>

View file

@ -514,19 +514,19 @@
<value>Add a custom configuration</value> <value>Add a custom configuration</value>
</data> </data>
<data name="menuAddShadowsocksServer" xml:space="preserve"> <data name="menuAddShadowsocksServer" xml:space="preserve">
<value>Add [Shadowsocks] </value> <value>Add [Shadowsocks]</value>
</data> </data>
<data name="menuAddSocksServer" xml:space="preserve"> <data name="menuAddSocksServer" xml:space="preserve">
<value>Add [SOCKS] </value> <value>Add [SOCKS]</value>
</data> </data>
<data name="menuAddTrojanServer" xml:space="preserve"> <data name="menuAddTrojanServer" xml:space="preserve">
<value>Add [Trojan] </value> <value>Add [Trojan]</value>
</data> </data>
<data name="menuAddVlessServer" xml:space="preserve"> <data name="menuAddVlessServer" xml:space="preserve">
<value>Add [VLESS] </value> <value>Add [VLESS]</value>
</data> </data>
<data name="menuAddVmessServer" xml:space="preserve"> <data name="menuAddVmessServer" xml:space="preserve">
<value>Add [VMess] </value> <value>Add [VMess]</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>Select all</value> <value>Select all</value>
@ -1036,7 +1036,7 @@
<value>Domain</value> <value>Domain</value>
</data> </data>
<data name="menuAddHysteria2Server" xml:space="preserve"> <data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] </value> <value>Add [Hysteria2]</value>
</data> </data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve"> <data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Down)</value> <value>Hysteria Max bandwidth (Up/Down)</value>
@ -1045,7 +1045,7 @@
<value>Use System Hosts</value> <value>Use System Hosts</value>
</data> </data>
<data name="menuAddTuicServer" xml:space="preserve"> <data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] </value> <value>Add [TUIC]</value>
</data> </data>
<data name="TbHeaderType8" xml:space="preserve"> <data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value> <value>Congestion control</value>
@ -1075,7 +1075,7 @@
<value>Enable IPv6 Address</value> <value>Enable IPv6 Address</value>
</data> </data>
<data name="menuAddWireguardServer" xml:space="preserve"> <data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [WireGuard] </value> <value>Add [WireGuard]</value>
</data> </data>
<data name="TbPrivateKey" xml:space="preserve"> <data name="TbPrivateKey" xml:space="preserve">
<value>Private Key</value> <value>Private Key</value>
@ -1516,13 +1516,13 @@
<value>Policy Group Type</value> <value>Policy Group Type</value>
</data> </data>
<data name="menuAddPolicyGroupServer" xml:space="preserve"> <data name="menuAddPolicyGroupServer" xml:space="preserve">
<value>Add Policy Group </value> <value>Add Policy Group</value>
</data> </data>
<data name="menuAddProxyChainServer" xml:space="preserve"> <data name="menuAddProxyChainServer" xml:space="preserve">
<value>Add Proxy Chain</value> <value>Add Proxy Chain</value>
</data> </data>
<data name="menuAddChildServer" xml:space="preserve"> <data name="menuAddChildServer" xml:space="preserve">
<value>Add Child </value> <value>Add Child</value>
</data> </data>
<data name="menuRemoveChildServer" xml:space="preserve"> <data name="menuRemoveChildServer" xml:space="preserve">
<value>Remove Child </value> <value>Remove Child </value>
@ -1671,4 +1671,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>
<data name="menuAddNaiveServer" xml:space="preserve">
<value>Add [NaïveProxy]</value>
</data>
<data name="TbInsecureConcurrency" xml:space="preserve">
<value>Insecure Concurrency</value>
</data>
<data name="TbUsername" xml:space="preserve">
<value>Username</value>
</data>
</root> </root>

View file

@ -1671,4 +1671,13 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>
<data name="menuAddNaiveServer" xml:space="preserve">
<value>Добавить сервер [NaïveProxy]</value>
</data>
<data name="TbInsecureConcurrency" xml:space="preserve">
<value>Insecure Concurrency</value>
</data>
<data name="TbUsername" xml:space="preserve">
<value>Username</value>
</data>
</root> </root>

View file

@ -517,16 +517,16 @@
<value>添加 [Shadowsocks]</value> <value>添加 [Shadowsocks]</value>
</data> </data>
<data name="menuAddSocksServer" xml:space="preserve"> <data name="menuAddSocksServer" xml:space="preserve">
<value>添加 [SOCKS] </value> <value>添加 [SOCKS]</value>
</data> </data>
<data name="menuAddTrojanServer" xml:space="preserve"> <data name="menuAddTrojanServer" xml:space="preserve">
<value>添加 [Trojan] </value> <value>添加 [Trojan]</value>
</data> </data>
<data name="menuAddVlessServer" xml:space="preserve"> <data name="menuAddVlessServer" xml:space="preserve">
<value>添加 [VLESS] </value> <value>添加 [VLESS]</value>
</data> </data>
<data name="menuAddVmessServer" xml:space="preserve"> <data name="menuAddVmessServer" xml:space="preserve">
<value>添加 [VMess] </value> <value>添加 [VMess]</value>
</data> </data>
<data name="menuSelectAll" xml:space="preserve"> <data name="menuSelectAll" xml:space="preserve">
<value>全选</value> <value>全选</value>
@ -1033,7 +1033,7 @@
<value>Domain</value> <value>Domain</value>
</data> </data>
<data name="menuAddHysteria2Server" xml:space="preserve"> <data name="menuAddHysteria2Server" xml:space="preserve">
<value>添加 [Hysteria2] </value> <value>添加 [Hysteria2]</value>
</data> </data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve"> <data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria 最大带宽 (Up/Dw)</value> <value>Hysteria 最大带宽 (Up/Dw)</value>
@ -1042,7 +1042,7 @@
<value>使用系统 hosts</value> <value>使用系统 hosts</value>
</data> </data>
<data name="menuAddTuicServer" xml:space="preserve"> <data name="menuAddTuicServer" xml:space="preserve">
<value>添加 [TUIC] </value> <value>添加 [TUIC]</value>
</data> </data>
<data name="TbHeaderType8" xml:space="preserve"> <data name="TbHeaderType8" xml:space="preserve">
<value>拥塞控制算法</value> <value>拥塞控制算法</value>
@ -1072,7 +1072,7 @@
<value>启用 IPv6</value> <value>启用 IPv6</value>
</data> </data>
<data name="menuAddWireguardServer" xml:space="preserve"> <data name="menuAddWireguardServer" xml:space="preserve">
<value>添加 [WireGuard] </value> <value>添加 [WireGuard]</value>
</data> </data>
<data name="TbPrivateKey" xml:space="preserve"> <data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value> <value>PrivateKey</value>
@ -1105,7 +1105,7 @@
<value>*grpc Authority</value> <value>*grpc Authority</value>
</data> </data>
<data name="menuAddHttpServer" xml:space="preserve"> <data name="menuAddHttpServer" xml:space="preserve">
<value>添加 [HTTP] </value> <value>添加 [HTTP]</value>
</data> </data>
<data name="TbSettingsEnableFragment" xml:space="preserve"> <data name="TbSettingsEnableFragment" xml:space="preserve">
<value>启用分片 (Fragment)</value> <value>启用分片 (Fragment)</value>
@ -1402,7 +1402,7 @@
<value>Mldsa65Verify</value> <value>Mldsa65Verify</value>
</data> </data>
<data name="menuAddAnytlsServer" xml:space="preserve"> <data name="menuAddAnytlsServer" xml:space="preserve">
<value>添加 [Anytls] </value> <value>添加 [Anytls]</value>
</data> </data>
<data name="TbRemoteDNS" xml:space="preserve"> <data name="TbRemoteDNS" xml:space="preserve">
<value>远程 DNS</value> <value>远程 DNS</value>
@ -1668,4 +1668,13 @@
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>
<data name="menuAddNaiveServer" xml:space="preserve">
<value>添加 [NaïveProxy]</value>
</data>
<data name="TbInsecureConcurrency" xml:space="preserve">
<value>不安全并发</value>
</data>
<data name="TbUsername" xml:space="preserve">
<value>用户名</value>
</data>
</root> </root>

View file

@ -1668,4 +1668,13 @@
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
</data> </data>
<data name="menuAddNaiveServer" xml:space="preserve">
<value>新增 [NaïveProxy] 節點</value>
</data>
<data name="TbInsecureConcurrency" xml:space="preserve">
<value>Insecure Concurrency</value>
</data>
<data name="TbUsername" xml:space="preserve">
<value>Username</value>
</data>
</root> </root>

View file

@ -278,6 +278,22 @@ public partial class CoreConfigSingboxService
outbound.password = _node.Password; outbound.password = _node.Password;
break; break;
} }
case EConfigType.Naive:
{
outbound.username = _node.Username;
outbound.password = _node.Password;
if (outbound.network == "quic")
{
outbound.quic = true;
outbound.quic_congestion_control = protocolExtra.CongestionControl.NullIfEmpty();
}
if (protocolExtra.InsecureConcurrency > 0)
{
outbound.insecure_concurrency = protocolExtra.InsecureConcurrency;
}
outbound.udp_over_tcp = protocolExtra.Uot == true ? true : null;
break;
}
} }
FillOutboundTls(outbound); FillOutboundTls(outbound);

View file

@ -67,6 +67,9 @@ public class AddServerViewModel : MyReactiveObject
[Reactive] [Reactive]
public string CongestionControl { get; set; } public string CongestionControl { get; set; }
[Reactive]
public int InsecureConcurrency { get; set; }
public ReactiveCommand<Unit, Unit> FetchCertCmd { get; } public ReactiveCommand<Unit, Unit> FetchCertCmd { get; }
public ReactiveCommand<Unit, Unit> FetchCertChainCmd { get; } public ReactiveCommand<Unit, Unit> FetchCertChainCmd { get; }
public ReactiveCommand<Unit, Unit> SaveCmd { get; } public ReactiveCommand<Unit, Unit> SaveCmd { get; }
@ -131,6 +134,7 @@ public class AddServerViewModel : MyReactiveObject
WgMtu = protocolExtra?.WgMtu ?? 1280; WgMtu = protocolExtra?.WgMtu ?? 1280;
Uot = protocolExtra?.Uot ?? false; Uot = protocolExtra?.Uot ?? false;
CongestionControl = protocolExtra?.CongestionControl ?? string.Empty; CongestionControl = protocolExtra?.CongestionControl ?? string.Empty;
InsecureConcurrency = protocolExtra?.InsecureConcurrency ?? 0;
} }
private async Task SaveServerAsync() private async Task SaveServerAsync()
@ -195,6 +199,7 @@ public class AddServerViewModel : MyReactiveObject
WgMtu = WgMtu >= 576 ? WgMtu : null, WgMtu = WgMtu >= 576 ? WgMtu : null,
Uot = Uot ? true : null, Uot = Uot ? true : null,
CongestionControl = CongestionControl.NullIfEmpty(), CongestionControl = CongestionControl.NullIfEmpty(),
InsecureConcurrency = InsecureConcurrency > 0 ? InsecureConcurrency : null
}); });
if (await ConfigHandler.AddServer(_config, SelectedSource) == 0) if (await ConfigHandler.AddServer(_config, SelectedSource) == 0)

View file

@ -18,6 +18,7 @@ public class MainWindowViewModel : MyReactiveObject
public ReactiveCommand<Unit, Unit> AddTuicServerCmd { get; } public ReactiveCommand<Unit, Unit> AddTuicServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; } public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; } public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddNaiveServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; } public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddPolicyGroupServerCmd { get; } public ReactiveCommand<Unit, Unit> AddPolicyGroupServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddProxyChainServerCmd { get; } public ReactiveCommand<Unit, Unit> AddProxyChainServerCmd { get; }
@ -117,6 +118,10 @@ public class MainWindowViewModel : MyReactiveObject
{ {
await AddServerAsync(EConfigType.Anytls); await AddServerAsync(EConfigType.Anytls);
}); });
AddNaiveServerCmd = ReactiveCommand.CreateFromTask(async () =>
{
await AddServerAsync(EConfigType.Naive);
});
AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () => AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
await AddServerAsync(EConfigType.Custom); await AddServerAsync(EConfigType.Custom);

View file

@ -593,12 +593,84 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbId3}" /> Text="{x:Static resx:ResUI.TbId3}" />
<TextBox <TextBox
x:Name="txtId10" x:Name="txtId11"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}" />
</Grid> </Grid>
<Grid
x:Name="gridNaive"
Grid.Row="2"
ColumnDefinitions="300,Auto"
IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbUsername}" />
<TextBox
x:Name="txtId12"
Grid.Row="1"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbId3}" />
<TextBox
x:Name="txtSecurity12"
Grid.Row="2"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbInsecureConcurrency}" />
<TextBox
x:Name="txtInsecureConcurrency12"
Grid.Row="3"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbHeaderType8}" />
<ComboBox
x:Name="cmbHeaderType12"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbUot}" />
<ToggleSwitch
x:Name="togUotEnabled12"
Grid.Row="5"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</Grid>
<Separator <Separator
x:Name="sepa2" x:Name="sepa2"

View file

@ -94,10 +94,24 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.Anytls: case EConfigType.Anytls:
gridAnytls.IsVisible = true; gridAnytls.IsVisible = true;
sepa2.IsVisible = false;
gridTransport.IsVisible = false;
lstStreamSecurity.Add(Global.StreamSecurityReality); lstStreamSecurity.Add(Global.StreamSecurityReality);
cmbCoreType.IsEnabled = false; cmbCoreType.IsEnabled = false;
gridFinalmask.IsVisible = false; gridFinalmask.IsVisible = false;
break; break;
case EConfigType.Naive:
gridNaive.IsVisible = true;
cmbCoreType.IsEnabled = false;
gridFinalmask.IsVisible = false;
cmbFingerprint.IsEnabled = false;
cmbFingerprint.SelectedValue = string.Empty;
cmbAllowInsecure.IsEnabled = false;
cmbAllowInsecure.SelectedValue = string.Empty;
cmbHeaderType12.ItemsSource = Global.NaiveCongestionControls;
break;
} }
cmbStreamSecurity.ItemsSource = lstStreamSecurity; cmbStreamSecurity.ItemsSource = lstStreamSecurity;
@ -169,7 +183,15 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
break; break;
case EConfigType.Anytls: case EConfigType.Anytls:
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId10.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId11.Text).DisposeWith(disposables);
break;
case EConfigType.Naive:
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType12.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables);
break; break;
} }
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);

View file

@ -50,6 +50,7 @@
<Separator /> <Separator />
<MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" /> <MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" />
<MenuItem x:Name="menuAddAnytlsServer" Header="{x:Static resx:ResUI.menuAddAnytlsServer}" /> <MenuItem x:Name="menuAddAnytlsServer" Header="{x:Static resx:ResUI.menuAddAnytlsServer}" />
<MenuItem x:Name="menuAddNaiveServer" Header="{x:Static resx:ResUI.menuAddNaiveServer}" />
</MenuItem> </MenuItem>
<MenuItem Header="{x:Static resx:ResUI.menuSubscription}"> <MenuItem Header="{x:Static resx:ResUI.menuSubscription}">

View file

@ -72,6 +72,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables);

View file

@ -786,13 +786,106 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbId3}" /> Text="{x:Static resx:ResUI.TbId3}" />
<TextBox <TextBox
x:Name="txtId10" x:Name="txtId11"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
</Grid> </Grid>
<Grid
x:Name="gridNaive"
Grid.Row="2"
Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbUsername}" />
<TextBox
x:Name="txtId12"
Grid.Row="1"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbId3}" />
<TextBox
x:Name="txtSecurity12"
Grid.Row="2"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbInsecureConcurrency}" />
<TextBox
x:Name="txtInsecureConcurrency12"
Grid.Row="3"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbHeaderType8}" />
<ComboBox
x:Name="cmbHeaderType12"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbUot}" />
<ToggleButton
x:Name="togUotEnabled12"
Grid.Row="5"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</Grid>
<Separator <Separator
x:Name="sepa2" x:Name="sepa2"

View file

@ -89,10 +89,24 @@ public partial class AddServerWindow
case EConfigType.Anytls: case EConfigType.Anytls:
gridAnytls.Visibility = Visibility.Visible; gridAnytls.Visibility = Visibility.Visible;
sepa2.Visibility = Visibility.Collapsed;
gridTransport.Visibility = Visibility.Collapsed;
cmbCoreType.IsEnabled = false; cmbCoreType.IsEnabled = false;
lstStreamSecurity.Add(Global.StreamSecurityReality); lstStreamSecurity.Add(Global.StreamSecurityReality);
gridFinalmask.Visibility = Visibility.Collapsed; gridFinalmask.Visibility = Visibility.Collapsed;
break; break;
case EConfigType.Naive:
gridNaive.Visibility = Visibility.Visible;
cmbCoreType.IsEnabled = false;
gridFinalmask.Visibility = Visibility.Collapsed;
cmbFingerprint.IsEnabled = false;
cmbFingerprint.Text = string.Empty;
cmbAllowInsecure.IsEnabled = false;
cmbAllowInsecure.Text = string.Empty;
cmbHeaderType12.ItemsSource = Global.NaiveCongestionControls;
break;
} }
cmbStreamSecurity.ItemsSource = lstStreamSecurity; cmbStreamSecurity.ItemsSource = lstStreamSecurity;
@ -164,7 +178,15 @@ public partial class AddServerWindow
break; break;
case EConfigType.Anytls: case EConfigType.Anytls:
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId10.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId11.Text).DisposeWith(disposables);
break;
case EConfigType.Naive:
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables);
break; break;
} }
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);

View file

@ -124,6 +124,10 @@
x:Name="menuAddAnytlsServer" x:Name="menuAddAnytlsServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddAnytlsServer}" /> Header="{x:Static resx:ResUI.menuAddAnytlsServer}" />
<MenuItem
x:Name="menuAddNaiveServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddNaiveServer}" />
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />

View file

@ -71,6 +71,7 @@ public partial class MainWindow
this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables);