Compare commits

...

33 commits

Author SHA1 Message Date
DHR60
4254c1c28e Adds anytls reality support 2025-07-07 11:38:18 +08:00
DHR60
f635456508 Deletes Duplicate Rules 2025-07-07 11:38:18 +08:00
DHR60
ebf0e1715b Adds sing-box DomainStrategy support 2025-07-07 11:38:18 +08:00
DHR60
8772e76067 Adds tag resolver supports 2025-07-07 11:38:18 +08:00
DHR60
d3fbaa3a91 Support sing-box hosts 2025-07-07 11:38:18 +08:00
DHR60
7719123373 Removes Wireguard listen port 2025-07-07 11:38:18 +08:00
DHR60
f28bc28394 Adds properties to Rule4Sbox class 2025-07-07 11:38:18 +08:00
DHR60
9fa430dff7 Improves DNS address parsing in Singbox
DNS type, host, port, and path
2025-07-07 11:38:18 +08:00
DHR60
aeb57a3c1c Removes direct clash_mode domain strategy 2025-07-07 11:38:18 +08:00
DHR60
5db4bd158b Fixes wrong field 2025-07-07 11:38:18 +08:00
DHR60
6a6f4f5407 fix singbox endpoints proxy chain not work 2025-07-07 11:38:18 +08:00
DHR60
951eb2e1fd Fixes config generation 2025-07-07 11:38:18 +08:00
DHR60
b0018c99ea Refactors DNS address parsing 2025-07-07 11:38:18 +08:00
DHR60
892a5ef064 Adds IPv4 preference to DNS configurations
对应原dns.servers[].strategy = prefer_ipv4
2025-07-07 11:38:18 +08:00
DHR60
0d2eec6e36 Adds Sing-box legacy DNS config support 2025-07-07 11:38:17 +08:00
DHR60
e7607a9a6a Utils.GetFreePort() default port to be zero 2025-07-07 11:38:17 +08:00
DHR60
730bb0521b support Wireguard endpoint
Refactors Singbox config classes for dial fields
2025-07-07 11:38:17 +08:00
DHR60
1fbbcb046b Fetches DNS strategy for domain resolution 2025-07-07 11:38:17 +08:00
DHR60
33c2e00ebd Enables dhcp interface configuration 2025-07-07 11:38:17 +08:00
DHR60
3d0c78bdeb Simplifies local DNS address handling 2025-07-07 11:38:17 +08:00
DHR60
72695167ab add anytls support 2025-07-07 11:38:17 +08:00
DHR60
64dc0ea0c2 Improves geoip rule handling in singbox 2025-07-07 11:38:12 +08:00
DHR60
3cb23e9f57 Adds Google cn dns rules 2025-07-07 11:38:12 +08:00
DHR60
d30b9fc08b Migrating to singbox 1.12 support 2025-07-07 11:38:12 +08:00
DHR60
c230a183fb Removes unnecessary sniffer 2025-07-07 11:38:12 +08:00
DHR60
e9cced8e09 Migrating to singbox 1.11 support 2025-07-07 11:38:12 +08:00
2dust
da3d4c36a9 Improve and optimize the active rules code in routing settings
Some checks failed
release Linux / build (Release) (push) Has been cancelled
release macOS / build (Release) (push) Has been cancelled
release Windows desktop (Avalonia UI) / build (Release) (push) Has been cancelled
release Windows / build (Release) (push) Has been cancelled
2025-07-06 18:15:07 +08:00
2dust
1d01476523 Adjust UI 2025-07-06 17:51:09 +08:00
2dust
75ceba1b08 Remove unused 2025-07-06 14:11:34 +08:00
2dust
493c37e7d5 Update Directory.Packages.props 2025-07-06 12:27:38 +08:00
2dust
6d686b284d Fix macOS scaling size
Some checks failed
release Linux / build (Release) (push) Has been cancelled
release macOS / build (Release) (push) Has been cancelled
release Windows desktop (Avalonia UI) / build (Release) (push) Has been cancelled
release Windows / build (Release) (push) Has been cancelled
2025-07-04 20:48:32 +08:00
Nelson Lai
60fcf6174e
Update zh hant localization (#7528)
Some checks are pending
release Linux / build (Release) (push) Waiting to run
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 localization

* Remove newline at end of Traditional Chinese localization file
2025-07-03 20:46:22 +08:00
2dust
4141f451b7 The window height and width variable type is changed from double to int
Some checks are pending
release Linux / build (Release) (push) Waiting to run
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
2025-07-02 20:53:53 +08:00
41 changed files with 835 additions and 467 deletions

View file

@ -5,22 +5,22 @@
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.1" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.1" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.1" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.1" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.2" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.2" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.2" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.2" />
<PackageVersion Include="CliWrap" Version="3.9.0" />
<PackageVersion Include="Downloader" Version="3.3.4" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
<PackageVersion Include="QRCoder" Version="1.6.0" />
<PackageVersion Include="ReactiveUI" Version="20.3.1" />
<PackageVersion Include="ReactiveUI" Version="20.4.1" />
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageVersion Include="ReactiveUI.WPF" Version="20.3.1" />
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.8" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.8" />
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
<PackageVersion Include="Splat.NLog" Version="15.4.1" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
<PackageVersion Include="WebDav.Client" Version="2.9.0" />

View file

@ -427,11 +427,11 @@ public class Utils
return false;
}
public static int GetFreePort(int defaultPort = 9090)
public static int GetFreePort(int defaultPort = 0)
{
try
{
if (!Utils.PortInUse(defaultPort))
if (!(defaultPort == 0 || Utils.PortInUse(defaultPort)))
{
return defaultPort;
}
@ -816,18 +816,6 @@ public class Utils
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
}
return false;
//else
//{
// var id = GetLinuxUserId().Result ?? "1000";
// if (int.TryParse(id, out var userId))
// {
// return userId == 0;
// }
// else
// {
// return false;
// }
//}
}
private static async Task<string?> GetLinuxUserId()

View file

@ -11,5 +11,6 @@ public enum EConfigType
Hysteria2 = 7,
TUIC = 8,
WireGuard = 9,
HTTP = 10
HTTP = 10,
Anytls = 11
}

View file

@ -167,7 +167,8 @@ public class Global
{ EConfigType.Trojan, "trojan://" },
{ EConfigType.Hysteria2, "hysteria2://" },
{ EConfigType.TUIC, "tuic://" },
{ EConfigType.WireGuard, "wireguard://" }
{ EConfigType.WireGuard, "wireguard://" },
{ EConfigType.Anytls, "anytls://" }
};
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
@ -180,7 +181,8 @@ public class Global
{ EConfigType.Trojan, "trojan" },
{ EConfigType.Hysteria2, "hysteria2" },
{ EConfigType.TUIC, "tuic" },
{ EConfigType.WireGuard, "wireguard" }
{ EConfigType.WireGuard, "wireguard" },
{ EConfigType.Anytls, "anytls" }
};
public static readonly List<string> VmessSecurities =

View file

@ -261,6 +261,7 @@ public class ConfigHandler
EConfigType.Hysteria2 => await AddHysteria2Server(config, item),
EConfigType.TUIC => await AddTuicServer(config, item),
EConfigType.WireGuard => await AddWireguardServer(config, item),
EConfigType.Anytls => await AddAnytlsServer(config, item),
_ => -1,
};
return ret;
@ -785,6 +786,35 @@ public class ConfigHandler
return 0;
}
/// <summary>
/// Add or edit a Anytls server
/// Validates and processes Anytls-specific settings
/// </summary>
/// <param name="config">Current configuration</param>
/// <param name="profileItem">Anytls 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> AddAnytlsServer(Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.ConfigType = EConfigType.Anytls;
profileItem.CoreType = ECoreType.sing_box;
profileItem.Address = profileItem.Address.TrimEx();
profileItem.Id = profileItem.Id.TrimEx();
profileItem.Security = profileItem.Security.TrimEx();
profileItem.Network = string.Empty;
if (profileItem.StreamSecurity.IsNullOrEmpty())
{
profileItem.StreamSecurity = Global.StreamSecurity;
}
if (profileItem.Id.IsNullOrEmpty())
{
return -1;
}
await AddServerCommon(config, profileItem, toFile);
return 0;
}
/// <summary>
/// Sort the server list by the specified column
/// Updates the sort order in the profile extension data
@ -1294,6 +1324,7 @@ public class ConfigHandler
EConfigType.Hysteria2 => await AddHysteria2Server(config, profileItem, false),
EConfigType.TUIC => await AddTuicServer(config, profileItem, false),
EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false),
EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false),
_ => -1,
};
@ -1857,12 +1888,25 @@ public class ConfigHandler
/// <returns>0 if successful</returns>
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
{
if (await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(t => t.Id == routingItem.Id).CountAsync() > 0)
var items = await AppHandler.Instance.RoutingItems();
if (items.Any(t => t.Id == routingItem.Id && t.IsActive == true))
{
config.RoutingBasicItem.RoutingIndexId = routingItem.Id;
return -1;
}
await SaveConfig(config);
foreach (var item in items)
{
if (item.Id == routingItem.Id)
{
item.IsActive = true;
}
else
{
item.IsActive = false;
}
}
await SQLiteHelper.Instance.UpdateAllAsync(items);
return 0;
}
@ -1875,7 +1919,7 @@ public class ConfigHandler
/// <returns>The default routing item</returns>
public static async Task<RoutingItem> GetDefaultRouting(Config config)
{
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
var item = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.IsActive == true);
if (item is null)
{
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
@ -1983,6 +2027,18 @@ public class ConfigHandler
if (!blImportAdvancedRules && items.Count > 0)
{
//migrate
//TODO Temporary code to be removed later
if (config.RoutingBasicItem.RoutingIndexId.IsNotEmpty())
{
var item = items.FirstOrDefault(t => t.Id == config.RoutingBasicItem.RoutingIndexId);
if (item != null)
{
await SetDefaultRouting(config, item);
}
config.RoutingBasicItem.RoutingIndexId = string.Empty;
}
return 0;
}
@ -2198,8 +2254,18 @@ public class ConfigHandler
config.UiItem.WindowSizeItem.Add(sizeItem);
}
sizeItem.Width = width;
sizeItem.Height = height;
sizeItem.Width = (int)width;
sizeItem.Height = (int)height;
return 0;
}
public static int SaveMainGirdHeight(Config config, double height1, double height2)
{
var uiItem = config.UiItem ?? new();
uiItem.MainGirdHeight1 = (int)(height1 + 0.1);
uiItem.MainGirdHeight2 = (int)(height2 + 0.1);
return 0;
}

