Compare commits

...

8 commits

Author SHA1 Message Date
DHR60
a74dc383b7
Merge 5414bae069 into 74e5ead1ed 2026-03-22 14:41:56 +08:00
tt2563
74e5ead1ed
Update Traditional Chinese translation (#8973)
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
* Update Traditional Chinese translation

* Update confirmation message for removing nodes
2026-03-22 14:33:47 +08:00
DHR60
2caec729fc
Protect xhttp split address (#8970)
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-21 19:59:52 +08:00
DHR60
194c240243
Add ICMP routing (#8894) 2026-03-21 19:55:34 +08:00
DHR60
db9fe9c5ea
Fix (#8972) 2026-03-21 19:47:04 +08:00
DHR60
5414bae069 Sync 2026-03-09 22:20:05 +08:00
DHR60
4a10a862eb Fix 2026-03-09 22:17:47 +08:00
DHR60
ecf8b8f939 Support new hysteria2 stream settings 2026-03-08 16:36:55 +08:00
29 changed files with 266 additions and 89 deletions

View file

@ -675,5 +675,14 @@ public class Global
"" ""
]; ];
public static readonly List<string> TunIcmpRoutingPolicies =
[
"rule",
"direct",
"unreachable",
"drop",
"reply",
];
#endregion const #endregion const
} }

View file

@ -322,6 +322,7 @@ public class CoreConfigContextBuilder
context.ProtectDomainList.Add(address); context.ProtectDomainList.Add(address);
} }
// ech query server name protect
if (!node.EchConfigList.IsNullOrEmpty()) if (!node.EchConfigList.IsNullOrEmpty())
{ {
var echQuerySni = node.Sni; var echQuerySni = node.Sni;
@ -338,6 +339,20 @@ public class CoreConfigContextBuilder
} }
} }
// xhttp downloadSettings address protect
if (!string.IsNullOrEmpty(node.Extra)
&& JsonUtils.ParseJson(node.Extra) is JsonObject extra
&& extra.TryGetPropertyValue("downloadSettings", out var dsNode)
&& dsNode is JsonObject downloadSettings
&& downloadSettings.TryGetPropertyValue("address", out var dAddrNode)
&& dAddrNode is JsonValue dAddrValue
&& dAddrValue.TryGetValue(out string? dAddr)
&& !string.IsNullOrEmpty(dAddr)
&& Utils.IsDomain(dAddr))
{
context.ProtectDomainList.Add(dAddr);
}
return nodeValidatorResult; return nodeValidatorResult;
} }

View file