View file

@ -101,7 +101,7 @@ public class CoreHandler
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
{
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC) ? ECoreType.sing_box : ECoreType.Xray;
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls) ? ECoreType.sing_box : ECoreType.Xray;
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
var configPath = Utils.GetBinConfigPath(fileName);
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);

View file

@ -0,0 +1,49 @@
using static QRCoder.PayloadGenerator;
namespace ServiceLib.Handler.Fmt;
public class AnytlsFmt : 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.Anytls,
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
Address = parsedUrl.IdnHost,
Port = parsedUrl.Port,
};
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
item.Id = rawUserInfo;
var query = Utils.ParseQueryString(parsedUrl.Query);
_ = ResolveStdTransport(query, ref item);
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 pw = item.Id;
var dicQuery = new Dictionary<string, string>();
_ = GetStdTransport(item, Global.None, ref dicQuery);
return ToUri(EConfigType.Anytls, item.Address, item.Port, pw, dicQuery, remark);
}
}

View file

@ -18,6 +18,7 @@ public class FmtHandler
EConfigType.Hysteria2 => Hysteria2Fmt.ToUri(item),
EConfigType.TUIC => TuicFmt.ToUri(item),
EConfigType.WireGuard => WireguardFmt.ToUri(item),
EConfigType.Anytls => AnytlsFmt.ToUri(item),
_ => null,
};
@ -75,6 +76,10 @@ public class FmtHandler
{
return WireguardFmt.Resolve(str, out msg);
}
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Anytls]))
{
return AnytlsFmt.Resolve(str, out msg);
}
else
{
msg = ResUI.NonvmessOrssProtocol;

View file

@ -89,8 +89,8 @@ public class UIItem
{
public bool EnableAutoAdjustMainLvColWidth { get; set; }
public bool EnableUpdateSubOnlyRemarksExist { get; set; }
public double MainGirdHeight1 { get; set; }
public double MainGirdHeight2 { get; set; }
public int MainGirdHeight1 { get; set; }
public int MainGirdHeight2 { get; set; }
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
public string? ColorPrimaryName { get; set; }
public string? CurrentTheme { get; set; }
@ -250,6 +250,6 @@ public class Fragment4RayItem
public class WindowSizeItem
{
public string TypeName { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}

View file

@ -19,4 +19,5 @@ public class RoutingItem
public string DomainStrategy { get; set; }
public string DomainStrategy4Singbox { get; set; }
public int Sort { get; set; }
public bool IsActive { get; set; }
}

View file

@ -3,5 +3,4 @@ namespace ServiceLib.Models;
[Serializable]
public class RoutingItemModel : RoutingItem
{
public bool IsActive { get; set; }
}

View file

@ -1,3 +1,5 @@
using System.Text.Json.Serialization;
namespace ServiceLib.Models;
public class SingboxConfig
@ -6,6 +8,7 @@ public class SingboxConfig
public Dns4Sbox? dns { get; set; }
public List<Inbound4Sbox> inbounds { get; set; }
public List<Outbound4Sbox> outbounds { get; set; }
public List<Endpoints4Sbox>? endpoints { get; set; }
public Route4Sbox route { get; set; }
public Experimental4Sbox? experimental { get; set; }
}
@ -37,6 +40,7 @@ public class Route4Sbox
public bool? auto_detect_interface { get; set; }
public List<Rule4Sbox> rules { get; set; }
public List<Ruleset4Sbox>? rule_set { get; set; }
public string? final { get; set; }
}
[Serializable]
@ -49,6 +53,7 @@ public class Rule4Sbox
public string? mode { get; set; }
public bool? ip_is_private { get; set; }
public string? client_subnet { get; set; }
public int? rewrite_ttl { get; set; }
public bool? invert { get; set; }
public string? clash_mode { get; set; }
public List<string>? inbound { get; set; }
@ -67,6 +72,27 @@ public class Rule4Sbox
public List<string>? process_name { get; set; }
public List<string>? rule_set { get; set; }
public List<Rule4Sbox>? rules { get; set; }
public string? action { get; set; }
public string? strategy { get; set; }
public List<string>? sniffer { get; set; }
public string? rcode { get; set; }
public List<object>? query_type { get; set; }
public List<string>? answer { get; set; }
public List<string>? ns { get; set; }
public List<string>? extra { get; set; }
public string? method { get; set; }
public bool? no_drop { get; set; }
public bool? source_ip_is_private { get; set; }
public bool? ip_accept_any { get; set; }
public int? source_port { get; set; }
public List<string>? source_port_range { get; set; }
public List<string>? network_type { get; set; }
public bool? network_is_expensive { get; set; }
public bool? network_is_constrained { get; set; }
public List<string>? wifi_ssid { get; set; }
public List<string>? wifi_bssid { get; set; }
public bool? rule_set_ip_cidr_match_source { get; set; }
public bool? rule_set_ip_cidr_accept_empty { get; set; }
}
[Serializable]
@ -76,7 +102,6 @@ public class Inbound4Sbox
public string tag { get; set; }
public string listen { get; set; }
public int? listen_port { get; set; }
public string? domain_strategy { get; set; }
public string interface_name { get; set; }
public List<string>? address { get; set; }
public int? mtu { get; set; }
@ -84,8 +109,6 @@ public class Inbound4Sbox
public bool? strict_route { get; set; }
public bool? endpoint_independent_nat { get; set; }
public string? stack { get; set; }
public bool? sniff { get; set; }
public bool? sniff_override_destination { get; set; }
public List<User4Sbox> users { get; set; }
}
@ -95,10 +118,8 @@ public class User4Sbox
public string password { get; set; }
}
public class Outbound4Sbox
public class Outbound4Sbox : BaseServer4Sbox
{
public string type { get; set; }
public string tag { get; set; }
public string? server { get; set; }
public int? server_port { get; set; }
public List<string>? server_ports { get; set; }
@ -113,7 +134,6 @@ public class Outbound4Sbox
public int? recv_window_conn { get; set; }
public int? recv_window { get; set; }
public bool? disable_mtu_discovery { get; set; }
public string? detour { get; set; }
public string? method { get; set; }
public string? username { get; set; }
public string? password { get; set; }
@ -121,21 +141,36 @@ public class Outbound4Sbox
public string? version { get; set; }
public string? network { get; set; }
public string? packet_encoding { get; set; }
public List<string>? local_address { get; set; }
public string? private_key { get; set; }
public string? peer_public_key { get; set; }
public List<int>? reserved { get; set; }
public int? mtu { get; set; }
public string? plugin { get; set; }
public string? plugin_opts { get; set; }
public Tls4Sbox? tls { get; set; }
public Multiplex4Sbox? multiplex { get; set; }
public Transport4Sbox? transport { get; set; }
public HyObfs4Sbox? obfs { get; set; }
public List<string>? outbounds { get; set; }
public bool? interrupt_exist_connections { get; set; }
}
public class Endpoints4Sbox : BaseServer4Sbox
{
public bool? system { get; set; }
public string? name { get; set; }
public int? mtu { get; set; }
public List<string> address { get; set; }
public string private_key { get; set; }
public int? listen_port { get; set; }
public string? udp_timeout { get; set; }
public int? workers { get; set; }
public List<Peer4Sbox> peers { get; set; }
}
public class Peer4Sbox
{
public string address { get; set; }
public int port { get; set; }
public string public_key { get; set; }
public string? pre_shared_key { get; set; }
public List<string> allowed_ips { get; set; }
public int? persistent_keepalive_interval { get; set; }
public List<int> reserved { get; set; }
}
public class Tls4Sbox
{
public bool enabled { get; set; }
@ -191,15 +226,23 @@ public class HyObfs4Sbox
public string? password { get; set; }
}
public class Server4Sbox
public class Server4Sbox : BaseServer4Sbox
{
public string? tag { get; set; }
public string? client_subnet { get; set; }
public string? server { get; set; }
public new string? domain_resolver { get; set; }
[JsonPropertyName("interface")] public string? Interface { get; set; }
public int? server_port { get; set; }
public string? path { get; set; }
public Headers4Sbox? headers { get; set; }
// public List<string>? path { get; set; } // hosts
public Dictionary<string, object>? predefined { get; set; }
// Deprecated
public string? address { get; set; }
public string? address_resolver { get; set; }
public string? address_strategy { get; set; }
public string? strategy { get; set; }
public string? detour { get; set; }
public string? client_subnet { get; set; }
// Deprecated End
}
public class Experimental4Sbox
@ -254,3 +297,33 @@ public class Ruleset4Sbox
public string? download_detour { get; set; }
public string? update_interval { get; set; }
}
public abstract class DialFields4Sbox
{
public string? detour { get; set; }
public string? bind_interface { get; set; }
public string? inet4_bind_address { get; set; }
public string? inet6_bind_address { get; set; }
public int? routing_mark { get; set; }
public bool? reuse_addr { get; set; }
public string? netns { get; set; }
public string? connect_timeout { get; set; }
public bool? tcp_fast_open { get; set; }
public bool? tcp_multi_path { get; set; }
public bool? udp_fragment { get; set; }
public Rule4Sbox? domain_resolver { get; set; } // or string
public string? network_strategy { get; set; }
public List<string>? network_type { get; set; }
public List<string>? fallback_network_type { get; set; }
public string? fallback_delay { get; set; }
public Tls4Sbox? tls { get; set; }
public Multiplex4Sbox? multiplex { get; set; }
public Transport4Sbox? transport { get; set; }
public HyObfs4Sbox? obfs { get; set; }
}
public abstract class BaseServer4Sbox : DialFields4Sbox
{
public string type { get; set; }
public string tag { get; set; }
}

View file

@ -132,24 +132,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Download speed 的本地化字符串。
/// </summary>
public static string downloadSpeed {
get {
return ResourceManager.GetString("downloadSpeed", resourceCulture);
}
}
/// <summary>
/// 查找类似 Do you want to download {0}? 的本地化字符串。
/// </summary>
public static string DownloadYesNo {
get {
return ResourceManager.GetString("DownloadYesNo", resourceCulture);
}
}
/// <summary>
/// 查找类似 Failed to convert configuration file 的本地化字符串。
/// </summary>
@ -672,6 +654,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Add [Anytls] Configuration 的本地化字符串。
/// </summary>
public static string menuAddAnytlsServer {
get {
return ResourceManager.GetString("menuAddAnytlsServer", resourceCulture);
}
}
/// <summary>
/// 查找类似 Add a custom configuration Configuration 的本地化字符串。
/// </summary>
@ -1347,15 +1338,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Advanced Function 的本地化字符串。
/// </summary>
public static string menuRoutingAdvanced {
get {
return ResourceManager.GetString("menuRoutingAdvanced", resourceCulture);
}
}
/// <summary>
/// 查找类似 Add 的本地化字符串。
/// </summary>
@ -2715,33 +2697,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 3. Block Domain or IP 的本地化字符串。
/// </summary>
public static string TbRoutingTabBlock {
get {
return ResourceManager.GetString("TbRoutingTabBlock", resourceCulture);
}
}
/// <summary>
/// 查找类似 2. Direct Domain or IP 的本地化字符串。
/// </summary>
public static string TbRoutingTabDirect {
get {
return ResourceManager.GetString("TbRoutingTabDirect", resourceCulture);
}
}
/// <summary>
/// 查找类似 1. Proxy Domain or IP 的本地化字符串。
/// </summary>
public static string TbRoutingTabProxy {
get {
return ResourceManager.GetString("TbRoutingTabProxy", resourceCulture);
}
}
/// <summary>
/// 查找类似 Pre-defined Rule Set List 的本地化字符串。
/// </summary>
@ -3237,24 +3192,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Please set the sudo password in Tun mode settings first 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordIsEmpty {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordIsEmpty", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please do not run this app with sudo 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordNotSudoRunApp {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordNotSudoRunApp", resourceCulture);
}
}
/// <summary>
/// 查找类似 The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart. 的本地化字符串。
/// </summary>
@ -3948,15 +3885,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Ungrouped 的本地化字符串。
/// </summary>
public static string UngroupedServers {
get {
return ResourceManager.GetString("UngroupedServers", resourceCulture);
}
}
/// <summary>
/// 查找类似 Upgrade App does not exist 的本地化字符串。
/// </summary>

View file

@ -132,12 +132,6 @@
<data name="Downloading" xml:space="preserve">
<value>درحال دانلود...</value>
</data>
<data name="downloadSpeed" xml:space="preserve">
<value>دانلود</value>
</data>
<data name="DownloadYesNo" xml:space="preserve">
<value>آیا می خواهید {0} را دانلود کنید؟</value>
</data>
<data name="FailedConversionConfiguration" xml:space="preserve">
<value>تبدیل فایل پیکربندی انجام نشد</value>
</data>
@ -387,9 +381,6 @@
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
<value>کلید میانبر جهانی {0} با موفقیت ثبت شد</value>
</data>
<data name="UngroupedServers" xml:space="preserve">
<value>گروه بندی نشده</value>
</data>
<data name="AllGroupServers" xml:space="preserve">
<value>همه سرورها</value>
</data>
@ -822,9 +813,6 @@
<data name="menuWebsiteItem" xml:space="preserve">
<value>{0} وب سایت</value>
</data>
<data name="menuRoutingAdvanced" xml:space="preserve">
<value>عملکرد پیشرفته</value>
</data>
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
<value>اضافه کردن</value>
</data>
@ -843,15 +831,6 @@
<data name="TbdomainStrategy" xml:space="preserve">
<value>استراتژی دامنه</value>
</data>
<data name="TbRoutingTabBlock" xml:space="preserve">
<value>3. مسدود کردن دامنه یا آیپی</value>
</data>
<data name="TbRoutingTabDirect" xml:space="preserve">
<value>2. دایرکت کردن دامنه یا IP</value>
</data>
<data name="TbRoutingTabProxy" xml:space="preserve">
<value>1. پروکسی کردن دامنه یا IP</value>
</data>
<data name="TbRoutingTabRuleList" xml:space="preserve">
<value>لیست مجموعه قوانین از پیش تعریف شده</value>
</data>
@ -1341,12 +1320,6 @@
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>رمز عبوری که وارد کرده اید تایید نمی شود، بنابراین مطمئن شوید که آن را به درستی وارد کرده اید. اگر برنامه به دلیل ورودی نادرست به درستی کار نمی کند، لطفاً برنامه را مجدداً راه اندازی کنید. رمز عبور ذخیره نمی شود و پس از هر بار راه اندازی مجدد باید آن را دوباره وارد کنید.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>لطفا این برنامه را با sudo اجرا نکنید</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*حالت xhttp</value>
</data>
@ -1419,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>URL آزمایش اطلاعات اتصال فعلی</value>
</data>
</root>
<data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value>
</data>
</root>

View file

@ -132,12 +132,6 @@
<data name="Downloading" xml:space="preserve">
<value>Letöltés...</value>
</data>
<data name="downloadSpeed" xml:space="preserve">
<value>Letöltés</value>
</data>
<data name="DownloadYesNo" xml:space="preserve">
<value>Le szeretné tölteni? {0}</value>
</data>
<data name="FailedConversionConfiguration" xml:space="preserve">
<value>Nem sikerült a konfigurációs fájl átalakítása</value>
</data>
@ -387,9 +381,6 @@
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
<value>A globális billentyűparancs {0} sikeresen bejegyezve</value>
</data>
<data name="UngroupedServers" xml:space="preserve">
<value>Összegyűjtetlen</value>
</data>
<data name="AllGroupServers" xml:space="preserve">
<value>Összes</value>
</data>
@ -822,9 +813,6 @@
<data name="menuWebsiteItem" xml:space="preserve">
<value>{0} Weboldal</value>
</data>
<data name="menuRoutingAdvanced" xml:space="preserve">
<value>Fejlett funkció</value>
</data>
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
<value>Hozzáadás</value>
</data>
@ -843,15 +831,6 @@
<data name="TbdomainStrategy" xml:space="preserve">
<value>Domain stratégia</value>
</data>
<data name="TbRoutingTabBlock" xml:space="preserve">
<value>3. Domain vagy IP blokkolása</value>
</data>
<data name="TbRoutingTabDirect" xml:space="preserve">
<value>2. Közvetlen domain vagy IP</value>
</data>
<data name="TbRoutingTabProxy" xml:space="preserve">
<value>1. Proxy domain vagy IP</value>
</data>
<data name="TbRoutingTabRuleList" xml:space="preserve">
<value>Előre definiált szabálykészletlista</value>
</data>
@ -1341,12 +1320,6 @@
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Kérlek, először állítsd be a sudo jelszót a Tun módban</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Kérlek, ne futtasd ezt az alkalmazást sudo-ként</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mód</value>
</data>
@ -1419,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
<data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value>
</data>
</root>