@ -152,12 +152,6 @@ public class NodeValidator
private static string? ValidateSingboxTransport(EConfigType configType, string net) private static string? ValidateSingboxTransport(EConfigType configType, string net)
{ {
// Naive support tcp and quic transports
if (configType == EConfigType.Naive && net == "quic")
{
return null;
}
// sing-box does not support xhttp / kcp transports // sing-box does not support xhttp / kcp transports
if (SingboxUnsupportedTransports.Contains(net)) if (SingboxUnsupportedTransports.Contains(net))
{ {

View file

@ -91,6 +91,7 @@ public static class ConfigHandler
{ {
EnableTun = false, EnableTun = false,
Mtu = 9000, Mtu = 9000,
IcmpRouting = Global.TunIcmpRoutingPolicies.First(),
}; };
config.GuiItem ??= new(); config.GuiItem ??= new();
config.MsgUIItem ??= new(); config.MsgUIItem ??= new();
@ -848,7 +849,8 @@ public static class ConfigHandler
profileItem.Address = profileItem.Address.TrimEx(); profileItem.Address = profileItem.Address.TrimEx();
profileItem.Username = profileItem.Username.TrimEx(); profileItem.Username = profileItem.Username.TrimEx();
profileItem.Password = profileItem.Password.TrimEx(); profileItem.Password = profileItem.Password.TrimEx();
profileItem.Network = profileItem.Network == "quic" ? "quic" : string.Empty; profileItem.Alpn = string.Empty;
profileItem.Network = string.Empty;
if (profileItem.StreamSecurity.IsNullOrEmpty()) if (profileItem.StreamSecurity.IsNullOrEmpty())
{ {
profileItem.StreamSecurity = Global.StreamSecurity; profileItem.StreamSecurity = Global.StreamSecurity;

View file

@ -19,9 +19,13 @@ public class NaiveFmt : BaseFmt
Address = parsedUrl.IdnHost, Address = parsedUrl.IdnHost,
Port = parsedUrl.Port, Port = parsedUrl.Port,
}; };
var protocolExtra = item.GetProtocolExtra();
if (parsedUrl.Scheme.Contains("quic")) if (parsedUrl.Scheme.Contains("quic"))
{ {
item.Network = "quic"; protocolExtra = protocolExtra with
{
NaiveQuic = true,
};
} }
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo); var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
if (rawUserInfo.Contains(':')) if (rawUserInfo.Contains(':'))
@ -40,12 +44,13 @@ public class NaiveFmt : BaseFmt
var insecureConcurrency = int.TryParse(GetQueryValue(query, "insecure-concurrency"), out var ic) ? ic : 0; var insecureConcurrency = int.TryParse(GetQueryValue(query, "insecure-concurrency"), out var ic) ? ic : 0;
if (insecureConcurrency > 0) if (insecureConcurrency > 0)
{ {
item.SetProtocolExtra(item.GetProtocolExtra() with protocolExtra = protocolExtra with
{ {
InsecureConcurrency = insecureConcurrency, InsecureConcurrency = insecureConcurrency,
}); };
} }
item.SetProtocolExtra(protocolExtra);
return item; return item;
} }
@ -63,9 +68,10 @@ public class NaiveFmt : BaseFmt
var userInfo = item.Username.IsNotEmpty() ? $"{Utils.UrlEncode(item.Username)}:{Utils.UrlEncode(item.Password)}" : Utils.UrlEncode(item.Password); var userInfo = item.Username.IsNotEmpty() ? $"{Utils.UrlEncode(item.Username)}:{Utils.UrlEncode(item.Password)}" : Utils.UrlEncode(item.Password);
var dicQuery = new Dictionary<string, string>(); var dicQuery = new Dictionary<string, string>();
ToUriQuery(item, Global.None, ref dicQuery); ToUriQuery(item, Global.None, ref dicQuery);
if (item.GetProtocolExtra().InsecureConcurrency > 0) var protocolExtra = item.GetProtocolExtra();
if (protocolExtra.InsecureConcurrency > 0)
{ {
dicQuery.Add("insecure-concurrency", item.GetProtocolExtra()?.InsecureConcurrency.ToString()); dicQuery.Add("insecure-concurrency", protocolExtra?.InsecureConcurrency.ToString());
} }
var query = dicQuery.Count > 0 var query = dicQuery.Count > 0
@ -73,7 +79,7 @@ public class NaiveFmt : BaseFmt
: string.Empty; : string.Empty;
var url = $"{userInfo}@{GetIpv6(item.Address)}:{item.Port}"; var url = $"{userInfo}@{GetIpv6(item.Address)}:{item.Port}";
if (item.Network == "quic") if (protocolExtra.NaiveQuic == true)
{ {
return $"{Global.NaiveQuicProtocolShare}{url}{query}{remark}"; return $"{Global.NaiveQuicProtocolShare}{url}{query}{remark}";
} }

View file

@ -144,6 +144,7 @@ public class TunModeItem
public string Stack { get; set; } public string Stack { get; set; }
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; }
} }
[Serializable] [Serializable]

View file

@ -34,6 +34,7 @@ public record ProtocolExtraItem
// naiveproxy // naiveproxy
public int? InsecureConcurrency { get; init; } public int? InsecureConcurrency { get; init; }
public bool? NaiveQuic { get; init; }
// group profile // group profile
public string? GroupType { get; init; } public string? GroupType { get; init; }