View file

@ -132,12 +132,6 @@
<data name="Downloading" xml:space="preserve">
<value>Downloading...</value>
</data>
<data name="downloadSpeed" xml:space="preserve">
<value>Download speed</value>
</data>
<data name="DownloadYesNo" xml:space="preserve">
<value>Do you want to download {0}?</value>
</data>
<data name="FailedConversionConfiguration" xml:space="preserve">
<value>Failed to convert configuration file</value>
</data>
@ -387,9 +381,6 @@
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
<value>Global hotkey {0} registered successfully</value>
</data>
<data name="UngroupedServers" xml:space="preserve">
<value>Ungrouped</value>
</data>
<data name="AllGroupServers" xml:space="preserve">
<value>All</value>
</data>
@ -822,9 +813,6 @@
<data name="menuWebsiteItem" xml:space="preserve">
<value>{0} Website</value>
</data>
<data name="menuRoutingAdvanced" xml:space="preserve">
<value>Advanced Function</value>
</data>
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
<value>Add</value>
</data>
@ -843,15 +831,6 @@
<data name="TbdomainStrategy" xml:space="preserve">
<value>Domain strategy</value>
</data>
<data name="TbRoutingTabBlock" xml:space="preserve">
<value>3. Block Domain or IP</value>
</data>
<data name="TbRoutingTabDirect" xml:space="preserve">
<value>2. Direct Domain or IP</value>
</data>
<data name="TbRoutingTabProxy" xml:space="preserve">
<value>1. Proxy Domain or IP</value>
</data>
<data name="TbRoutingTabRuleList" xml:space="preserve">
<value>Pre-defined Rule Set List</value>
</data>
@ -1341,12 +1320,6 @@
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
@ -1419,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
<data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value>
</data>
</root>

View file

@ -132,12 +132,6 @@
<data name="Downloading" xml:space="preserve">
<value>Загрузка...</value>
</data>
<data name="downloadSpeed" xml:space="preserve">
<value>Скорость загрузки</value>
</data>
<data name="DownloadYesNo" xml:space="preserve">
<value>Хотите загрузить {0}?</value>
</data>
<data name="FailedConversionConfiguration" xml:space="preserve">
<value>Не удалось преобразовать файл конфигурации</value>
</data>
@ -387,9 +381,6 @@
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
<value>Глобальная горячая клавиша {0} зарегистрирована успешно</value>
</data>
<data name="UngroupedServers" xml:space="preserve">
<value>Разгруппировано</value>
</data>
<data name="AllGroupServers" xml:space="preserve">
<value>Все серверы</value>
</data>
@ -825,9 +816,6 @@
<data name="menuWebsiteItem" xml:space="preserve">
<value>{0} веб-сайт</value>
</data>
<data name="menuRoutingAdvanced" xml:space="preserve">
<value>Расширенная функция</value>
</data>
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
<value>Добавить</value>
</data>
@ -846,15 +834,6 @@
<data name="TbdomainStrategy" xml:space="preserve">
<value>Доменная стратегия</value>
</data>
<data name="TbRoutingTabBlock" xml:space="preserve">
<value>3.Заблокировать домен или IP</value>
</data>
<data name="TbRoutingTabDirect" xml:space="preserve">
<value>2.Прямой домен или IP</value>
</data>
<data name="TbRoutingTabProxy" xml:space="preserve">
<value>1.Прокси домен или IP</value>
</data>
<data name="TbRoutingTabRuleList" xml:space="preserve">
<value>Предустановленный список наборов правил</value>
</data>
@ -1341,12 +1320,6 @@
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>Введенный вами пароль не может быть подтвержден, поэтому убедитесь, что вы ввели его правильно. Если приложение не работает должным образом из-за неправильного ввода, то перезапустите его. Пароль не будет сохранен, и вам придется вводить его заново после каждого перезапуска</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Сначала задайте пароль sudo в настройках TUN-режима</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Не запускайте программу как суперпользователь</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*XHTTP-режим</value>
</data>
@ -1419,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>URL для тестирования текущего соединения</value>
</data>
</root>
<data name="menuAddAnytlsServer" xml:space="preserve">
<value>Add [Anytls] Configuration</value>
</data>
</root>

View file

@ -132,12 +132,6 @@
<data name="Downloading" xml:space="preserve">
<value>下载开始...</value>
</data>
<data name="downloadSpeed" xml:space="preserve">
<value>下载</value>
</data>
<data name="DownloadYesNo" xml:space="preserve">
<value>是否下载?{0}</value>
</data>
<data name="FailedConversionConfiguration" xml:space="preserve">
<value>转换配置文件失败</value>
</data>
@ -387,9 +381,6 @@
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
<value>注册全局热键 {0} 成功</value>
</data>
<data name="UngroupedServers" xml:space="preserve">
<value>未分组配置文件</value>
</data>
<data name="AllGroupServers" xml:space="preserve">
<value>所有</value>
</data>
@ -822,9 +813,6 @@
<data name="menuWebsiteItem" xml:space="preserve">
<value>{0} 官网</value>
</data>
<data name="menuRoutingAdvanced" xml:space="preserve">
<value>高级功能</value>
</data>
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
<value>添加规则集</value>
</data>
@ -843,15 +831,6 @@
<data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value>
</data>
<data name="TbRoutingTabBlock" xml:space="preserve">
<value>3.阻止的 Domain 或 IP</value>
</data>
<data name="TbRoutingTabDirect" xml:space="preserve">
<value>2.直连的 Domain 或 IP</value>
</data>
<data name="TbRoutingTabProxy" xml:space="preserve">
<value>1.代理的 Domain 或 IP</value>
</data>
<data name="TbRoutingTabRuleList" xml:space="preserve">
<value>预定义规则集列表</value>
</data>
@ -1338,12 +1317,6 @@
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>输入的密码无法校验,所以请确保输入正确。如果因为输入错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在 Tun 模式设置中设置 sudo 密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>请不要用 sudo 运行本程序</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
</data>
@ -1416,4 +1389,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>当前连接信息测试地址</value>
</data>
<data name="menuAddAnytlsServer" xml:space="preserve">
<value>添加 [Anytls] 配置文件</value>
</data>
</root>

View file