View file

@ -337,7 +337,7 @@ public class StreamSettings4Ray
public HysteriaSettings4Ray? hysteriaSettings { get; set; } public HysteriaSettings4Ray? hysteriaSettings { get; set; }
public Finalmask4Ray? finalmask { get; set; } public object? finalmask { get; set; }
public Sockopt4Ray? sockopt { get; set; } public Sockopt4Ray? sockopt { get; set; }
} }
@ -462,27 +462,24 @@ public class HysteriaSettings4Ray
{ {
public int version { get; set; } public int version { get; set; }
public string? auth { get; set; } public string? auth { get; set; }
public string? up { get; set; }
public string? down { get; set; }
public HysteriaUdpHop4Ray? udphop { get; set; }
} }
public class HysteriaUdpHop4Ray public class UdpHop4Ray
{ {
public string? port { get; set; } public string? ports { get; set; }
public string? interval { get; set; } public string? interval { get; set; }
} }
public class Finalmask4Ray public class Finalmask4Ray
{ {
public List<Mask4Ray>? tcp { get; set; }
public List<Mask4Ray>? udp { get; set; } public List<Mask4Ray>? udp { get; set; }
public QuicParams4Ray? quicParams { get; set; }
} }
public class Mask4Ray public class Mask4Ray
{ {
public string type { get; set; } public string type { get; set; }
public object? settings { get; set; } public MaskSettings4Ray? settings { get; set; }
} }
public class MaskSettings4Ray public class MaskSettings4Ray
@ -491,6 +488,14 @@ public class MaskSettings4Ray
public string? domain { get; set; } public string? domain { get; set; }
} }
public class QuicParams4Ray
{
public string? congestion { get; set; }
public string? brutalUp { get; set; }
public string? brutalDown { get; set; }
public UdpHop4Ray? udpHop { get; set; }
}
public class AccountsItem4Ray public class AccountsItem4Ray
{ {
public string user { get; set; } public string user { get; set; }

View file

@ -3078,6 +3078,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 ICMP routing policy 的本地化字符串。
/// </summary>
public static string TbIcmpRoutingPolicy {
get {
return ResourceManager.GetString("TbIcmpRoutingPolicy", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 UUID(id) 的本地化字符串。 /// 查找类似 UUID(id) 的本地化字符串。
/// </summary> /// </summary>

View file

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

View file

@ -1689,4 +1689,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbUsername" xml:space="preserve"> <data name="TbUsername" xml:space="preserve">
<value>Username</value> <value>Username</value>
</data> </data>
<data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</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="TbUsername" xml:space="preserve"> <data name="TbUsername" xml:space="preserve">
<value>Username</value> <value>Username</value>
</data> </data>
<data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</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="TbUsername" xml:space="preserve"> <data name="TbUsername" xml:space="preserve">
<value>Username</value> <value>Username</value>
</data> </data>
<data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</value>
</data>
</root> </root>

View file

@ -1692,4 +1692,7 @@
<data name="TbUsername" xml:space="preserve"> <data name="TbUsername" xml:space="preserve">
<value>Username</value> <value>Username</value>
</data> </data>
<data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP routing policy</value>
</data>
</root> </root>

View file

@ -1689,4 +1689,7 @@
<data name="TbUsername" xml:space="preserve"> <data name="TbUsername" xml:space="preserve">
<value>用户名</value> <value>用户名</value>
</data> </data>
<data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP 路由策略</value>
</data>
</root> </root>

View file

@ -1672,10 +1672,10 @@
<value>全選</value> <value>全選</value>
</data> </data>
<data name="menuEditPaste" xml:space="preserve"> <data name="menuEditPaste" xml:space="preserve">
<value>Paste</value> <value>貼上</value>
</data> </data>
<data name="menuEditFormat" xml:space="preserve"> <data name="menuEditFormat" xml:space="preserve">
<value>Format</value> <value>格式化</value>
</data> </data>
<data name="TbUot" xml:space="preserve"> <data name="TbUot" xml:space="preserve">
<value>UDP over TCP</value> <value>UDP over TCP</value>
@ -1684,9 +1684,12 @@
<value>新增 [NaïveProxy] 節點</value> <value>新增 [NaïveProxy] 節點</value>
</data> </data>
<data name="TbInsecureConcurrency" xml:space="preserve"> <data name="TbInsecureConcurrency" xml:space="preserve">
<value>Insecure Concurrency</value> <value>不安全的並行處理</value>
</data> </data>
<data name="TbUsername" xml:space="preserve"> <data name="TbUsername" xml:space="preserve">
<value>Username</value> <value>使用者名稱</value>
</data> </data>
</root> <data name="TbIcmpRoutingPolicy" xml:space="preserve">
<value>ICMP 路由策略</value>
</data>
</root>

View file

@ -224,13 +224,14 @@ public partial class CoreConfigSingboxService
password = protocolExtra.SalamanderPass.TrimEx(), password = protocolExtra.SalamanderPass.TrimEx(),
}; };
} }
int? upMbps = protocolExtra?.UpMbps is { } su and >= 0
outbound.up_mbps = protocolExtra?.UpMbps is { } su and >= 0
? su ? su
: _config.HysteriaItem.UpMbps; : _config.HysteriaItem.UpMbps;
outbound.down_mbps = protocolExtra?.DownMbps is { } sd and >= 0 int? downMbps = protocolExtra?.DownMbps is { } sd and >= 0
? sd ? sd
: _config.HysteriaItem.DownMbps; : _config.HysteriaItem.UpMbps;
outbound.up_mbps = upMbps > 0 ? upMbps : null;
outbound.down_mbps = downMbps > 0 ? downMbps : null;
var ports = protocolExtra?.Ports?.IsNullOrEmpty() == false ? protocolExtra.Ports : null; var ports = protocolExtra?.Ports?.IsNullOrEmpty() == false ? protocolExtra.Ports : null;
if ((!ports.IsNullOrEmpty()) && (ports.Contains(':') || ports.Contains('-') || ports.Contains(','))) if ((!ports.IsNullOrEmpty()) && (ports.Contains(':') || ports.Contains('-') || ports.Contains(',')))
{ {
@ -282,7 +283,7 @@ public partial class CoreConfigSingboxService
{ {
outbound.username = _node.Username; outbound.username = _node.Username;
outbound.password = _node.Password; outbound.password = _node.Password;
if (outbound.network == "quic") if (protocolExtra.NaiveQuic == true)
{ {
outbound.quic = true; outbound.quic = true;
outbound.quic_congestion_control = protocolExtra.CongestionControl.NullIfEmpty(); outbound.quic_congestion_control = protocolExtra.CongestionControl.NullIfEmpty();

View file

@ -47,6 +47,36 @@ public partial class CoreConfigSingboxService
outbound = Global.DirectTag, outbound = Global.DirectTag,
process_name = lstDirectExe process_name = lstDirectExe
}); });
// ICMP Routing
var icmpRouting = _config.TunModeItem.IcmpRouting ?? "";
if (!Global.TunIcmpRoutingPolicies.Contains(icmpRouting))
{
icmpRouting = Global.TunIcmpRoutingPolicies.First();
}
if (icmpRouting == "direct")
{
_coreConfig.route.rules.Add(new()
{
network = ["icmp"],
outbound = Global.DirectTag,
});
}
else if (icmpRouting != "rule")
{
var rejectMethod = icmpRouting switch
{
"unreachable" => "default",
"drop" => "drop",
_ => "reply",
};
_coreConfig.route.rules.Add(new()
{
network = ["icmp"],
action = "reject",
method = rejectMethod,
});
}
} }
if (_config.Inbound.First().SniffingEnabled) if (_config.Inbound.First().SniffingEnabled)

View file

@ -441,10 +441,10 @@ public partial class CoreConfigV2rayService
kcpSettings.congestion = _config.KcpItem.Congestion; kcpSettings.congestion = _config.KcpItem.Congestion;
kcpSettings.readBufferSize = _config.KcpItem.ReadBufferSize; kcpSettings.readBufferSize = _config.KcpItem.ReadBufferSize;
kcpSettings.writeBufferSize = _config.KcpItem.WriteBufferSize; kcpSettings.writeBufferSize = _config.KcpItem.WriteBufferSize;
streamSettings.finalmask ??= new(); var kcpFinalmask = new Finalmask4Ray();
if (Global.KcpHeaderMaskMap.TryGetValue(_node.HeaderType, out var header)) if (Global.KcpHeaderMaskMap.TryGetValue(_node.HeaderType, out var header))
{ {
streamSettings.finalmask.udp = kcpFinalmask.udp =
[ [
new Mask4Ray new Mask4Ray
{ {
@ -453,23 +453,24 @@ public partial class CoreConfigV2rayService
} }
]; ];
} }
streamSettings.finalmask.udp ??= []; kcpFinalmask.udp ??= [];
if (path.IsNullOrEmpty()) if (path.IsNullOrEmpty())
{ {
streamSettings.finalmask.udp.Add(new Mask4Ray kcpFinalmask.udp.Add(new Mask4Ray
{ {
type = "mkcp-original" type = "mkcp-original"
}); });
} }
else else
{ {
streamSettings.finalmask.udp.Add(new Mask4Ray kcpFinalmask.udp.Add(new Mask4Ray
{ {
type = "mkcp-aes128gcm", type = "mkcp-aes128gcm",
settings = new MaskSettings4Ray { password = path } settings = new MaskSettings4Ray { password = path }
}); });
} }
streamSettings.kcpSettings = kcpSettings; streamSettings.kcpSettings = kcpSettings;
streamSettings.finalmask = kcpFinalmask;
break; break;
//ws //ws
case nameof(ETransport.ws): case nameof(ETransport.ws):
@ -598,36 +599,46 @@ public partial class CoreConfigV2rayService
: (_config.HysteriaItem.HopInterval >= 5 : (_config.HysteriaItem.HopInterval >= 5
? _config.HysteriaItem.HopInterval ? _config.HysteriaItem.HopInterval
: Global.Hysteria2DefaultHopInt).ToString(); : Global.Hysteria2DefaultHopInt).ToString();
HysteriaUdpHop4Ray? udpHop = null; var hy2Finalmask = new Finalmask4Ray();
var quicParams = new QuicParams4Ray();
if (!ports.IsNullOrEmpty() && if (!ports.IsNullOrEmpty() &&
(ports.Contains(':') || ports.Contains('-') || ports.Contains(','))) (ports.Contains(':') || ports.Contains('-') || ports.Contains(',')))
{ {
udpHop = new HysteriaUdpHop4Ray var udpHop = new UdpHop4Ray
{ {
port = ports.Replace(':', '-'), ports = ports.Replace(':', '-'),
interval = hopInterval, interval = hopInterval,
}; };
quicParams.udpHop = udpHop;
}
if (upMbps > 0 || downMbps > 0)
{
quicParams.congestion = "brutal";
quicParams.brutalUp = upMbps > 0 ? $"{upMbps}mbps" : null;
quicParams.brutalDown = downMbps > 0 ? $"{downMbps}mbps" : null;
}
else
{
quicParams.congestion = "bbr";
}
hy2Finalmask.quicParams = quicParams;
if (!protocolExtra.SalamanderPass.IsNullOrEmpty())
{
hy2Finalmask.udp =
[
new Mask4Ray
{
type = "salamander",
settings = new MaskSettings4Ray { password = protocolExtra.SalamanderPass.TrimEx(), }
}
];
} }
streamSettings.hysteriaSettings = new() streamSettings.hysteriaSettings = new()
{ {
version = 2, version = 2,
auth = _node.Password, auth = _node.Password,
up = upMbps > 0 ? $"{upMbps}mbps" : null,
down = downMbps > 0 ? $"{downMbps}mbps" : null,
udphop = udpHop,
}; };
if (!protocolExtra.SalamanderPass.IsNullOrEmpty()) streamSettings.finalmask = hy2Finalmask;
{
streamSettings.finalmask ??= new();
streamSettings.finalmask.udp =
[
new Mask4Ray
{
type = "salamander",
settings = new MaskSettings4Ray { password = protocolExtra.SalamanderPass.TrimEx(), }
}
];
}
break; break;
default: default:
@ -665,7 +676,7 @@ public partial class CoreConfigV2rayService
if (!_node.Finalmask.IsNullOrEmpty()) if (!_node.Finalmask.IsNullOrEmpty())
{ {
streamSettings.finalmask = JsonUtils.Deserialize<Finalmask4Ray>(_node.Finalmask); streamSettings.finalmask = JsonUtils.ParseJson(_node.Finalmask);
} }
} }
catch (Exception ex) catch (Exception ex)

View file

@ -68,7 +68,10 @@ public class AddServerViewModel : MyReactiveObject
public string CongestionControl { get; set; } public string CongestionControl { get; set; }
[Reactive] [Reactive]
public int InsecureConcurrency { get; set; } public int? InsecureConcurrency { get; set; }
[Reactive]
public bool NaiveQuic { 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; }
@ -134,7 +137,8 @@ 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; InsecureConcurrency = protocolExtra?.InsecureConcurrency > 0 ? protocolExtra.InsecureConcurrency : null;
NaiveQuic = protocolExtra?.NaiveQuic ?? false;
} }
private async Task SaveServerAsync() private async Task SaveServerAsync()
@ -199,7 +203,8 @@ 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 InsecureConcurrency = InsecureConcurrency > 0 ? InsecureConcurrency : null,
NaiveQuic = NaiveQuic ? true : null,
}); });
if (await ConfigHandler.AddServer(_config, SelectedSource) == 0) if (await ConfigHandler.AddServer(_config, SelectedSource) == 0)

View file

@ -95,6 +95,7 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public string TunStack { get; set; } [Reactive] public string TunStack { get; set; }
[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; }
#endregion Tun mode #endregion Tun mode
@ -218,6 +219,7 @@ public class OptionSettingViewModel : MyReactiveObject
TunStack = _config.TunModeItem.Stack; TunStack = _config.TunModeItem.Stack;
TunMtu = _config.TunModeItem.Mtu; TunMtu = _config.TunModeItem.Mtu;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address; TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunIcmpRouting = _config.TunModeItem.IcmpRouting;
#endregion Tun mode #endregion Tun mode
@ -376,6 +378,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.TunModeItem.Stack = TunStack; _config.TunModeItem.Stack = TunStack;
_config.TunModeItem.Mtu = TunMtu; _config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address; _config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
_config.TunModeItem.IcmpRouting = TunIcmpRouting;
//coreType //coreType
await SaveCoreType(); await SaveCoreType();