@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="BatchExportURLSuccessfully" xml:space="preserve">
<value>匯出分享链接至剪貼簿成功</value>
<value>匯出分享連結至剪貼簿成功</value>
</data>
<data name="CheckServerSettings" xml:space="preserve">
<value>請先檢查設定檔設定</value>
@ -132,12 +132,6 @@
<data name="Downloading" xml:space="preserve">
<value>下載開始...</value>
</data>
<data name="downloadSpeed" xml:space="preserve">
<value>下載</value>
</data>
<data name="DownloadYesNo" xml:space="preserve">
<value>是否下載?{0}</value>
</data>
<data name="FailedConversionConfiguration" xml:space="preserve">
<value>轉換設定檔失敗</value>
</data>
@ -295,7 +289,7 @@
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
</data>
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
<value>掃描匯入分享链接成功</value>
<value>掃描匯入分享連結成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>目前延遲: {0} ms{1}</value>
@ -387,9 +381,6 @@
<data name="RegisterGlobalHotkeySuccessfully" xml:space="preserve">
<value>註冊全域快速鍵 {0} 成功</value>
</data>
<data name="UngroupedServers" xml:space="preserve">
<value>未分組設定檔</value>
</data>
<data name="AllGroupServers" xml:space="preserve">
<value>所有</value>
</data>
@ -481,7 +472,7 @@
<value>語言 (需重啟)</value>
</data>
<data name="menuAddServerViaClipboard" xml:space="preserve">
<value>從剪貼簿導入分享鏈接 (Ctrl+V)</value>
<value>從剪貼簿導入分享連結 (Ctrl+V)</value>
</data>
<data name="menuAddServerViaScan" xml:space="preserve">
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
@ -517,7 +508,7 @@
<value>匯出所選設定檔完整設定</value>
</data>
<data name="menuExport2ShareUrl" xml:space="preserve">
<value>匯出分享链接至剪貼簿 (多選) (Ctrl+C)</value>
<value>匯出分享連結至剪貼簿 (多選) (Ctrl+C)</value>
</data>
<data name="menuAddCustomServer" xml:space="preserve">
<value>新增自訂設定設定檔</value>
@ -822,9 +813,6 @@
<data name="menuWebsiteItem" xml:space="preserve">
<value>{0} 官網</value>
</data>
<data name="menuRoutingAdvanced" xml:space="preserve">
<value>進階功能</value>
</data>
<data name="menuRoutingAdvancedAdd" xml:space="preserve">
<value>新增規則集</value>
</data>
@ -843,15 +831,6 @@
<data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value>
</data>
<data name="TbRoutingTabBlock" xml:space="preserve">
<value>3.阻止的 Domain 或 IP</value>
</data>
<data name="TbRoutingTabDirect" xml:space="preserve">
<value>2.直連的 Domain 或 IP</value>
</data>
<data name="TbRoutingTabProxy" xml:space="preserve">
<value>1.代理的 Domain 或 IP</value>
</data>
<data name="TbRoutingTabRuleList" xml:space="preserve">
<value>預定義規則集列表</value>
</data>
@ -892,7 +871,7 @@
<value>規則詳細說明檔案</value>
</data>
<data name="TbDnsObjectDoc" xml:space="preserve">
<value>支援填寫 DnsObjectJSON 格式,點擊查看明</value>
<value>支援填寫 DnsObjectJSON 格式,點擊查看明</value>
</data>
<data name="SubUrlTips" xml:space="preserve">
<value>普通分組此處請留空</value>
@ -1003,7 +982,7 @@
<value>啟用硬體加速 (需重啟)</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>等待测试中(按 ESC 终止)...</value>
<value>等待測試中(按 ESC 終止)...</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>當有異常斷流時請關閉</value>
@ -1102,10 +1081,10 @@
<value>混淆密碼 (obfs password)</value>
</data>
<data name="TbRuleMatchingTips" xml:space="preserve">
<value>(Domain 或 IP 或 行程名) 与 Port 与 Protocol 与 InboundTag =&gt; OutboundTag</value>
<value>(Domain 或 IP 或 行程名) 與 Port 與 Protocol 與 InboundTag =&gt; OutboundTag</value>
</data>
<data name="TbAutoScrollToEnd" xml:space="preserve">
<value>自动滚动到末尾</value>
<value>自動滾動到末尾</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>真連線測試位址</value>
@ -1201,7 +1180,7 @@
<value>全局</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>原配置</value>
<value>原配置</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>規則</value>
@ -1231,7 +1210,7 @@
<value>自動調整列寬</value>
</data>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>匯出分享链接至剪貼簿 (多選) Base64 编码</value>
<value>匯出分享連結至剪貼簿 (多選) Base64 編碼</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>匯出所選設定檔完整設定至剪貼簿</value>
@ -1267,7 +1246,7 @@
<value>WebDav 伺服器位址</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>WebDav 戶</value>
<value>WebDav 戶</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>WebDav 密碼</value>
@ -1336,13 +1315,7 @@
<value>系統的 sudo 密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會存儲,每次重啟後都需要再次輸入。</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在 Tun 模式設定中設定 sudo 密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>請不要用 sudo 來運行此 App</value>
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會儲存,每次重啟後都需要再次輸入。</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
@ -1366,7 +1339,7 @@
<value>開啟第二個本機監聽埠</value>
</data>
<data name="TbRoutingInboundTagTips" xml:space="preserve">
<value>socks本地端口socks2第二個本地端口socks3區域網路端口</value>
<value>socks本地socks2第二個本地埠socks3區域網路埠</value>
</data>
<data name="TbSettingsTheme" xml:space="preserve">
<value>主題</value>
@ -1387,10 +1360,10 @@
<value>移除無效測試結果 {0} 個。</value>
</data>
<data name="TbPorts7" xml:space="preserve">
<value>跳躍端口範圍</value>
<value>跳躍範圍</value>
</data>
<data name="TbPorts7Tips" xml:space="preserve">
<value>會覆蓋端口,多組時用逗號 (,) 隔開</value>
<value>會覆蓋,多組時用逗號 (,) 隔開</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>多設定檔產生自訂配置 (多選)</value>
@ -1416,4 +1389,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>目前連接資訊測試地址</value>
</data>
<data name="menuAddAnytlsServer" xml:space="preserve">
<value>新增 [Anytls] 設定檔</value>
</data>
</root>

View file

@ -1,4 +1,4 @@
{
{
"log": {
"level": "debug",
"timestamp": true
@ -14,22 +14,10 @@
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
},
{
"tag": "dns_out",
"type": "dns"
}
],
"route": {
"rules": [
{
"protocol": [ "dns" ],
"outbound": "dns_out"
}
]
}
}

View file

@ -2,28 +2,33 @@
"servers": [
{
"tag": "remote",
"address": "tcp://8.8.8.8",
"strategy": "prefer_ipv4",
"type": "tcp",
"server": "8.8.8.8",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"strategy": "prefer_ipv4",
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
"type": "udp",
"server": "223.5.5.5"
}
],
"rules": [
{
"domain_suffix": [
"googleapis.cn",
"gstatic.com"
],
"server": "remote",
"strategy": "prefer_ipv4"
},
{
"rule_set": [
"geosite-cn"
],
"server": "local"
"server": "local",
"strategy": "prefer_ipv4"
}
],
"final": "remote"
"final": "remote",
"strategy": "prefer_ipv4"
}

View file

@ -2,29 +2,33 @@
"servers": [
{
"tag": "remote",
"address": "tcp://8.8.8.8",
"strategy": "prefer_ipv4",
"type": "tcp",
"server": "8.8.8.8",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"strategy": "prefer_ipv4",
"detour": "direct"
},
{
"tag": "block",
"address": "rcode://success"
"type": "udp",
"server": "223.5.5.5"
}
],
"rules": [
{
"rule_set": [
"geosite-cn",
"geosite-geolocation-cn"
"domain_suffix": [
"googleapis.cn",
"gstatic.com"
],
"server": "local"
"server": "remote",
"strategy": "prefer_ipv4"
},
{
"rule_set": [
"geosite-cn"
],
"server": "local",
"strategy": "prefer_ipv4"
}
],
"final": "remote"
}
"final": "remote",
"strategy": "prefer_ipv4"
}

View file

@ -8,13 +8,13 @@
139,
5353
],
"outbound": "block"
"action": "reject"
},
{
"ip_cidr": [
"224.0.0.0/3",
"ff00::/8"
],
"outbound": "block"
"action": "reject"
}
]

View file