View file

@ -497,7 +497,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbHeaderType8}" /> Text="{x:Static resx:ResUI.TbHeaderType8}" />
<ComboBox <ComboBox
x:Name="cmbHeaderType8" x:Name="cmbCongestionControl8"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
@ -637,27 +637,36 @@
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbInsecureConcurrency}" /> Text="QUIC" />
<TextBox <StackPanel
x:Name="txtInsecureConcurrency12"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Orientation="Horizontal">
HorizontalAlignment="Left" /> <ToggleSwitch
x:Name="togNaiveQuic12"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<ComboBox
x:Name="cmbCongestionControl12"
Width="200"
Margin="{StaticResource Margin4}"
PlaceholderText="{x:Static resx:ResUI.TbHeaderType8}" />
</StackPanel>
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbHeaderType8}" /> Text="{x:Static resx:ResUI.TbInsecureConcurrency}" />
<ComboBox <TextBox
x:Name="cmbHeaderType12" x:Name="txtInsecureConcurrency12"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"

View file

@ -80,7 +80,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
cmbFingerprint.SelectedValue = string.Empty; cmbFingerprint.SelectedValue = string.Empty;
gridFinalmask.IsVisible = false; gridFinalmask.IsVisible = false;
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls; cmbCongestionControl8.ItemsSource = Global.TuicCongestionControls;
break; break;
case EConfigType.WireGuard: case EConfigType.WireGuard:
@ -103,14 +103,18 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.Naive: case EConfigType.Naive:
gridNaive.IsVisible = true; gridNaive.IsVisible = true;
sepa2.IsVisible = false;
gridTransport.IsVisible = false;
cmbCoreType.IsEnabled = false; cmbCoreType.IsEnabled = false;
gridFinalmask.IsVisible = false; gridFinalmask.IsVisible = false;
cmbFingerprint.IsEnabled = false; cmbFingerprint.IsEnabled = false;
cmbFingerprint.SelectedValue = string.Empty; cmbFingerprint.SelectedValue = string.Empty;
cmbAlpn.IsEnabled = false;
cmbAlpn.SelectedValue = string.Empty;
cmbAllowInsecure.IsEnabled = false; cmbAllowInsecure.IsEnabled = false;
cmbAllowInsecure.SelectedValue = string.Empty; cmbAllowInsecure.SelectedValue = string.Empty;
cmbHeaderType12.ItemsSource = Global.NaiveCongestionControls; cmbCongestionControl12.ItemsSource = Global.NaiveCongestionControls;
break; break;
} }
cmbStreamSecurity.ItemsSource = lstStreamSecurity; cmbStreamSecurity.ItemsSource = lstStreamSecurity;
@ -171,7 +175,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.TUIC: case EConfigType.TUIC:
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbCongestionControl8.SelectedValue).DisposeWith(disposables);
break; break;
case EConfigType.WireGuard: case EConfigType.WireGuard:
@ -189,8 +193,10 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.Naive: case EConfigType.Naive:
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables); 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.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NaiveQuic, v => v.togNaiveQuic12.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NaiveQuic, v => v.cmbCongestionControl12.IsEnabled).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbCongestionControl12.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.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); this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables);
break; break;
} }