@ -1,6 +1,9 @@
using System.Data;
using System.Net;
using System.Net.NetworkInformation;
using System.Reactive;
using DynamicData;
using ServiceLib.Models;
namespace ServiceLib.Services.CoreConfig;
@ -53,7 +56,18 @@ public class CoreConfigSingboxService
await GenInbounds(singboxConfig);
await GenOutbound(node, singboxConfig.outbounds.First());
if (node.ConfigType == EConfigType.WireGuard)
{
singboxConfig.outbounds.RemoveAt(0);
var endpoints = new Endpoints4Sbox();
await GenEndpoint(node, endpoints);
endpoints.tag = Global.ProxyTag;
singboxConfig.endpoints = new() { endpoints };
}
else
{
await GenOutbound(node, singboxConfig.outbounds.First());
}
await GenMoreOutbounds(node, singboxConfig);
@ -202,16 +216,29 @@ public class CoreConfigSingboxService
continue;
}
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.listen_port.ToString();
singboxConfig.outbounds.Add(outbound);
var server = await GenServer(item);
if (server is null)
{
ret.Msg = ResUI.FailedGenDefaultConfiguration;
return ret;
}
var tag = Global.ProxyTag + inbound.listen_port.ToString();
server.tag = tag;
if (server is Endpoints4Sbox endpoint)
{
singboxConfig.endpoints ??= new();
singboxConfig.endpoints.Add(endpoint);
}
else if (server is Outbound4Sbox outbound)
{
singboxConfig.outbounds.Add(outbound);
}
//rule
Rule4Sbox rule = new()
{
inbound = new List<string> { inbound.tag },
outbound = outbound.tag
outbound = tag
};
singboxConfig.route.rules.Add(rule);
}
@ -275,7 +302,18 @@ public class CoreConfigSingboxService
}
await GenLog(singboxConfig);
await GenOutbound(node, singboxConfig.outbounds.First());
if (node.ConfigType == EConfigType.WireGuard)
{
singboxConfig.outbounds.RemoveAt(0);
var endpoints = new Endpoints4Sbox();
await GenEndpoint(node, endpoints);
endpoints.tag = Global.ProxyTag;
singboxConfig.endpoints = new() { endpoints };
}
else
{
await GenOutbound(node, singboxConfig.outbounds.First());
}
await GenMoreOutbounds(node, singboxConfig);
await GenDnsDomains(null, singboxConfig, null);
@ -534,15 +572,6 @@ public class CoreConfigSingboxService
singboxConfig.inbounds.Add(inbound);
inbound.listen_port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
inbound.sniff = _config.Inbound.First().SniffingEnabled;
inbound.sniff_override_destination = _config.Inbound.First().RouteOnly ? false : _config.Inbound.First().SniffingEnabled;
inbound.domain_strategy = _config.RoutingBasicItem.DomainStrategy4Singbox.IsNullOrEmpty() ? null : _config.RoutingBasicItem.DomainStrategy4Singbox;
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing.DomainStrategy4Singbox.IsNotEmpty())
{
inbound.domain_strategy = routing.DomainStrategy4Singbox;
}
if (_config.Inbound.First().SecondLocalPortEnabled)
{
@ -587,8 +616,6 @@ public class CoreConfigSingboxService
tunInbound.mtu = _config.TunModeItem.Mtu;
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
tunInbound.stack = _config.TunModeItem.Stack;
tunInbound.sniff = _config.Inbound.First().SniffingEnabled;
//tunInbound.sniff_override_destination = _config.inbound.First().routeOnly ? false : _config.inbound.First().sniffingEnabled;
if (_config.TunModeItem.EnableIPv6Address == false)
{
tunInbound.address = ["172.18.0.1/30"];
@ -621,6 +648,17 @@ public class CoreConfigSingboxService
outbound.server_port = node.Port;
outbound.type = Global.ProtocolTypes[node.ConfigType];
if (Utils.IsDomain(node.Address))
{
var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
var localDnsAddress = string.IsNullOrEmpty(item?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : item?.DomainDNSAddress;
outbound.domain_resolver = new()
{
server = localDnsAddress.StartsWith("tag://") ? localDnsAddress.Substring(6) : "local_resolver",
strategy = string.IsNullOrEmpty(item?.DomainStrategy4Freedom) ? null : item?.DomainStrategy4Freedom
};
}
switch (node.ConfigType)
{
case EConfigType.VMess:
@ -725,13 +763,9 @@ public class CoreConfigSingboxService
outbound.congestion_control = node.HeaderType;
break;
}
case EConfigType.WireGuard:
case EConfigType.Anytls:
{
outbound.private_key = node.Id;
outbound.peer_public_key = node.PublicKey;
outbound.reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList();
outbound.local_address = Utils.String2List(node.RequestHost);
outbound.mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt();
outbound.password = node.Id;
break;
}
}
@ -747,6 +781,76 @@ public class CoreConfigSingboxService
return 0;
}
private async Task<int> GenEndpoint(ProfileItem node, Endpoints4Sbox endpoint)
{
try
{
endpoint.address = Utils.String2List(node.RequestHost);
endpoint.type = Global.ProtocolTypes[node.ConfigType];
if (Utils.IsDomain(node.Address))
{
var item = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
var localDnsAddress = string.IsNullOrEmpty(item?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : item?.DomainDNSAddress;
endpoint.domain_resolver = new()
{
server = localDnsAddress.StartsWith("tag://") ? localDnsAddress.Substring(6) : "local_resolver",
strategy = string.IsNullOrEmpty(item?.DomainStrategy4Freedom) ? null : item?.DomainStrategy4Freedom
};
}
switch (node.ConfigType)
{
case EConfigType.WireGuard:
{
var peer = new Peer4Sbox
{
public_key = node.PublicKey,
reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList(),
address = node.Address,
port = node.Port,
// TODO default ["0.0.0.0/0", "::/0"]
allowed_ips = new() { "0.0.0.0/0", "::/0" },
};
endpoint.private_key = node.Id;
endpoint.mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt();
endpoint.peers = new() { peer };
break;
}
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return await Task.FromResult(0);
}
private async Task<BaseServer4Sbox?> GenServer(ProfileItem node)
{
try
{
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
if (node.ConfigType == EConfigType.WireGuard)
{
var endpoint = JsonUtils.Deserialize<Endpoints4Sbox>(txtOutbound);
await GenEndpoint(node, endpoint);
return endpoint;
}
else
{
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(node, outbound);
return outbound;
}
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
return await Task.FromResult<BaseServer4Sbox?>(null);
}
private async Task<int> GenOutboundMux(ProfileItem node, Outbound4Sbox outbound)
{
try
@ -913,7 +1017,8 @@ public class CoreConfigSingboxService
}
//current proxy
var outbound = singboxConfig.outbounds.First();
BaseServer4Sbox? outbound = singboxConfig.endpoints?.FirstOrDefault(t => t.tag == Global.ProxyTag) == null ? singboxConfig.outbounds.First() : null;
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
//Previous proxy
@ -922,17 +1027,32 @@ public class CoreConfigSingboxService
if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom)
{
var prevOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(prevNode, prevOutbound);
prevOutboundTag = $"prev-{Global.ProxyTag}";
prevOutbound.tag = prevOutboundTag;
singboxConfig.outbounds.Add(prevOutbound);
var prevServer = await GenServer(prevNode);
prevServer.tag = prevOutboundTag;
if (prevServer is Endpoints4Sbox endpoint)
{
singboxConfig.endpoints ??= new();
singboxConfig.endpoints.Add(endpoint);
}
else if (prevServer is Outbound4Sbox outboundPrev)
{
singboxConfig.outbounds.Add(outboundPrev);
}
}
var nextOutbound = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
var nextServer = await GenChainOutbounds(subItem, outbound, prevOutboundTag);
if (nextOutbound is not null)
if (nextServer is not null)
{
singboxConfig.outbounds.Insert(0, nextOutbound);
if (nextServer is Endpoints4Sbox endpoint)
{
singboxConfig.endpoints ??= new();
singboxConfig.endpoints.Insert(0, endpoint);
}
else if (nextServer is Outbound4Sbox outboundNext)
{
singboxConfig.outbounds.Insert(0, outboundNext);
}
}
}
catch (Exception ex)
@ -955,11 +1075,13 @@ public class CoreConfigSingboxService
}
var resultOutbounds = new List<Outbound4Sbox>();
var resultEndpoints = new List<Endpoints4Sbox>(); // For endpoints
var prevOutbounds = new List<Outbound4Sbox>(); // Separate list for prev outbounds
var prevEndpoints = new List<Endpoints4Sbox>(); // Separate list for prev endpoints
var proxyTags = new List<string>(); // For selector and urltest outbounds
// Cache for chain proxies to avoid duplicate generation
var nextProxyCache = new Dictionary<string, Outbound4Sbox?>();
var nextProxyCache = new Dictionary<string, BaseServer4Sbox?>();
var prevProxyTags = new Dictionary<string, string?>(); // Map from profile name to tag
int prevIndex = 0; // Index for prev outbounds
@ -971,19 +1093,18 @@ public class CoreConfigSingboxService
// Handle proxy chain
string? prevTag = null;
var currentOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
var nextOutbound = nextProxyCache.GetValueOrDefault(node.Subid, null);
if (nextOutbound != null)
var currentServer = await GenServer(node);
var nextServer = nextProxyCache.GetValueOrDefault(node.Subid, null);
if (nextServer != null)
{
nextOutbound = JsonUtils.DeepCopy(nextOutbound);
nextServer = JsonUtils.DeepCopy(nextServer);
}
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
// current proxy
await GenOutbound(node, currentOutbound);
currentOutbound.tag = $"{Global.ProxyTag}-{index}";
proxyTags.Add(currentOutbound.tag);
currentServer.tag = $"{Global.ProxyTag}-{index}";
proxyTags.Add(currentServer.tag);
if (!node.Subid.IsNullOrEmpty())
{
@ -1006,18 +1127,32 @@ public class CoreConfigSingboxService
prevProxyTags[node.Subid] = prevTag;
}
nextOutbound = await GenChainOutbounds(subItem, currentOutbound, prevTag, nextOutbound);
nextServer = await GenChainOutbounds(subItem, currentServer, prevTag, nextServer);
if (!nextProxyCache.ContainsKey(node.Subid))
{
nextProxyCache[node.Subid] = nextOutbound;
nextProxyCache[node.Subid] = nextServer;
}
}
if (nextOutbound is not null)
if (nextServer is not null)
{
resultOutbounds.Add(nextOutbound);
if (nextServer is Endpoints4Sbox nextEndpoint)
{
resultEndpoints.Add(nextEndpoint);
}
else if (nextServer is Outbound4Sbox nextOutbound)
{
resultOutbounds.Add(nextOutbound);
}
}
if (currentServer is Endpoints4Sbox currentEndpoint)
{
resultEndpoints.Add(currentEndpoint);
}
else if (currentServer is Outbound4Sbox currentOutbound)
{
resultOutbounds.Add(currentOutbound);
}
resultOutbounds.Add(currentOutbound);
}
// Add urltest outbound (auto selection based on latency)
@ -1050,6 +1185,9 @@ public class CoreConfigSingboxService
resultOutbounds.AddRange(prevOutbounds);
resultOutbounds.AddRange(singboxConfig.outbounds);
singboxConfig.outbounds = resultOutbounds;
singboxConfig.endpoints ??= new List<Endpoints4Sbox>();
resultEndpoints.AddRange(singboxConfig.endpoints);
singboxConfig.endpoints = resultEndpoints;
}
catch (Exception ex)
{
@ -1071,7 +1209,7 @@ public class CoreConfigSingboxService
/// <returns>
/// The outbound configuration for the next proxy in the chain, or null if no next proxy exists.
/// </returns>
private async Task<Outbound4Sbox?> GenChainOutbounds(SubItem subItem, Outbound4Sbox outbound, string? prevOutboundTag, Outbound4Sbox? nextOutbound = null)
private async Task<BaseServer4Sbox?> GenChainOutbounds(SubItem subItem, BaseServer4Sbox outbound, string? prevOutboundTag, BaseServer4Sbox? nextOutbound = null)
{
try
{
@ -1087,11 +1225,7 @@ public class CoreConfigSingboxService
if (nextNode is not null
&& nextNode.ConfigType != EConfigType.Custom)
{
if (nextOutbound == null)
{
nextOutbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(nextNode, nextOutbound);
}
nextOutbound ??= await GenServer(nextNode);
nextOutbound.tag = outbound.tag;
outbound.tag = $"mid-{outbound.tag}";
@ -1110,7 +1244,7 @@ public class CoreConfigSingboxService
{
try
{
var dnsOutbound = "dns_out";
singboxConfig.route.final = Global.ProxyTag;
if (_config.TunModeItem.EnableTun)
{
@ -1126,7 +1260,7 @@ public class CoreConfigSingboxService
singboxConfig.route.rules.Add(new()
{
port = new() { 53 },
outbound = dnsOutbound,
action = "hijack-dns",
process_name = lstDnsExe
});
@ -1137,13 +1271,25 @@ public class CoreConfigSingboxService
});
}
if (!_config.Inbound.First().SniffingEnabled)
if (_config.Inbound.First().SniffingEnabled)
{
singboxConfig.route.rules.Add(new()
{
port = [53],
network = ["udp"],
outbound = dnsOutbound
action = "sniff"
});
singboxConfig.route.rules.Add(new()
{
protocol = new() { "dns" },
action = "hijack-dns"
});
}
else
{
singboxConfig.route.rules.Add(new()
{
port = new() { 53 },
network = new() { "udp" },
action = "hijack-dns"
});
}
@ -1158,7 +1304,24 @@ public class CoreConfigSingboxService
clash_mode = ERuleMode.Global.ToString()
});
var domainStrategy = _config.RoutingBasicItem.DomainStrategy4Singbox.IsNullOrEmpty() ? null : _config.RoutingBasicItem.DomainStrategy4Singbox;
var defaultRouting = await ConfigHandler.GetDefaultRouting(_config);
if (defaultRouting.DomainStrategy4Singbox.IsNotEmpty())
{
domainStrategy = defaultRouting.DomainStrategy4Singbox;
}
var resolveRule = new Rule4Sbox
{
action = "resolve",
strategy = domainStrategy
};
if (_config.RoutingBasicItem.DomainStrategy == "IPOnDemand")
{
singboxConfig.route.rules.Add(resolveRule);
}
var routing = await ConfigHandler.GetDefaultRouting(_config);
var ipRules = new List<RulesItem>();
if (routing != null)
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
@ -1167,9 +1330,21 @@ public class CoreConfigSingboxService
if (item.Enabled)
{
await GenRoutingUserRule(item, singboxConfig.route.rules);
if (item.Ip != null && item.Ip.Count > 0)
{
ipRules.Add(item);
}
}
}
}
if (_config.RoutingBasicItem.DomainStrategy == "IPIfNonMatch")
{
singboxConfig.route.rules.Add(resolveRule);
foreach (var item in ipRules)
{
await GenRoutingUserRule(item, singboxConfig.route.rules);
}
}
}
catch (Exception ex)
{
@ -1215,10 +1390,15 @@ public class CoreConfigSingboxService
return 0;
}
var rule = new Rule4Sbox()
var rule = new Rule4Sbox();
if (item.OutboundTag == "block")
{
outbound = item.OutboundTag,
};
rule.action = "reject";
}
else
{
rule.outbound = item.OutboundTag;
}
if (item.Port.IsNotEmpty())
{
@ -1342,24 +1522,28 @@ public class CoreConfigSingboxService
{
return false;
}
else if (address.StartsWith("geoip:!"))
{
return false;
}
else if (address.Equals("geoip:private"))
{
rule.ip_is_private = true;
}
else if (address.StartsWith("geoip:"))
{
if (rule.geoip is null)
{ rule.geoip = new(); }
rule.geoip ??= new();
rule.geoip?.Add(address.Substring(6));
}
else if (address.Equals("geoip:!private"))
{
rule.ip_is_private = false;
}
else if (address.StartsWith("geoip:!"))
{
rule.geoip ??= new();
rule.geoip?.Add(address.Substring(6));
rule.invert = true;
}
else
{
if (rule.ip_cidr is null)
{ rule.ip_cidr = new(); }
rule.ip_cidr ??= new();
rule.ip_cidr?.Add(address);
}
return true;
@ -1387,7 +1571,14 @@ public class CoreConfigSingboxService
}
singboxConfig.dns = dns4Sbox;
await GenDnsDomains(node, singboxConfig, item);
if (dns4Sbox.servers != null && dns4Sbox.servers.Count > 0 && dns4Sbox.servers.First().address.IsNullOrEmpty())
{
await GenDnsDomains(node, singboxConfig, item);
}
else
{
await GenDnsDomainsLegacy(node, singboxConfig, item);
}
}
catch (Exception ex)
{
@ -1402,6 +1593,75 @@ public class CoreConfigSingboxService
dns4Sbox.servers ??= [];
dns4Sbox.rules ??= [];
var tag = "local_resolver";
var localDnsAddress = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.SingboxDomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress;
if (localDnsAddress.StartsWith("tag://"))
{
tag = localDnsAddress.Substring(6);
var localDnsTag = "local_local";
dns4Sbox.servers.Add(new()
{
tag = localDnsTag,
type = "local"
});
dns4Sbox.rules.Insert(0, new()
{
server = localDnsTag,
clash_mode = ERuleMode.Direct.ToString()
});
}
else
{
var (dnsType, dnsHost, dnsPort, dnsPath) = ParseDnsAddress(localDnsAddress);
dns4Sbox.servers.Add(new()
{
tag = tag,
type = dnsType,
server = dnsHost,
Interface = dnsType == "dhcp" ? dnsHost : null,
server_port = dnsPort,
path = dnsPath
});
dns4Sbox.rules.Insert(0, new()
{
server = tag,
clash_mode = ERuleMode.Direct.ToString()
});
}
dns4Sbox.rules.Insert(0, new()
{
server = dns4Sbox.servers.Where(t => t.detour == Global.ProxyTag).Select(t => t.tag).FirstOrDefault() ?? "remote",
clash_mode = ERuleMode.Global.ToString()
});
//Tun2SocksAddress
if (_config.TunModeItem.EnableTun && node?.ConfigType == EConfigType.SOCKS && Utils.IsDomain(node?.Sni))
{
dns4Sbox.rules.Insert(0, new()
{
server = tag,
domain = [node?.Sni],
strategy = string.IsNullOrEmpty(dNSItem?.DomainStrategy4Freedom) ? null : dNSItem?.DomainStrategy4Freedom
});
}
singboxConfig.dns = dns4Sbox;
return await Task.FromResult(0);
}
private async Task<int> GenDnsDomainsLegacy(ProfileItem? node, SingboxConfig singboxConfig, DNSItem? dNSItem)
{
var dns4Sbox = singboxConfig.dns ?? new();
dns4Sbox.servers ??= [];
dns4Sbox.rules ??= [];
var tag = "local_local";
dns4Sbox.servers.Add(new()
{
@ -1449,6 +1709,91 @@ public class CoreConfigSingboxService
return await Task.FromResult(0);
}
private (string type, string? host, int? port, string? path) ParseDnsAddress(string address)
{
string type = "udp";
string? host = null;
int? port = null;
string? path = null;
if (address is "local" or "localhost")
{
return ("local", null, null, null);
}
if (address.StartsWith("dhcp://", StringComparison.OrdinalIgnoreCase))
{
string interface_name = address.Substring(7);
return ("dhcp", interface_name == "auto" ? null : interface_name, null, null);
}
if (!address.Contains("://"))
{
// udp dns
host = address;
return (type, host, port, path);
}
try
{
int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal);
type = address.Substring(0, protocolEndIndex).ToLower();
var uri = new Uri(address);
host = uri.Host;
if (!uri.IsDefaultPort)
{
port = uri.Port;
}
if ((type == "https" || type == "h3") && !string.IsNullOrEmpty(uri.AbsolutePath) && uri.AbsolutePath != "/")
{
path = uri.AbsolutePath;
}
}
catch (UriFormatException)
{
int protocolEndIndex = address.IndexOf("://", StringComparison.Ordinal);
if (protocolEndIndex > 0)
{
type = address.Substring(0, protocolEndIndex).ToLower();
string remaining = address.Substring(protocolEndIndex + 3);
int portIndex = remaining.IndexOf(':');
int pathIndex = remaining.IndexOf('/');
if (portIndex > 0)
{
host = remaining.Substring(0, portIndex);
string portPart = pathIndex > portIndex
? remaining.Substring(portIndex + 1, pathIndex - portIndex - 1)
: remaining.Substring(portIndex + 1);
if (int.TryParse(portPart, out int parsedPort))
{
port = parsedPort;
}
}
else if (pathIndex > 0)
{
host = remaining.Substring(0, pathIndex);
}
else
{
host = remaining;
}
if (pathIndex > 0 && (type == "https" || type == "h3"))
{
path = remaining.Substring(pathIndex);
}
}
}
return (type, host, port, path);
}
private async Task<int> GenExperimental(SingboxConfig singboxConfig)
{
//if (_config.guiItem.enableStatistics)

View file

@ -1322,7 +1322,8 @@ public class CoreConfigV2rayService
if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2
&& prevNode.ConfigType != EConfigType.TUIC)
&& prevNode.ConfigType != EConfigType.TUIC
&& prevNode.ConfigType != EConfigType.Anytls)
{
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(prevNode, prevOutbound);
@ -1397,7 +1398,8 @@ public class CoreConfigV2rayService
if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2
&& prevNode.ConfigType != EConfigType.TUIC)
&& prevNode.ConfigType != EConfigType.TUIC
&& prevNode.ConfigType != EConfigType.Anytls)
{
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(prevNode, prevOutbound);
@ -1466,7 +1468,8 @@ public class CoreConfigV2rayService
if (nextNode is not null
&& nextNode.ConfigType != EConfigType.Custom
&& nextNode.ConfigType != EConfigType.Hysteria2
&& nextNode.ConfigType != EConfigType.TUIC)
&& nextNode.ConfigType != EConfigType.TUIC
&& nextNode.ConfigType != EConfigType.Anytls)
{
if (nextOutbound == null)
{

View file

@ -358,8 +358,8 @@ public class SpeedtestService
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
{
List<List<ServerTestItem>> lstTest = new();
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC)).ToList();
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC).ToList();
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls)).ToList();
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.Anytls).ToList();
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
{

View file

@ -20,6 +20,7 @@ public class MainWindowViewModel : MyReactiveObject
public ReactiveCommand<Unit, Unit> AddHysteria2ServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddTuicServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
public ReactiveCommand<Unit, Unit> AddServerViaClipboardCmd { get; }
public ReactiveCommand<Unit, Unit> AddServerViaScanCmd { get; }
@ -111,6 +112,10 @@ public class MainWindowViewModel : MyReactiveObject
{
await AddServerAsync(true, EConfigType.WireGuard);
});
AddAnytlsServerCmd = ReactiveCommand.CreateFromTask(async () =>
{
await AddServerAsync(true, EConfigType.Anytls);
});
AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () =>
{
await AddServerAsync(true, EConfigType.Custom);

View file

@ -91,11 +91,9 @@ public class RoutingSettingViewModel : MyReactiveObject
var routings = await AppHandler.Instance.RoutingItems();
foreach (var item in routings)
{
var def = item.Id == _config.RoutingBasicItem.RoutingIndexId;
var it = new RoutingItemModel()
{
IsActive = def,
IsActive = item.IsActive,
RuleNum = item.RuleNum,
Id = item.Id,
Remarks = item.Remarks,

View file

@ -372,7 +372,7 @@ public class StatusBarViewModel : MyReactiveObject
foreach (var item in routings)
{
_routingItems.Add(item);
if (item.Id == _config.RoutingBasicItem.RoutingIndexId)
if (item.IsActive)
{
SelectedRouting = item;
}
@ -396,10 +396,6 @@ public class StatusBarViewModel : MyReactiveObject
{
return;
}
if (_config.RoutingBasicItem.RoutingIndexId == item.Id)
{
return;
}
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
{

View file

@ -30,7 +30,7 @@ public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewMode
Height = sizeItem.Height;
var workingArea = (Screens.ScreenFromWindow(this) ?? Screens.Primary).WorkingArea;
var scaling = VisualRoot is not null ? VisualRoot.RenderScaling : 1.0;
var scaling = (Utils.IsOSX() ? null : VisualRoot?.RenderScaling) ?? 1.0;
var x = workingArea.X + ((workingArea.Width - (Width * scaling)) / 2);
var y = workingArea.Y + ((workingArea.Height - (Height * scaling)) / 2);

View file

@ -533,6 +533,26 @@
HorizontalAlignment="Left"
Watermark="1500" />
</Grid>
<Grid
x:Name="gridAnytls"
Grid.Row="2"
ColumnDefinitions="180,Auto"
IsVisible="False"
RowDefinitions="Auto,Auto,Auto">
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbId3}" />
<TextBox
x:Name="txtId10"
Grid.Row="1"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}" />
</Grid>
<Separator
x:Name="sepa2"

View file

@ -133,6 +133,11 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
gridTls.IsVisible = false;
break;
case EConfigType.Anytls:
gridAnytls.IsVisible = true;
cmbCoreType.IsEnabled = false;
break;
}
gridTlsMore.IsVisible = false;
@ -197,6 +202,10 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost9.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId9.Text).DisposeWith(disposables);
break;
case EConfigType.Anytls:
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId10.Text).DisposeWith(disposables);
break;
}
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables);