View file

@ -824,6 +824,20 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbIcmpRoutingPolicy}" />
<ComboBox
x:Name="cmbIcmpRoutingPolicy"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"

View file

@ -34,6 +34,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs; cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs;
cmbMtu.ItemsSource = Global.TunMtus; cmbMtu.ItemsSource = Global.TunMtus;
cmbStack.ItemsSource = Global.TunStacks; cmbStack.ItemsSource = Global.TunStacks;
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
cmbCoreType1.ItemsSource = Global.CoreTypes; cmbCoreType1.ItemsSource = Global.CoreTypes;
cmbCoreType2.ItemsSource = Global.CoreTypes; cmbCoreType2.ItemsSource = Global.CoreTypes;
@ -114,6 +115,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.SelectedValue).DisposeWith(disposables);
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.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

@ -660,7 +660,7 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbHeaderType8}" /> Text="{x:Static resx:ResUI.TbHeaderType8}" />
<ComboBox <ComboBox
x:Name="cmbHeaderType8" x:Name="cmbCongestionControl8"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
@ -846,15 +846,24 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbInsecureConcurrency}" /> Text="QUIC" />
<TextBox <StackPanel
x:Name="txtInsecureConcurrency12"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="200" VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Orientation="Horizontal">
HorizontalAlignment="Left" <ToggleButton
Style="{StaticResource DefTextBox}" /> x:Name="togNaiveQuic12"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<ComboBox
x:Name="cmbCongestionControl12"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Right"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.TbHeaderType8}"
Style="{StaticResource DefComboBox}" />
</StackPanel>
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@ -862,14 +871,15 @@
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbHeaderType8}" /> Text="{x:Static resx:ResUI.TbInsecureConcurrency}" />
<ComboBox <TextBox
x:Name="cmbHeaderType12" x:Name="txtInsecureConcurrency12"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" /> HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"

View file

@ -75,7 +75,7 @@ public partial class AddServerWindow
cmbFingerprint.Text = string.Empty; cmbFingerprint.Text = string.Empty;
gridFinalmask.Visibility = Visibility.Collapsed; gridFinalmask.Visibility = Visibility.Collapsed;
cmbHeaderType8.ItemsSource = Global.TuicCongestionControls; cmbCongestionControl8.ItemsSource = Global.TuicCongestionControls;
break; break;
case EConfigType.WireGuard: case EConfigType.WireGuard:
@ -98,14 +98,18 @@ public partial class AddServerWindow
case EConfigType.Naive: case EConfigType.Naive:
gridNaive.Visibility = Visibility.Visible; gridNaive.Visibility = Visibility.Visible;
sepa2.Visibility = Visibility.Collapsed;
gridTransport.Visibility = Visibility.Collapsed;
cmbCoreType.IsEnabled = false; cmbCoreType.IsEnabled = false;
gridFinalmask.Visibility = Visibility.Collapsed; gridFinalmask.Visibility = Visibility.Collapsed;
cmbFingerprint.IsEnabled = false; cmbFingerprint.IsEnabled = false;
cmbFingerprint.Text = string.Empty; cmbFingerprint.Text = string.Empty;
cmbAlpn.IsEnabled = false;
cmbAlpn.Text = string.Empty;
cmbAllowInsecure.IsEnabled = false; cmbAllowInsecure.IsEnabled = false;
cmbAllowInsecure.Text = string.Empty; cmbAllowInsecure.Text = string.Empty;
cmbHeaderType12.ItemsSource = Global.NaiveCongestionControls; cmbCongestionControl12.ItemsSource = Global.NaiveCongestionControls;
break; break;
} }
cmbStreamSecurity.ItemsSource = lstStreamSecurity; cmbStreamSecurity.ItemsSource = lstStreamSecurity;
@ -166,7 +170,7 @@ public partial class AddServerWindow
case EConfigType.TUIC: case EConfigType.TUIC:
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbCongestionControl8.Text).DisposeWith(disposables);
break; break;
case EConfigType.WireGuard: case EConfigType.WireGuard:
@ -184,8 +188,9 @@ public partial class AddServerWindow
case EConfigType.Naive: case EConfigType.Naive:
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables); 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.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.NaiveQuic, v => v.togNaiveQuic12.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbCongestionControl12.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.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); this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables);
break; break;
} }

View file

@ -1076,6 +1076,22 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbIcmpRoutingPolicy}" />
<ComboBox
x:Name="cmbIcmpRoutingPolicy"
Grid.Row="6"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"

View file

@ -31,6 +31,7 @@ public partial class OptionSettingWindow
cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs; cmbmux4SboxProtocol.ItemsSource = Global.SingboxMuxs;
cmbMtu.ItemsSource = Global.TunMtus; cmbMtu.ItemsSource = Global.TunMtus;
cmbStack.ItemsSource = Global.TunStacks; cmbStack.ItemsSource = Global.TunStacks;
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
cmbCoreType1.ItemsSource = Global.CoreTypes; cmbCoreType1.ItemsSource = Global.CoreTypes;
cmbCoreType2.ItemsSource = Global.CoreTypes; cmbCoreType2.ItemsSource = Global.CoreTypes;
@ -119,6 +120,7 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
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.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);