View file

@ -46,6 +46,7 @@
<Separator />
<MenuItem x:Name="menuAddHysteria2Server" Header="{x:Static resx:ResUI.menuAddHysteria2Server}" />
<MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" />
<MenuItem x:Name="menuAddAnytlsServer" Header="{x:Static resx:ResUI.menuAddAnytlsServer}" />
</MenuItem>
<MenuItem Padding="8,0">

View file

@ -83,6 +83,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).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.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
@ -134,20 +135,19 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
break;
}
});
this.Title = $"{Utils.GetVersion()}";
if (Utils.IsWindows())
{
this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
}
else
{
if (Utils.IsAdministrator())
{
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
}
this.Title = $"{Utils.GetVersion()}";
menuRebootAsAdmin.IsVisible = false;
menuSettingsSetUWP.IsVisible = false;
menuGlobalHotkeySetting.IsVisible = false;
@ -464,13 +464,11 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
{
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
}
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
{
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
}
}

View file

@ -31,12 +31,6 @@
HorizontalAlignment="Right"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<StackPanel
Width="600"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<TextBlock Text="{x:Static resx:ResUI.TbRoutingTips}" />
</StackPanel>
<Button
x:Name="btnSave"
Width="100"

View file

@ -85,7 +85,6 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
case EViewAction.PasswordInput:
return await PasswordInputAsync();
break;
}
return await Task.FromResult(true);
}

View file

@ -707,6 +707,35 @@
materialDesign:HintAssist.Hint="1500"
Style="{StaticResource DefTextBox}" />
</Grid>
<Grid
x:Name="gridAnytls"
Grid.Row="2"
Visibility="Hidden">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" />
<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.TbId3}" />
<TextBox
x:Name="txtId10"
Grid.Row="1"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefTextBox}" />
</Grid>
<Separator
x:Name="sepa2"

View file

@ -126,6 +126,11 @@ public partial class AddServerWindow
gridTransport.Visibility = Visibility.Collapsed;
gridTls.Visibility = Visibility.Collapsed;
break;
case EConfigType.Anytls:
gridAnytls.Visibility = Visibility.Visible;
cmbCoreType.IsEnabled = false;
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
break;
}
@ -191,6 +196,10 @@ public partial class AddServerWindow
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost9.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.ShortId, v => v.txtShortId9.Text).DisposeWith(disposables);
break;
case EConfigType.Anytls:
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId10.Text).DisposeWith(disposables);
break;
}
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.Text).DisposeWith(disposables);

View file

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

View file

@ -80,6 +80,7 @@ public partial class MainWindow
this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).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.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
@ -423,13 +424,11 @@ public partial class MainWindow
if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
{
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
}
else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
{
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
}
}

View file

@ -57,12 +57,6 @@
HorizontalAlignment="Right"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<StackPanel
Width="600"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<TextBlock Style="{StaticResource ToolbarTextBlock}" Text="{x:Static resx:ResUI.TbRoutingTips}" />
</StackPanel>
<Button
x:Name="btnSave"
Width="100"