Compare commits

..

13 commits

Author SHA1 Message Date
DHR60
4ef6b2dac6 Refactor, use record instead of class 2026-01-21 21:19:07 +08:00
2dust
fb6977734f Refactor ProfileItem protocol extra handling 2026-01-21 20:59:10 +08:00
DHR60
c8922dd23b Refactor 2026-01-21 19:48:41 +08:00
DHR60
017593cca3 Fix 2026-01-21 15:53:59 +08:00
DHR60
951ab1194a Fix hy2 migrate 2026-01-21 12:23:40 +08:00
DHR60
c2fcc0e117 Remove unused code 2026-01-21 12:21:47 +08:00
DHR60
20a6a3b823 Fix warning CS0618 2026-01-21 12:15:21 +08:00
DHR60
c769c89211 Fix hy2 bbr 2026-01-21 12:11:06 +08:00
DHR60
93d45612d9 Refactor flow 2026-01-21 12:03:23 +08:00
DHR60
c5d56df3a8 Refactor id and security 2026-01-21 11:58:29 +08:00
DHR60
6029b7ad85 Upgrade config version and rename 2026-01-21 10:44:46 +08:00
DHR60
7ff40f3730 Add hysteria2 bandwidth and hop interval support 2026-01-19 12:38:19 +08:00
DHR60
25967615d6 Refactor 2026-01-19 12:38:19 +08:00
44 changed files with 469 additions and 919 deletions

View file

@ -31,7 +31,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.1
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'
@ -103,67 +103,14 @@ jobs:
steps: steps:
- name: Prepare tools (Red Hat) - name: Prepare tools (Red Hat)
shell: bash
run: | run: |
set -euo pipefail dnf repolist all
dnf -y makecache
. /etc/os-release dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm
EL_MAJOR="${VERSION_ID%%.*}" dnf -y install sudo git rpm-build rpmdevtools dnf-plugins-core rsync findutils tar gzip unzip which
echo "EL_MAJOR=${EL_MAJOR}"
dnf -y makecache || true
command -v curl >/dev/null || dnf -y install curl ca-certificates
ARCH="$(uname -m)"
case "$ARCH" in x86_64|aarch64) ;; *) echo "Unsupported arch: $ARCH"; exit 1 ;; esac
install_epel_from_dir() {
local base="$1" rpm
echo "Try: $base"
rpm="$(
{
curl -fsSL "$base/Packages/" 2>/dev/null
curl -fsSL "$base/Packages/e/" 2>/dev/null | sed 's|href="|href="e/|'
} |
sed -n 's/.*href="\([^"]*epel-release-[^"]*\.noarch\.rpm\)".*/\1/p' |
sort -V | tail -n1
)" || true
if [[ -n "$rpm" ]]; then
dnf -y install "$base/Packages/$rpm"
return 0
fi
return 1
}
FEDORA="https://dl.fedoraproject.org/pub/epel/epel-release-latest-${EL_MAJOR}.noarch.rpm"
echo "Try Fedora: $FEDORA"
if curl -fsSLI "$FEDORA" >/dev/null; then
dnf -y install "$FEDORA"
else
ROCKY="https://dl.rockylinux.org/pub/rocky/${EL_MAJOR}/extras/${ARCH}/os"
if install_epel_from_dir "$ROCKY"; then
:
else
ALMA="https://repo.almalinux.org/almalinux/${EL_MAJOR}/extras/${ARCH}/os"
if install_epel_from_dir "$ALMA"; then
:
else
echo "EPEL bootstrap failed (Fedora/Rocky/Alma)"
exit 1
fi
fi
fi
dnf -y install sudo git rpm-build rpmdevtools dnf-plugins-core \
rsync findutils tar gzip unzip which
dnf repolist | grep -i epel || true
- name: Checkout repo (for scripts) - name: Checkout repo (for scripts)
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.1
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'

View file

@ -26,7 +26,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.1
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'

View file

@ -26,7 +26,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.1
with: with:
submodules: 'recursive' submodules: 'recursive'
fetch-depth: '0' fetch-depth: '0'

View file

@ -15,6 +15,7 @@ env:
OutputArchArm: "windows-arm64" OutputArchArm: "windows-arm64"
OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64" OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64"
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64" OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64"
OutputPath64Sc: "${{ github.workspace }}/v2rayN/Release/windows-64-SelfContained"
jobs: jobs:
build: build:
@ -26,7 +27,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.1
- name: Setup - name: Setup
uses: actions/setup-dotnet@v5.0.1 uses: actions/setup-dotnet@v5.0.1
@ -38,8 +39,11 @@ jobs:
cd v2rayN cd v2rayN
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64 dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64 dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc
- name: Upload build artifacts - name: Upload build artifacts
uses: actions/upload-artifact@v6.0.0 uses: actions/upload-artifact@v6.0.0
@ -55,6 +59,7 @@ jobs:
chmod 755 package-release-zip.sh chmod 755 package-release-zip.sh
./package-release-zip.sh $OutputArch $OutputPath64 ./package-release-zip.sh $OutputArch $OutputPath64
./package-release-zip.sh $OutputArchArm $OutputPathArm64 ./package-release-zip.sh $OutputArchArm $OutputPathArm64
./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc
- name: Upload zip archive to release - name: Upload zip archive to release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2

View file

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.18.0</Version> <Version>7.17.1</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -5,7 +5,7 @@
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled> <CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.4.0" /> <PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.3.0" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.11" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.11" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.11" /> <PackageVersion Include="Avalonia.Desktop" Version="11.3.11" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.11" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.3.11" />
@ -22,7 +22,7 @@
<PackageVersion Include="Semi.Avalonia" Version="11.3.7.2" /> <PackageVersion Include="Semi.Avalonia" Version="11.3.7.2" />
<PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" /> <PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.2" /> <PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.2" />
<PackageVersion Include="NLog" Version="6.1.0" /> <PackageVersion Include="NLog" Version="6.0.7" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" /> <PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.2" /> <PackageVersion Include="TaskScheduler" Version="2.12.2" />
<PackageVersion Include="WebDav.Client" Version="2.9.0" /> <PackageVersion Include="WebDav.Client" Version="2.9.0" />

View file

@ -94,28 +94,4 @@ public static class Extension
{ {
return configType is EConfigType.Custom or EConfigType.PolicyGroup or EConfigType.ProxyChain; return configType is EConfigType.Custom or EConfigType.PolicyGroup or EConfigType.ProxyChain;
} }
/// <summary>
/// Safely adds elements from a collection to the list. Does nothing if the source is null.
/// </summary>
public static void AddRangeSafe<T>(this ICollection<T> destination, IEnumerable<T>? source)
{
ArgumentNullException.ThrowIfNull(destination);
if (source is null)
{
return;
}
if (destination is List<T> list)
{
list.AddRange(source);
return;
}
foreach (var item in source)
{
destination.Add(item);
}
}
} }

View file

@ -462,18 +462,6 @@ public class Utils
return (domain, port); return (domain, port);
} }
public static string? DomainStrategy4Sbox(string? strategy)
{
return strategy switch
{
not null when strategy.StartsWith("UseIPv4") => "prefer_ipv4",
not null when strategy.StartsWith("UseIPv6") => "prefer_ipv6",
not null when strategy.StartsWith("ForceIPv4") => "ipv4_only",
not null when strategy.StartsWith("ForceIPv6") => "ipv6_only",
_ => null
};
}
#endregion Conversion Functions #endregion Conversion Functions
#region Data Checks #region Data Checks
@ -517,31 +505,6 @@ public class Utils
return false; return false;
} }
public static bool IsIpAddress(string? ip)
{
if (ip.IsNullOrEmpty())
{
return false;
}
ip = ip.Trim();
// First, validate using built-in parser
if (!IPAddress.TryParse(ip, out var address))
{
return false;
}
// For IPv4: ensure it has exactly 3 dots (meaning 4 parts)
if (address.AddressFamily == AddressFamily.InterNetwork)
{
return ip.Count(c => c == '.') == 3;
}
// For IPv6: TryParse is already strict enough
return address.AddressFamily == AddressFamily.InterNetworkV6;
}
public static Uri? TryUri(string url) public static Uri? TryUri(string url)
{ {
try try
@ -756,65 +719,33 @@ public class Utils
return Guid.TryParse(strSrc, out _); return Guid.TryParse(strSrc, out _);
} }
private static Dictionary<string, string> GetSystemHosts(string hostFile) public static Dictionary<string, string> GetSystemHosts()
{ {
var systemHosts = new Dictionary<string, string>(); var systemHosts = new Dictionary<string, string>();
var hostFile = @"C:\Windows\System32\drivers\etc\hosts";
try try
{ {
if (!File.Exists(hostFile)) if (File.Exists(hostFile))
{ {
return systemHosts; var hosts = File.ReadAllText(hostFile).Replace("\r", "");
var hostsList = hosts.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var host in hostsList)
{
if (host.StartsWith("#"))
{
continue;
}
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (hostItem.Length < 2)
{
continue;
}
systemHosts.Add(hostItem[1], hostItem[0]);
}
} }
var hosts = File.ReadAllText(hostFile).Replace("\r", "");
var hostsList = hosts.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var host in hostsList)
{
// Trim whitespace
var line = host.Trim();
// Skip comments and empty lines
if (line.IsNullOrEmpty() || line.StartsWith("#"))
{
continue;
}
// Strip inline comments
var commentIndex = line.IndexOf('#');
if (commentIndex >= 0)
{
line = line.Substring(0, commentIndex).Trim();
}
if (line.IsNullOrEmpty())
{
continue;
}
var hostItem = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (hostItem.Length < 2)
{
continue;
}
var ipAddress = hostItem[0];
var domain = hostItem[1];
// Validate IP address
if (!IsIpAddress(ipAddress))
{
continue;
}
// Validate domain name
if (domain.IsNullOrEmpty() || domain.Length > 255)
{
continue;
}
systemHosts[domain] = ipAddress;
}
return systemHosts;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -824,19 +755,6 @@ public class Utils
return systemHosts; return systemHosts;
} }
public static Dictionary<string, string> GetSystemHosts()
{
var hosts = GetSystemHosts(@"C:\Windows\System32\drivers\etc\hosts");
var hostsIcs = GetSystemHosts(@"C:\Windows\System32\drivers\etc\hosts.ics");
foreach (var (key, value) in hostsIcs)
{
hosts[key] = value;
}
return hosts;
}
public static async Task<string?> GetCliWrapOutput(string filePath, string? arg) public static async Task<string?> GetCliWrapOutput(string filePath, string? arg)
{ {
return await GetCliWrapOutput(filePath, arg != null ? new List<string>() { arg } : null); return await GetCliWrapOutput(filePath, arg != null ? new List<string>() { arg } : null);

View file

@ -290,16 +290,6 @@ public class Global
"dns" "dns"
]; ];
public static readonly Dictionary<string, string> KcpHeaderMaskMap = new()
{
{ "srtp", "header-srtp" },
{ "utp", "header-utp" },
{ "wechat-video", "header-wechat" },
{ "dtls", "header-dtls" },
{ "wireguard", "header-wireguard" },
{ "dns", "header-dns" }
};
public static readonly List<string> CoreTypes = public static readonly List<string> CoreTypes =
[ [
"Xray", "Xray",
@ -341,13 +331,13 @@ public class Global
IPOnDemand IPOnDemand
]; ];
public static readonly List<string> DomainStrategies4Sbox = public static readonly List<string> DomainStrategies4Singbox =
[ [
"", "ipv4_only",
"ipv6_only",
"prefer_ipv4", "prefer_ipv4",
"prefer_ipv6", "prefer_ipv6",
"ipv4_only", ""
"ipv6_only"
]; ];
public static readonly List<string> Fingerprints = public static readonly List<string> Fingerprints =
@ -389,22 +379,28 @@ public class Global
"" ""
]; ];
public static readonly List<string> DomainStrategy = public static readonly List<string> DomainStrategy4Freedoms =
[ [
"AsIs", "AsIs",
"UseIP", "UseIP",
"UseIPv4v6",
"UseIPv6v4",
"UseIPv4", "UseIPv4",
"UseIPv6", "UseIPv6",
"" ""
]; ];
public static readonly List<string> SingboxDomainStrategy4Out =
[
"",
"ipv4_only",
"prefer_ipv4",
"prefer_ipv6",
"ipv6_only"
];
public static readonly List<string> DomainDirectDNSAddress = public static readonly List<string> DomainDirectDNSAddress =
[ [
"https://dns.alidns.com/dns-query", "https://dns.alidns.com/dns-query",
"https://doh.pub/dns-query", "https://doh.pub/dns-query",
"https://dns.alidns.com/dns-query,https://doh.pub/dns-query",
"223.5.5.5", "223.5.5.5",
"119.29.29.29", "119.29.29.29",
"localhost" "localhost"
@ -413,9 +409,8 @@ public class Global
public static readonly List<string> DomainRemoteDNSAddress = public static readonly List<string> DomainRemoteDNSAddress =
[ [
"https://cloudflare-dns.com/dns-query", "https://cloudflare-dns.com/dns-query",
"https://dns.google/dns-query",
"https://cloudflare-dns.com/dns-query,https://dns.google/dns-query,8.8.8.8",
"https://dns.cloudflare.com/dns-query", "https://dns.cloudflare.com/dns-query",
"https://dns.google/dns-query",
"https://doh.dns.sb/dns-query", "https://doh.dns.sb/dns-query",
"https://doh.opendns.com/dns-query", "https://doh.opendns.com/dns-query",
"https://common.dot.dns.yandex.net", "https://common.dot.dns.yandex.net",
@ -613,20 +608,20 @@ public class Global
public static readonly Dictionary<string, List<string>> PredefinedHosts = new() public static readonly Dictionary<string, List<string>> PredefinedHosts = new()
{ {
{ "dns.google", ["8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844"] }, { "dns.google", new List<string> { "8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844" } },
{ "dns.alidns.com", ["223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1"] }, { "dns.alidns.com", new List<string> { "223.5.5.5", "223.6.6.6", "2400:3200::1", "2400:3200:baba::1" } },
{ "one.one.one.one", ["1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"] }, { "one.one.one.one", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
{ "1dot1dot1dot1.cloudflare-dns.com", ["1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"] }, { "1dot1dot1dot1.cloudflare-dns.com", new List<string> { "1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001" } },
{ "cloudflare-dns.com", ["104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9"] }, { "cloudflare-dns.com", new List<string> { "104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9" } },
{ "dns.cloudflare.com", ["104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5"] }, { "dns.cloudflare.com", new List<string> { "104.16.132.229", "104.16.133.229", "2606:4700::6810:84e5", "2606:4700::6810:85e5" } },
{ "dot.pub", ["1.12.12.12", "120.53.53.53"] }, { "dot.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
{ "doh.pub", ["1.12.12.12", "120.53.53.53"] }, { "doh.pub", new List<string> { "1.12.12.12", "120.53.53.53" } },
{ "dns.quad9.net", ["9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9"] }, { "dns.quad9.net", new List<string> { "9.9.9.9", "149.112.112.112", "2620:fe::fe", "2620:fe::9" } },
{ "dns.yandex.net", ["77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff"] }, { "dns.yandex.net", new List<string> { "77.88.8.8", "77.88.8.1", "2a02:6b8::feed:0ff", "2a02:6b8:0:1::feed:0ff" } },
{ "dns.sb", ["185.222.222.222", "2a09::"] }, { "dns.sb", new List<string> { "185.222.222.222", "2a09::" } },
{ "dns.umbrella.com", ["208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53"] }, { "dns.umbrella.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
{ "dns.sse.cisco.com", ["208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53"] }, { "dns.sse.cisco.com", new List<string> { "208.67.220.220", "208.67.222.222", "2620:119:35::35", "2620:119:53::53" } },
{ "engage.cloudflareclient.com", ["162.159.192.1"] } { "engage.cloudflareclient.com", new List<string> { "162.159.192.1", "2606:4700:d0::a29f:c001" } }
}; };
public static readonly List<string> ExpectedIPs = public static readonly List<string> ExpectedIPs =

View file

@ -114,8 +114,6 @@ public static class ConfigHandler
config.SimpleDNSItem ??= InitBuiltinSimpleDNS(); config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
config.SimpleDNSItem.GlobalFakeIp ??= true; config.SimpleDNSItem.GlobalFakeIp ??= true;
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault(); config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
config.SimpleDNSItem.ServeStale ??= false;
config.SimpleDNSItem.ParallelQuery ??= false;
config.SpeedTestItem ??= new(); config.SpeedTestItem ??= new();
if (config.SpeedTestItem.SpeedTestTimeout < 10) if (config.SpeedTestItem.SpeedTestTimeout < 10)
@ -707,6 +705,7 @@ public static class ConfigHandler
profileItem.Address = profileItem.Address.TrimEx(); profileItem.Address = profileItem.Address.TrimEx();
profileItem.Password = profileItem.Password.TrimEx(); profileItem.Password = profileItem.Password.TrimEx();
profileItem.Path = profileItem.Path.TrimEx();
profileItem.Network = string.Empty; profileItem.Network = string.Empty;
if (profileItem.StreamSecurity.IsNullOrEmpty()) if (profileItem.StreamSecurity.IsNullOrEmpty())
@ -719,7 +718,6 @@ public static class ConfigHandler
} }
profileItem.SetProtocolExtra(profileItem.GetProtocolExtra() with profileItem.SetProtocolExtra(profileItem.GetProtocolExtra() with
{ {
SalamanderPass = profileItem.GetProtocolExtra().SalamanderPass?.TrimEx(),
UpMbps = profileItem.GetProtocolExtra().UpMbps is null or < 0 ? config.HysteriaItem.UpMbps : profileItem.GetProtocolExtra().UpMbps, UpMbps = profileItem.GetProtocolExtra().UpMbps is null or < 0 ? config.HysteriaItem.UpMbps : profileItem.GetProtocolExtra().UpMbps,
DownMbps = profileItem.GetProtocolExtra().DownMbps is null or < 0 ? config.HysteriaItem.DownMbps : profileItem.GetProtocolExtra().DownMbps, DownMbps = profileItem.GetProtocolExtra().DownMbps is null or < 0 ? config.HysteriaItem.DownMbps : profileItem.GetProtocolExtra().DownMbps,
HopInterval = profileItem.GetProtocolExtra().HopInterval is null or <= 5 ? Global.Hysteria2DefaultHopInt : profileItem.GetProtocolExtra().HopInterval, HopInterval = profileItem.GetProtocolExtra().HopInterval is null or <= 5 ? Global.Hysteria2DefaultHopInt : profileItem.GetProtocolExtra().HopInterval,
@ -1119,7 +1117,6 @@ public static class ConfigHandler
&& AreEqual(o.Path, n.Path) && AreEqual(o.Path, n.Path)
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity) && (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& AreEqual(oProtocolExtra.Flow, nProtocolExtra.Flow) && AreEqual(oProtocolExtra.Flow, nProtocolExtra.Flow)
&& AreEqual(oProtocolExtra.SalamanderPass, nProtocolExtra.SalamanderPass)
&& AreEqual(o.Sni, n.Sni) && AreEqual(o.Sni, n.Sni)
&& AreEqual(o.Alpn, n.Alpn) && AreEqual(o.Alpn, n.Alpn)
&& AreEqual(o.Fingerprint, n.Fingerprint) && AreEqual(o.Fingerprint, n.Fingerprint)

View file

@ -23,15 +23,16 @@ public class Hysteria2Fmt : BaseFmt
var query = Utils.ParseQueryString(url.Query); var query = Utils.ParseQueryString(url.Query);
ResolveUriQuery(query, ref item); ResolveUriQuery(query, ref item);
item.Path = GetQueryDecoded(query, "obfs-password");
if (item.CertSha.IsNullOrEmpty()) if (item.CertSha.IsNullOrEmpty())
{ {
item.CertSha = GetQueryDecoded(query, "pinSHA256"); item.CertSha = GetQueryDecoded(query, "pinSHA256");
} }
item.SetProtocolExtra(item.GetProtocolExtra() with ProtocolExtraItem extraItem = new()
{ {
Ports = GetQueryDecoded(query, "mport"), Ports = GetQueryDecoded(query, "mport")
SalamanderPass = GetQueryDecoded(query, "obfs-password"), };
}); item.SetProtocolExtra(extraItem);
return item; return item;
} }
@ -52,16 +53,15 @@ public class Hysteria2Fmt : BaseFmt
} }
var dicQuery = new Dictionary<string, string>(); var dicQuery = new Dictionary<string, string>();
ToUriQueryLite(item, ref dicQuery); ToUriQueryLite(item, ref dicQuery);
var protocolExtraItem = item.GetProtocolExtra();
if (!protocolExtraItem.SalamanderPass.IsNullOrEmpty()) if (item.Path.IsNotEmpty())
{ {
dicQuery.Add("obfs", "salamander"); dicQuery.Add("obfs", "salamander");
dicQuery.Add("obfs-password", Utils.UrlEncode(protocolExtraItem.SalamanderPass)); dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
} }
if (!protocolExtraItem.Ports.IsNullOrEmpty()) if (item.GetProtocolExtra()?.Ports?.IsNotEmpty() ?? false)
{ {
dicQuery.Add("mport", Utils.UrlEncode(protocolExtraItem.Ports.Replace(':', '-'))); dicQuery.Add("mport", Utils.UrlEncode(item.GetProtocolExtra().Ports.Replace(':', '-')));
} }
if (!item.CertSha.IsNullOrEmpty()) if (!item.CertSha.IsNullOrEmpty())
{ {

View file

@ -24,8 +24,8 @@ public class TuicFmt : BaseFmt
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2); var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
if (userInfoParts.Length == 2) if (userInfoParts.Length == 2)
{ {
item.SetProtocolExtra(item.GetProtocolExtra() with { Username = userInfoParts.First() }); item.Password = userInfoParts.First();
item.Password = userInfoParts.Last(); item.SetProtocolExtra(item.GetProtocolExtra() with { Username = userInfoParts.Last() });
} }
var query = Utils.ParseQueryString(url.Query); var query = Utils.ParseQueryString(url.Query);
@ -53,6 +53,6 @@ public class TuicFmt : BaseFmt
dicQuery.Add("congestion_control", item.HeaderType); dicQuery.Add("congestion_control", item.HeaderType);
return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.GetProtocolExtra().Username ?? ""}:{item.Password}", dicQuery, remark); return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Password}:{item.GetProtocolExtra().Username ?? ""}", dicQuery, remark);
} }
} }

View file

@ -279,7 +279,12 @@ public sealed class AppManager
foreach (var item in batch) foreach (var item in batch)
{ {
var extra = item.GetProtocolExtra(); ProtocolExtraItem extra = new()
{
AlterId = item.AlterId.ToString(),
Flow = item.Flow.IsNotEmpty() ? item.Flow : null,
Ports = item.Ports.IsNotEmpty() ? item.Ports : null,
};
if (item.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain) if (item.ConfigType is EConfigType.PolicyGroup or EConfigType.ProxyChain)
{ {
@ -295,56 +300,33 @@ public sealed class AppManager
MultipleLoad = groupItem.MultipleLoad, MultipleLoad = groupItem.MultipleLoad,
}; };
} }
}
switch (item.ConfigType) switch (item.ConfigType)
{ {
case EConfigType.Shadowsocks: case EConfigType.Shadowsocks:
extra = extra with { SsMethod = item.Security.NullIfEmpty() }; extra = extra with {SsMethod = item.Security.IsNotEmpty() ? item.Security : null};
break; break;
case EConfigType.VMess: case EConfigType.VMess:
extra = extra with extra = extra with {VmessSecurity = item.Security.IsNotEmpty() ? item.Security : null};
{ break;
AlterId = item.AlterId.ToString(), case EConfigType.Hysteria2:
VmessSecurity = item.Security.NullIfEmpty(), extra = extra with
}; {
break; UpMbps = _config.HysteriaItem.UpMbps,
case EConfigType.VLESS: DownMbps = _config.HysteriaItem.DownMbps,
extra = extra with HopInterval = _config.HysteriaItem.HopInterval
{ };
Flow = item.Flow.NullIfEmpty(), break;
VlessEncryption = item.Security, case EConfigType.WireGuard:
}; extra = extra with
break; {
case EConfigType.Hysteria2: WgPublicKey = item.PublicKey.IsNotEmpty() ? item.PublicKey : null,
extra = extra with WgInterfaceAddress = item.RequestHost.IsNotEmpty() ? item.RequestHost : null,
{ WgReserved = item.Path.IsNotEmpty() ? item.Path : null,
SalamanderPass = item.Path.NullIfEmpty(), WgMtu = int.TryParse(item.ShortId, out var mtu) ? mtu : 1280
Ports = item.Ports.NullIfEmpty(), };
UpMbps = _config.HysteriaItem.UpMbps, break;
DownMbps = _config.HysteriaItem.DownMbps, }
HopInterval = _config.HysteriaItem.HopInterval
};
break;
case EConfigType.TUIC:
extra = extra with
{
Username = item.Id,
};
item.Id = item.Security;
item.Password = item.Security;
break;
case EConfigType.WireGuard:
extra = extra with
{
WgPublicKey = item.PublicKey.NullIfEmpty(),
WgInterfaceAddress = item.RequestHost.NullIfEmpty(),
WgReserved = item.Path.NullIfEmpty(),
WgMtu = int.TryParse(item.ShortId, out var mtu) ? mtu : 1280
};
break;
default:
break;
} }
item.SetProtocolExtra(extra); item.SetProtocolExtra(extra);

View file

@ -197,7 +197,6 @@ public class CertPemManager
"D02A0F994A868C66395F2E7A880DF509BD0C29C96DE16015A0FD501EDA4F96A9", // OISTE Client Root RSA G1 "D02A0F994A868C66395F2E7A880DF509BD0C29C96DE16015A0FD501EDA4F96A9", // OISTE Client Root RSA G1
"EEC997C0C30F216F7E3B8B307D2BAE42412D753FC8219DAFD1520B2572850F49", // OISTE Server Root ECC G1 "EEC997C0C30F216F7E3B8B307D2BAE42412D753FC8219DAFD1520B2572850F49", // OISTE Server Root ECC G1
"9AE36232A5189FFDDB353DFD26520C015395D22777DAC59DB57B98C089A651E6", // OISTE Server Root RSA G1 "9AE36232A5189FFDDB353DFD26520C015395D22777DAC59DB57B98C089A651E6", // OISTE Server Root RSA G1
"B49141502D00663D740F2E7EC340C52800962666121A36D09CF7DD2B90384FB4", // e-Szigno TLS Root CA 2023
}; };
/// <summary> /// <summary>

View file

@ -226,7 +226,7 @@ public class CoreManager
{ {
if (mayNeedSudo if (mayNeedSudo
&& _config.TunModeItem.EnableTun && _config.TunModeItem.EnableTun
&& (coreInfo.CoreType is ECoreType.sing_box or ECoreType.mihomo) && coreInfo.CoreType == ECoreType.sing_box
&& Utils.IsNonWindows()) && Utils.IsNonWindows())
{ {
_linuxSudo = true; _linuxSudo = true;

View file

@ -72,30 +72,21 @@ public class GroupProfileManager
public static async Task<(List<ProfileItem> Items, ProtocolExtraItem? Extra)> GetChildProfileItems(ProfileItem profileItem) public static async Task<(List<ProfileItem> Items, ProtocolExtraItem? Extra)> GetChildProfileItems(ProfileItem profileItem)
{ {
var protocolExtra = profileItem?.GetProtocolExtra(); var protocolExtra = profileItem?.GetProtocolExtra();
return (await GetChildProfileItemsByProtocolExtra(protocolExtra), protocolExtra); var items = await GetChildProfileItems(protocolExtra);
}
public static async Task<List<ProfileItem>> GetChildProfileItemsByProtocolExtra(ProtocolExtraItem? protocolExtra)
{
if (protocolExtra == null)
{
return new();
}
var items = await GetSelectedChildProfileItems(protocolExtra);
var subItems = await GetSubChildProfileItems(protocolExtra); var subItems = await GetSubChildProfileItems(protocolExtra);
items.AddRange(subItems); items.AddRange(subItems);
return items; return (items, protocolExtra);
} }
public static async Task<List<ProfileItem>> GetSelectedChildProfileItems(ProtocolExtraItem? extra) public static async Task<List<ProfileItem>> GetChildProfileItems(ProtocolExtraItem? extra)
{ {
if (extra == null || extra.ChildItems.IsNullOrEmpty()) if (extra == null || extra.ChildItems.IsNullOrEmpty())
{ {
return new(); return new();
} }
var childProfiles = (await Task.WhenAll( var childProfiles = (await Task.WhenAll(
(Utils.String2List(extra.ChildItems) ?? new()) Utils.String2List(extra.ChildItems)
.Where(p => !p.IsNullOrEmpty()) .Where(p => !p.IsNullOrEmpty())
.Select(AppManager.Instance.GetProfileItem) .Select(AppManager.Instance.GetProfileItem)
)) ))
@ -110,19 +101,19 @@ public class GroupProfileManager
public static async Task<List<ProfileItem>> GetSubChildProfileItems(ProtocolExtraItem? extra) public static async Task<List<ProfileItem>> GetSubChildProfileItems(ProtocolExtraItem? extra)
{ {
if (extra == null || extra.SubChildItems.IsNullOrEmpty()) if (extra == null || extra.Filter.IsNullOrEmpty())
{ {
return new(); return new();
} }
var childProfiles = await AppManager.Instance.ProfileItems(extra.SubChildItems ?? string.Empty); var childProfiles = await AppManager.Instance.ProfileItems(extra.SubChildItems ?? string.Empty);
return childProfiles?.Where(p => return childProfiles.Where(p =>
p != null && p != null &&
p.IsValid() && p.IsValid() &&
!p.ConfigType.IsComplexType() && !p.ConfigType.IsComplexType() &&
(extra.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, extra.Filter)) (extra.Filter.IsNullOrEmpty() || Regex.IsMatch(p.Remarks, extra.Filter))
) )
.ToList() ?? new(); .ToList();
} }
public static async Task<HashSet<string>> GetAllChildDomainAddresses(ProfileItem profileItem) public static async Task<HashSet<string>> GetAllChildDomainAddresses(ProfileItem profileItem)

View file

@ -265,10 +265,9 @@ public class SimpleDNSItem
public string? DirectDNS { get; set; } public string? DirectDNS { get; set; }
public string? RemoteDNS { get; set; } public string? RemoteDNS { get; set; }
public string? BootstrapDNS { get; set; } public string? BootstrapDNS { get; set; }
public string? Strategy4Freedom { get; set; } public string? RayStrategy4Freedom { get; set; }
public string? Strategy4Proxy { get; set; } public string? SingboxStrategy4Direct { get; set; }
public bool? ServeStale { get; set; } public string? SingboxStrategy4Proxy { get; set; }
public bool? ParallelQuery { get; set; }
public string? Hosts { get; set; } public string? Hosts { get; set; }
public string? DirectExpectedIPs { get; set; } public string? DirectExpectedIPs { get; set; }
} }

View file

@ -26,7 +26,6 @@ public record ProtocolExtraItem
public int? WgMtu { get; init; } public int? WgMtu { get; init; }
// hysteria2 // hysteria2
public string? SalamanderPass { get; init; }
public int? UpMbps { get; init; } public int? UpMbps { get; init; }
public int? DownMbps { get; init; } public int? DownMbps { get; init; }
public string? Ports { get; init; } public string? Ports { get; init; }

View file

@ -3,7 +3,7 @@ namespace ServiceLib.Models;
public class V2rayConfig public class V2rayConfig
{ {
public Log4Ray log { get; set; } public Log4Ray log { get; set; }
public object dns { get; set; } public Dns4Ray dns { get; set; }
public List<Inbounds4Ray> inbounds { get; set; } public List<Inbounds4Ray> inbounds { get; set; }
public List<Outbounds4Ray> outbounds { get; set; } public List<Outbounds4Ray> outbounds { get; set; }
public Routing4Ray routing { get; set; } public Routing4Ray routing { get; set; }
@ -105,8 +105,6 @@ public class Outbounds4Ray
public string protocol { get; set; } public string protocol { get; set; }
public string? targetStrategy { get; set; }
public Outboundsettings4Ray settings { get; set; } public Outboundsettings4Ray settings { get; set; }
public StreamSettings4Ray streamSettings { get; set; } public StreamSettings4Ray streamSettings { get; set; }
@ -208,8 +206,12 @@ public class Dns4Ray
{ {
public Dictionary<string, object>? hosts { get; set; } public Dictionary<string, object>? hosts { get; set; }
public List<object> servers { get; set; } public List<object> servers { get; set; }
public bool? serveStale { get; set; } public string? clientIp { get; set; }
public bool? enableParallelQuery { get; set; } public string? queryStrategy { get; set; }
public bool? disableCache { get; set; }
public bool? disableFallback { get; set; }
public bool? disableFallbackIfMatch { get; set; }
public bool? useSystemHosts { get; set; }
public string? tag { get; set; } public string? tag { get; set; }
} }
@ -341,7 +343,7 @@ public class StreamSettings4Ray
public HysteriaSettings4Ray? hysteriaSettings { get; set; } public HysteriaSettings4Ray? hysteriaSettings { get; set; }
public FinalMask4Ray? finalmask { get; set; } public List<UdpMasks4Ray>? udpmasks { get; set; }
public Sockopt4Ray? sockopt { get; set; } public Sockopt4Ray? sockopt { get; set; }
} }
@ -386,6 +388,8 @@ public class Header4Ray
public object request { get; set; } public object request { get; set; }
public object response { get; set; } public object response { get; set; }
public string? domain { get; set; }
} }
public class KcpSettings4Ray public class KcpSettings4Ray
@ -403,6 +407,10 @@ public class KcpSettings4Ray
public int readBufferSize { get; set; } public int readBufferSize { get; set; }
public int writeBufferSize { get; set; } public int writeBufferSize { get; set; }
public Header4Ray header { get; set; }
public string seed { get; set; }
} }
public class WsSettings4Ray public class WsSettings4Ray
@ -476,22 +484,15 @@ public class HysteriaUdpHop4Ray
public int? interval { get; set; } public int? interval { get; set; }
} }
public class FinalMask4Ray public class UdpMasks4Ray
{
public List<Mask4Ray>? tcp { get; set; }
public List<Mask4Ray>? udp { get; set; }
}
public class Mask4Ray
{ {
public string type { get; set; } public string type { get; set; }
public MaskSettings4Ray? settings { get; set; } public UdpMasksSettings4Ray? settings { get; set; }
} }
public class MaskSettings4Ray public class UdpMasksSettings4Ray
{ {
public string? password { get; set; } public string? password { get; set; }
public string? domain { get; set; }
} }
public class AccountsItem4Ray public class AccountsItem4Ray

View file

@ -2727,24 +2727,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Direct Target Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbDirectResolveStrategy {
get {
return ResourceManager.GetString("TbDirectResolveStrategy", resourceCulture);
}
}
/// <summary>
/// 查找类似 If unset or &quot;AsIs&quot;, DNS resolution uses the system DNS; otherwise, the internal DNS module is used. 的本地化字符串。
/// </summary>
public static string TbDirectResolveStrategyTips {
get {
return ResourceManager.GetString("TbDirectResolveStrategyTips", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Display GUI 的本地化字符串。 /// 查找类似 Display GUI 的本地化字符串。
/// </summary> /// </summary>
@ -2817,15 +2799,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 By default, invoked only during routing for resolution 的本地化字符串。
/// </summary>
public static string TbDomesticDNSTips {
get {
return ResourceManager.GetString("TbDomesticDNSTips", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 EchConfigList 的本地化字符串。 /// 查找类似 EchConfigList 的本地化字符串。
/// </summary> /// </summary>
@ -3096,15 +3069,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Parallel Query 的本地化字符串。
/// </summary>
public static string TbParallelQuery {
get {
return ResourceManager.GetString("TbParallelQuery", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Path 的本地化字符串。 /// 查找类似 Path 的本地化字符串。
/// </summary> /// </summary>
@ -3259,7 +3223,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 By default, invoked only during routing for resolution; ensure the remote server can reach this DNS 的本地化字符串。 /// 查找类似 Via proxy — please ensure remote availability 的本地化字符串。
/// </summary> /// </summary>
public static string TbRemoteDNSTips { public static string TbRemoteDNSTips {
get { get {
@ -3267,24 +3231,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Proxy Target Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbRemoteResolveStrategy {
get {
return ResourceManager.GetString("TbRemoteResolveStrategy", resourceCulture);
}
}
/// <summary>
/// 查找类似 If unset or &quot;AsIs&quot;, DNS resolution is performed by the remote server&apos;s DNS; otherwise, the internal DNS module is used. 的本地化字符串。
/// </summary>
public static string TbRemoteResolveStrategyTips {
get {
return ResourceManager.GetString("TbRemoteResolveStrategyTips", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Camouflage domain(host) 的本地化字符串。 /// 查找类似 Camouflage domain(host) 的本地化字符串。
/// </summary> /// </summary>
@ -3420,6 +3366,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 sing-box Direct Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbSBDirectResolveStrategy {
get {
return ResourceManager.GetString("TbSBDirectResolveStrategy", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 sing-box Full Config Template 的本地化字符串。 /// 查找类似 sing-box Full Config Template 的本地化字符串。
/// </summary> /// </summary>
@ -3438,6 +3393,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 sing-box Remote Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbSBRemoteResolveStrategy {
get {
return ResourceManager.GetString("TbSBRemoteResolveStrategy", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Encryption method (security) 的本地化字符串。 /// 查找类似 Encryption method (security) 的本地化字符串。
/// </summary> /// </summary>
@ -3483,15 +3447,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Serve Stale 的本地化字符串。
/// </summary>
public static string TbServeStale {
get {
return ResourceManager.GetString("TbServeStale", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Set system proxy 的本地化字符串。 /// 查找类似 Set system proxy 的本地化字符串。
/// </summary> /// </summary>
@ -4465,7 +4420,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 When configured, validates IPs returned for regional domains (e.g., geosite:cn - geoip:cn), returning only expected IPs 的本地化字符串。 /// 查找类似 When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs 的本地化字符串。
/// </summary> /// </summary>
public static string TbValidateDirectExpectedIPsDesc { public static string TbValidateDirectExpectedIPsDesc {
get { get {
@ -4473,6 +4428,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 xray Freedom Resolution Strategy 的本地化字符串。
/// </summary>
public static string TbXrayFreedomStrategy {
get {
return ResourceManager.GetString("TbXrayFreedomStrategy", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 The delay: {0} ms, {1} 的本地化字符串。 /// 查找类似 The delay: {0} ms, {1} 的本地化字符串。
/// </summary> /// </summary>

View file

@ -1419,11 +1419,17 @@
<data name="TbDomesticDNS" xml:space="preserve"> <data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value> <value>Domestic DNS</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>Direct Target Resolution Strategy</value> <value>Via proxy — please ensure remote availability</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbXrayFreedomStrategy" xml:space="preserve">
<value>Proxy Target Resolution Strategy</value> <value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value> <value>Add Common DNS Hosts</value>
@ -1447,7 +1453,7 @@
<value>Validate Regional Domain IPs</value> <value>Validate Regional Domain IPs</value>
</data> </data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve"> <data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn - geoip:cn), returning only expected IPs</value> <value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data> </data>
<data name="TbCustomDNSEnable" xml:space="preserve"> <data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value> <value>Enable Custom DNS</value>
@ -1647,24 +1653,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>Certificate fingerprint (SHA-256)</value> <value>Certificate fingerprint (SHA-256)</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve">
<value>Serve Stale</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>Parallel Query</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>Port hopping interval</value> <value>Port hopping interval</value>
</data> </data>

View file

@ -1416,11 +1416,17 @@
<data name="TbDomesticDNS" xml:space="preserve"> <data name="TbDomesticDNS" xml:space="preserve">
<value>DNS direct</value> <value>DNS direct</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>Direct Target Resolution Strategy</value> <value>Via le proxy ; assurez-vous que le serveur distant est disponible</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbXrayFreedomStrategy" xml:space="preserve">
<value>Proxy Target Resolution Strategy</value> <value>Stratégie de résolution xray freedom</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>Stratégie de résolution directe sing-box</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>Stratégie de résolution distante sing-box</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Ajouter des hôtes DNS courants</value> <value>Ajouter des hôtes DNS courants</value>
@ -1444,7 +1450,7 @@
<value>Valider les IP des domaines de la région concernée</value> <value>Valider les IP des domaines de la région concernée</value>
</data> </data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve"> <data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>Après config, les IP renvoyées des domaines régionaux (ex. geosite:cn - geoip:cn) seront vérifiées ; seules les IP attendues seront retournées.</value> <value>Après config, les IP renvoyées des domaines régionaux (ex. geosite:cn) seront vérifiées ; seules les IP attendues seront retournées.</value>
</data> </data>
<data name="TbCustomDNSEnable" xml:space="preserve"> <data name="TbCustomDNSEnable" xml:space="preserve">
<value>Activer le DNS personnalisé</value> <value>Activer le DNS personnalisé</value>
@ -1644,24 +1650,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>Certificate fingerprint (SHA-256)</value> <value>Certificate fingerprint (SHA-256)</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve">
<value>Serve Stale</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>Parallel Query</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>Port hopping interval</value> <value>Port hopping interval</value>
</data> </data>

View file

@ -1419,11 +1419,17 @@
<data name="TbDomesticDNS" xml:space="preserve"> <data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value> <value>Domestic DNS</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>Direct Target Resolution Strategy</value> <value>Via proxy — please ensure remote availability</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbXrayFreedomStrategy" xml:space="preserve">
<value>Proxy Target Resolution Strategy</value> <value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value> <value>Add Common DNS Hosts</value>
@ -1447,7 +1453,7 @@
<value>Validate Regional Domain IPs</value> <value>Validate Regional Domain IPs</value>
</data> </data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve"> <data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn - geoip:cn), returning only expected IPs</value> <value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data> </data>
<data name="TbCustomDNSEnable" xml:space="preserve"> <data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value> <value>Enable Custom DNS</value>
@ -1647,24 +1653,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>Certificate fingerprint (SHA-256)</value> <value>Certificate fingerprint (SHA-256)</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve">
<value>Serve Stale</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>Parallel Query</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>Port hopping interval</value> <value>Port hopping interval</value>
</data> </data>

View file

@ -1419,11 +1419,17 @@
<data name="TbDomesticDNS" xml:space="preserve"> <data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value> <value>Domestic DNS</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>Direct Target Resolution Strategy</value> <value>Via proxy — please ensure remote availability</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbXrayFreedomStrategy" xml:space="preserve">
<value>Proxy Target Resolution Strategy</value> <value>xray Freedom Resolution Strategy</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value> <value>Add Common DNS Hosts</value>
@ -1447,7 +1453,7 @@
<value>Validate Regional Domain IPs</value> <value>Validate Regional Domain IPs</value>
</data> </data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve"> <data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn - geoip:cn), returning only expected IPs</value> <value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
</data> </data>
<data name="TbCustomDNSEnable" xml:space="preserve"> <data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value> <value>Enable Custom DNS</value>
@ -1647,24 +1653,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>Certificate fingerprint (SHA-256)</value> <value>Certificate fingerprint (SHA-256)</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve">
<value>Serve Stale</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>Parallel Query</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>Port hopping interval</value> <value>Port hopping interval</value>
</data> </data>

View file

@ -1419,11 +1419,17 @@
<data name="TbDomesticDNS" xml:space="preserve"> <data name="TbDomesticDNS" xml:space="preserve">
<value>Внутренний DNS</value> <value>Внутренний DNS</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>Direct Target Resolution Strategy</value> <value>Via proxy — please ensure remote availability</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbXrayFreedomStrategy" xml:space="preserve">
<value>Proxy Target Resolution Strategy</value> <value>Стратегия резолвинга Freedom (Xray)</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>Стратегия прямого резолвинга (sing-box)</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>Стратегия удалённого резолвинга (sing-box)</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Добавить стандартные записи hosts (DNS)</value> <value>Добавить стандартные записи hosts (DNS)</value>
@ -1447,7 +1453,7 @@
<value>Проверять IP-адреса региональных доменов</value> <value>Проверять IP-адреса региональных доменов</value>
</data> </data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve"> <data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>При включении проверяет IP-адреса, возвращаемые для региональных доменов (например, geosite:cn - geoip:cn), и оставляет только ожидаемые IP-адреса</value> <value>При включении проверяет IP-адреса, возвращаемые для региональных доменов (например, geosite:cn), и оставляет только ожидаемые IP-адреса</value>
</data> </data>
<data name="TbCustomDNSEnable" xml:space="preserve"> <data name="TbCustomDNSEnable" xml:space="preserve">
<value>Включить пользовательский DNS</value> <value>Включить пользовательский DNS</value>
@ -1647,24 +1653,6 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>Certificate fingerprint (SHA-256)</value> <value>Certificate fingerprint (SHA-256)</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve">
<value>Serve Stale</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>Parallel Query</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>Port hopping interval</value> <value>Port hopping interval</value>
</data> </data>

View file

@ -1416,11 +1416,17 @@
<data name="TbDomesticDNS" xml:space="preserve"> <data name="TbDomesticDNS" xml:space="preserve">
<value>直连 DNS</value> <value>直连 DNS</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>直连目标解析策略</value> <value>通过代理,请确保远程可用</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbXrayFreedomStrategy" xml:space="preserve">
<value>代理目标解析策略</value> <value>xray freedom 解析策略</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box 直连解析策略</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box 远程解析策略</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>添加常用 DNS Hosts</value> <value>添加常用 DNS Hosts</value>
@ -1444,7 +1450,7 @@
<value>校验相应地区域名 IP</value> <value>校验相应地区域名 IP</value>
</data> </data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve"> <data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>配置后,会对相应地区域名(如 geosite:cn - geoip:cn)的返回 IP 进行校验,仅返回期望 IP</value> <value>配置后,会对相应地区域名(如 geosite:cn的返回 IP 进行校验,仅返回期望 IP</value>
</data> </data>
<data name="TbCustomDNSEnable" xml:space="preserve"> <data name="TbCustomDNSEnable" xml:space="preserve">
<value>启用自定义 DNS</value> <value>启用自定义 DNS</value>
@ -1644,24 +1650,6 @@
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>证书指纹SHA-256</value> <value>证书指纹SHA-256</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve">
<value>乐观缓存</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>并行查询</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>默认仅在路由阶段被调用解析</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>默认仅在路由阶段被调用解析;请确保远程服务器可访问该 DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>当未选择或 "AsIs" 时,使用系统 DNS 进行解析;否则,使用内部 DNS 模块解析。</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>当未选择或 "AsIs" 时,由远程服务器端 DNS 解析;否则,使用内部 DNS 模块解析。</value>
</data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>端口跳跃间隔</value> <value>端口跳跃间隔</value>
</data> </data>

View file

@ -1416,11 +1416,17 @@
<data name="TbDomesticDNS" xml:space="preserve"> <data name="TbDomesticDNS" xml:space="preserve">
<value>直連 DNS</value> <value>直連 DNS</value>
</data> </data>
<data name="TbDirectResolveStrategy" xml:space="preserve"> <data name="TbRemoteDNSTips" xml:space="preserve">
<value>直連目標解析策略</value> <value>通过代理,请确保远程可用</value>
</data> </data>
<data name="TbRemoteResolveStrategy" xml:space="preserve"> <data name="TbXrayFreedomStrategy" xml:space="preserve">
<value>代理目標解析策略</value> <value>xray freedom 解析策略</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box 直連解析策略</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box 遠程解析策略</value>
</data> </data>
<data name="TbAddCommonDNSHosts" xml:space="preserve"> <data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>新增常用 DNS Hosts</value> <value>新增常用 DNS Hosts</value>
@ -1444,7 +1450,7 @@
<value>校驗相應地區域名 IP</value> <value>校驗相應地區域名 IP</value>
</data> </data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve"> <data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>配置後,會對相應地區域名(如 geosite:cn - geoip:cn)的返回 IP 進行校驗,僅返回期望 IP</value> <value>配置後,會對相應地區域名(如 geosite:cn的返回 IP 進行校驗,僅返回期望 IP</value>
</data> </data>
<data name="TbCustomDNSEnable" xml:space="preserve"> <data name="TbCustomDNSEnable" xml:space="preserve">
<value>啟用自訂 DNS</value> <value>啟用自訂 DNS</value>
@ -1644,24 +1650,6 @@
<data name="TbCertSha256Tips" xml:space="preserve"> <data name="TbCertSha256Tips" xml:space="preserve">
<value>Certificate fingerprint (SHA-256)</value> <value>Certificate fingerprint (SHA-256)</value>
</data> </data>
<data name="TbServeStale" xml:space="preserve">
<value>Serve Stale</value>
</data>
<data name="TbParallelQuery" xml:space="preserve">
<value>Parallel Query</value>
</data>
<data name="TbDomesticDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution</value>
</data>
<data name="TbRemoteDNSTips" xml:space="preserve">
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
</data>
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
</data>
<data name="TbHopInt7" xml:space="preserve"> <data name="TbHopInt7" xml:space="preserve">
<value>Port hopping interval</value> <value>Port hopping interval</value>
</data> </data>

View file

@ -175,18 +175,18 @@ public partial class CoreConfigSingboxService
singboxConfig.dns.rules ??= new List<Rule4Sbox>(); singboxConfig.dns.rules ??= new List<Rule4Sbox>();
singboxConfig.dns.rules.AddRange(new[] singboxConfig.dns.rules.AddRange(new[]
{ {
new Rule4Sbox { ip_accept_any = true, server = Global.SingboxHostsDNSTag }, new Rule4Sbox { ip_accept_any = true, server = Global.SingboxHostsDNSTag },
new Rule4Sbox new Rule4Sbox
{ {
server = Global.SingboxRemoteDNSTag, server = Global.SingboxRemoteDNSTag,
strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Proxy), strategy = simpleDNSItem.SingboxStrategy4Proxy.NullIfEmpty(),
clash_mode = ERuleMode.Global.ToString() clash_mode = ERuleMode.Global.ToString()
}, },
new Rule4Sbox new Rule4Sbox
{ {
server = Global.SingboxDirectDNSTag, server = Global.SingboxDirectDNSTag,
strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Freedom), strategy = simpleDNSItem.SingboxStrategy4Direct.NullIfEmpty(),
clash_mode = ERuleMode.Direct.ToString() clash_mode = ERuleMode.Direct.ToString()
} }
}); });
@ -309,7 +309,7 @@ public partial class CoreConfigSingboxService
if (item.OutboundTag == Global.DirectTag) if (item.OutboundTag == Global.DirectTag)
{ {
rule.server = Global.SingboxDirectDNSTag; rule.server = Global.SingboxDirectDNSTag;
rule.strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Freedom); rule.strategy = string.IsNullOrEmpty(simpleDNSItem.SingboxStrategy4Direct) ? null : simpleDNSItem.SingboxStrategy4Direct;
if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0) if (expectedIPsRegions.Count > 0 && rule.geosite?.Count > 0)
{ {
@ -343,7 +343,7 @@ public partial class CoreConfigSingboxService
singboxConfig.dns.rules.Add(rule4Fake); singboxConfig.dns.rules.Add(rule4Fake);
} }
rule.server = Global.SingboxRemoteDNSTag; rule.server = Global.SingboxRemoteDNSTag;
rule.strategy = Utils.DomainStrategy4Sbox(simpleDNSItem.Strategy4Proxy); rule.strategy = string.IsNullOrEmpty(simpleDNSItem.SingboxStrategy4Proxy) ? null : simpleDNSItem.SingboxStrategy4Proxy;
} }
singboxConfig.dns.rules.Add(rule); singboxConfig.dns.rules.Add(rule);

View file

@ -114,13 +114,13 @@ public partial class CoreConfigSingboxService
outbound.packet_encoding = "xudp"; outbound.packet_encoding = "xudp";
if (!protocolExtra.Flow.IsNullOrEmpty()) if (protocolExtra.Flow.IsNullOrEmpty())
{ {
outbound.flow = protocolExtra.Flow; await GenOutboundMux(node, outbound);
} }
else else
{ {
await GenOutboundMux(node, outbound); outbound.flow = protocolExtra.Flow;
} }
await GenOutboundTransport(node, outbound); await GenOutboundTransport(node, outbound);
@ -138,21 +138,21 @@ public partial class CoreConfigSingboxService
{ {
outbound.password = node.Password; outbound.password = node.Password;
if (!protocolExtra.SalamanderPass.IsNullOrEmpty()) if (node.Path.IsNotEmpty())
{ {
outbound.obfs = new() outbound.obfs = new()
{ {
type = "salamander", type = "salamander",
password = protocolExtra.SalamanderPass.TrimEx(), password = node.Path.TrimEx(),
}; };
} }
outbound.up_mbps = protocolExtra?.UpMbps is { } su and >= 0 outbound.up_mbps = protocolExtra?.UpMbps is { } su and >= 0
? su ? su
: _config.HysteriaItem.UpMbps; : 0;
outbound.down_mbps = protocolExtra?.DownMbps is { } sd and >= 0 outbound.down_mbps = protocolExtra?.DownMbps is { } sd and >= 0
? sd ? sd
: _config.HysteriaItem.DownMbps; : 0;
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(',')))
{ {
@ -175,8 +175,8 @@ public partial class CoreConfigSingboxService
} }
case EConfigType.TUIC: case EConfigType.TUIC:
{ {
outbound.uuid = protocolExtra.Username; outbound.uuid = node.Password;
outbound.password = node.Password; outbound.password = protocolExtra.Username;
outbound.congestion_control = node.HeaderType; outbound.congestion_control = node.HeaderType;
break; break;
} }

View file

@ -7,21 +7,21 @@ public partial class CoreConfigSingboxService
try try
{ {
singboxConfig.route.final = Global.ProxyTag; singboxConfig.route.final = Global.ProxyTag;
var simpleDnsItem = _config.SimpleDNSItem; var item = _config.SimpleDNSItem;
var defaultDomainResolverTag = Global.SingboxDirectDNSTag; var defaultDomainResolverTag = Global.SingboxDirectDNSTag;
var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom); var directDNSStrategy = item.SingboxStrategy4Direct.IsNullOrEmpty() ? Global.SingboxDomainStrategy4Out.FirstOrDefault() : item.SingboxStrategy4Direct;
var rawDNSItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); var rawDNSItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box);
if (rawDNSItem is { Enabled: true }) if (rawDNSItem != null && rawDNSItem.Enabled == true)
{ {
defaultDomainResolverTag = Global.SingboxLocalDNSTag; defaultDomainResolverTag = Global.SingboxLocalDNSTag;
directDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom; directDNSStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? Global.SingboxDomainStrategy4Out.FirstOrDefault() : rawDNSItem.DomainStrategy4Freedom;
} }
singboxConfig.route.default_domain_resolver = new() singboxConfig.route.default_domain_resolver = new()
{ {
server = defaultDomainResolverTag, server = defaultDomainResolverTag,
strategy = directDnsStrategy strategy = directDNSStrategy
}; };
if (_config.TunModeItem.EnableTun) if (_config.TunModeItem.EnableTun)
@ -73,17 +73,18 @@ public partial class CoreConfigSingboxService
var hostsDomains = new List<string>(); var hostsDomains = new List<string>();
var dnsItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box); var dnsItem = await AppManager.Instance.GetDNSItem(ECoreType.sing_box);
if (dnsItem == null || !dnsItem.Enabled) if (dnsItem == null || dnsItem.Enabled == false)
{ {
if (!simpleDnsItem.Hosts.IsNullOrEmpty()) var simpleDNSItem = _config.SimpleDNSItem;
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
{ {
var userHostsMap = Utils.ParseHostsToDictionary(simpleDnsItem.Hosts); var userHostsMap = Utils.ParseHostsToDictionary(simpleDNSItem.Hosts);
foreach (var kvp in userHostsMap) foreach (var kvp in userHostsMap)
{ {
hostsDomains.Add(kvp.Key); hostsDomains.Add(kvp.Key);
} }
} }
if (simpleDnsItem.UseSystemHosts == true) if (simpleDNSItem.UseSystemHosts == true)
{ {
var systemHostsMap = Utils.GetSystemHosts(); var systemHostsMap = Utils.GetSystemHosts();
foreach (var kvp in systemHostsMap) foreach (var kvp in systemHostsMap)
@ -280,9 +281,7 @@ public partial class CoreConfigSingboxService
if (_config.TunModeItem.EnableTun && item.Process?.Count > 0) if (_config.TunModeItem.EnableTun && item.Process?.Count > 0)
{ {
var ruleProcName = JsonUtils.DeepCopy(rule3); var ruleProcName = JsonUtils.DeepCopy(rule3);
ruleProcName.process_name ??= [];
var ruleProcPath = JsonUtils.DeepCopy(rule3); var ruleProcPath = JsonUtils.DeepCopy(rule3);
ruleProcPath.process_path ??= [];
foreach (var process in item.Process) foreach (var process in item.Process)
{ {
// sing-box doesn't support this, fall back to process name match // sing-box doesn't support this, fall back to process name match

View file

@ -7,74 +7,48 @@ public partial class CoreConfigV2rayService
try try
{ {
var item = await AppManager.Instance.GetDNSItem(ECoreType.Xray); var item = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
if (item is { Enabled: true }) if (item != null && item.Enabled == true)
{ {
var result = await GenDnsCompatible(node, v2rayConfig); var result = await GenDnsCompatible(node, v2rayConfig);
if (v2rayConfig.routing.domainStrategy != Global.IPIfNonMatch) if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch)
{ {
return result; // DNS routing
v2rayConfig.dns.tag = Global.DnsTag;
v2rayConfig.routing.rules.Add(new RulesItem4Ray
{
type = "field",
inboundTag = new List<string> { Global.DnsTag },
outboundTag = Global.ProxyTag,
});
} }
// DNS routing
var dnsObj = JsonUtils.SerializeToNode(v2rayConfig.dns);
if (dnsObj == null)
{
return result;
}
dnsObj["tag"] = Global.DnsTag;
v2rayConfig.dns = JsonUtils.Deserialize<Dns4Ray>(JsonUtils.Serialize(dnsObj));
v2rayConfig.routing.rules.Add(new RulesItem4Ray
{
type = "field",
inboundTag = new List<string> { Global.DnsTag },
outboundTag = Global.ProxyTag,
});
return result; return result;
} }
var simpleDnsItem = _config.SimpleDNSItem; var simpleDNSItem = _config.SimpleDNSItem;
var dnsItem = v2rayConfig.dns is Dns4Ray dns4Ray ? dns4Ray : new Dns4Ray(); var domainStrategy4Freedom = simpleDNSItem?.RayStrategy4Freedom;
var strategy4Freedom = simpleDnsItem?.Strategy4Freedom ?? Global.AsIs;
//Outbound Freedom domainStrategy //Outbound Freedom domainStrategy
if (strategy4Freedom.IsNotEmpty() && strategy4Freedom != Global.AsIs) if (domainStrategy4Freedom.IsNotEmpty())
{ {
var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag }); var outbound = v2rayConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
if (outbound != null) if (outbound != null)
{ {
outbound.settings = new() outbound.settings = new()
{ {
domainStrategy = strategy4Freedom, domainStrategy = domainStrategy4Freedom,
userLevel = 0 userLevel = 0
}; };
} }
} }
var strategy4Proxy = simpleDnsItem?.Strategy4Proxy ?? Global.AsIs; await GenDnsServers(node, v2rayConfig, simpleDNSItem);
//Outbound Proxy domainStrategy await GenDnsHosts(v2rayConfig, simpleDNSItem);
if (strategy4Proxy.IsNotEmpty() && strategy4Proxy != Global.AsIs)
{
var xraySupportConfigTypeNames = Global.XraySupportConfigType
.Select(x => x == EConfigType.Hysteria2 ? "hysteria" : Global.ProtocolTypes[x])
.ToHashSet();
v2rayConfig.outbounds
.Where(t => xraySupportConfigTypeNames.Contains(t.protocol))
.ToList()
.ForEach(outbound => outbound.targetStrategy = strategy4Proxy);
}
await GenDnsServers(node, dnsItem, simpleDnsItem);
await GenDnsHosts(dnsItem, simpleDnsItem);
dnsItem.serveStale = simpleDnsItem?.ServeStale is true ? true : null;
dnsItem.enableParallelQuery = simpleDnsItem?.ParallelQuery is true ? true : null;
if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch) if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch)
{ {
// DNS routing // DNS routing
dnsItem.tag = Global.DnsTag; v2rayConfig.dns.tag = Global.DnsTag;
v2rayConfig.routing.rules.Add(new RulesItem4Ray v2rayConfig.routing.rules.Add(new RulesItem4Ray
{ {
type = "field", type = "field",
@ -82,8 +56,6 @@ public partial class CoreConfigV2rayService
outboundTag = Global.ProxyTag, outboundTag = Global.ProxyTag,
}); });
} }
v2rayConfig.dns = dnsItem;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -92,7 +64,7 @@ public partial class CoreConfigV2rayService
return 0; return 0;
} }
private async Task<int> GenDnsServers(ProfileItem? node, Dns4Ray dnsItem, SimpleDNSItem simpleDNSItem) private async Task<int> GenDnsServers(ProfileItem? node, V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem)
{ {
static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress) static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress)
{ {
@ -105,7 +77,7 @@ public partial class CoreConfigV2rayService
return addresses.Count > 0 ? addresses : new List<string> { defaultAddress }; return addresses.Count > 0 ? addresses : new List<string> { defaultAddress };
} }
static object? CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null) static object CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
{ {
var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress); var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress);
var domainFinal = dnsAddress; var domainFinal = dnsAddress;
@ -134,8 +106,8 @@ public partial class CoreConfigV2rayService
}); });
} }
var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.First()); var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.FirstOrDefault());
var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.First()); var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.FirstOrDefault());
var directDomainList = new List<string>(); var directDomainList = new List<string>();
var directGeositeList = new List<string>(); var directGeositeList = new List<string>();
@ -145,7 +117,7 @@ public partial class CoreConfigV2rayService
var expectedIPs = new List<string>(); var expectedIPs = new List<string>();
var regionNames = new HashSet<string>(); var regionNames = new HashSet<string>();
var bootstrapDNSAddress = ParseDnsAddresses(simpleDNSItem?.BootstrapDNS, Global.DomainPureIPDNSAddress.First()); var bootstrapDNSAddress = ParseDnsAddresses(simpleDNSItem?.BootstrapDNS, Global.DomainPureIPDNSAddress.FirstOrDefault());
var dnsServerDomains = new List<string>(); var dnsServerDomains = new List<string>();
foreach (var dns in directDNSAddress) foreach (var dns in directDNSAddress)
@ -199,48 +171,51 @@ public partial class CoreConfigV2rayService
var routing = await ConfigHandler.GetDefaultRouting(_config); var routing = await ConfigHandler.GetDefaultRouting(_config);
List<RulesItem>? rules = null; List<RulesItem>? rules = null;
rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? []; if (routing != null)
foreach (var item in rules)
{ {
if (!item.Enabled || item.Domain is null || item.Domain.Count == 0) rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
foreach (var item in rules)
{ {
continue; if (!item.Enabled || item.Domain is null || item.Domain.Count == 0)
}
if (item.RuleType == ERuleType.Routing)
{
continue;
}
foreach (var domain in item.Domain)
{
if (domain.StartsWith('#'))
{ {
continue; continue;
} }
var normalizedDomain = domain.Replace(Global.RoutingRuleComma, ","); if (item.RuleType == ERuleType.Routing)
if (item.OutboundTag == Global.DirectTag)
{ {
if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) continue;
{
(regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain);
}
else
{
directDomainList.Add(normalizedDomain);
}
} }
else if (item.OutboundTag != Global.BlockTag)
foreach (var domain in item.Domain)
{ {
if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:")) if (domain.StartsWith('#'))
{ {
proxyGeositeList.Add(normalizedDomain); continue;
} }
else
var normalizedDomain = domain.Replace(Global.RoutingRuleComma, ",");
if (item.OutboundTag == Global.DirectTag)
{ {
proxyDomainList.Add(normalizedDomain); if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:"))
{
(regionNames.Contains(normalizedDomain) ? expectedDomainList : directGeositeList).Add(normalizedDomain);
}
else
{
directDomainList.Add(normalizedDomain);
}
}
else if (item.OutboundTag != Global.BlockTag)
{
if (normalizedDomain.StartsWith("geosite:") || normalizedDomain.StartsWith("ext:"))
{
proxyGeositeList.Add(normalizedDomain);
}
else
{
proxyDomainList.Add(normalizedDomain);
}
} }
} }
} }
@ -269,7 +244,8 @@ public partial class CoreConfigV2rayService
} }
} }
dnsItem.servers ??= []; v2rayConfig.dns ??= new Dns4Ray();
v2rayConfig.dns.servers ??= new List<object>();
void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null) void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null)
{ {
@ -277,7 +253,7 @@ public partial class CoreConfigV2rayService
{ {
foreach (var dnsAddress in dnsAddresses) foreach (var dnsAddress in dnsAddresses)
{ {
dnsItem.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs)); v2rayConfig.dns.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs));
} }
} }
} }
@ -299,21 +275,22 @@ public partial class CoreConfigV2rayService
|| lastRule.Ip?.Contains("0.0.0.0/0") == true); || lastRule.Ip?.Contains("0.0.0.0/0") == true);
var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress; var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress;
dnsItem.servers.AddRange(defaultDnsServers); v2rayConfig.dns.servers.AddRange(defaultDnsServers);
return 0; return 0;
} }
private async Task<int> GenDnsHosts(Dns4Ray dnsItem, SimpleDNSItem simpleDNSItem) private async Task<int> GenDnsHosts(V2rayConfig v2rayConfig, SimpleDNSItem simpleDNSItem)
{ {
if (simpleDNSItem.AddCommonHosts == false && simpleDNSItem.UseSystemHosts == false && simpleDNSItem.Hosts.IsNullOrEmpty()) if (simpleDNSItem.AddCommonHosts == false && simpleDNSItem.UseSystemHosts == false && simpleDNSItem.Hosts.IsNullOrEmpty())
{ {
return await Task.FromResult(0); return await Task.FromResult(0);
} }
dnsItem.hosts ??= new Dictionary<string, object>(); v2rayConfig.dns ??= new Dns4Ray();
v2rayConfig.dns.hosts ??= new Dictionary<string, object>();
if (simpleDNSItem.AddCommonHosts == true) if (simpleDNSItem.AddCommonHosts == true)
{ {
dnsItem.hosts = Global.PredefinedHosts.ToDictionary( v2rayConfig.dns.hosts = Global.PredefinedHosts.ToDictionary(
kvp => kvp.Key, kvp => kvp.Key,
kvp => (object)kvp.Value kvp => (object)kvp.Value
); );
@ -322,7 +299,7 @@ public partial class CoreConfigV2rayService
if (simpleDNSItem.UseSystemHosts == true) if (simpleDNSItem.UseSystemHosts == true)
{ {
var systemHosts = Utils.GetSystemHosts(); var systemHosts = Utils.GetSystemHosts();
var normalHost = dnsItem.hosts; var normalHost = v2rayConfig?.dns?.hosts;
if (normalHost != null && systemHosts?.Count > 0) if (normalHost != null && systemHosts?.Count > 0)
{ {
@ -339,7 +316,7 @@ public partial class CoreConfigV2rayService
foreach (var kvp in userHostsMap) foreach (var kvp in userHostsMap)
{ {
dnsItem.hosts[kvp.Key] = kvp.Value; v2rayConfig.dns.hosts[kvp.Key] = kvp.Value;
} }
} }
return await Task.FromResult(0); return await Task.FromResult(0);

View file

@ -144,12 +144,13 @@ public partial class CoreConfigV2rayService
usersItem.email = Global.UserEMail; usersItem.email = Global.UserEMail;
usersItem.encryption = protocolExtra.VlessEncryption; usersItem.encryption = protocolExtra.VlessEncryption;
if (!protocolExtra.Flow.IsNullOrEmpty()) if (protocolExtra.Flow.IsNullOrEmpty())
{ {
usersItem.flow = protocolExtra.Flow; await GenOutboundMux(node, outbound, muxEnabled, muxEnabled);
} }
else else
{ {
usersItem.flow = protocolExtra.Flow;
await GenOutboundMux(node, outbound, false, muxEnabled); await GenOutboundMux(node, outbound, false, muxEnabled);
} }
outbound.settings.servers = null; outbound.settings.servers = null;
@ -326,7 +327,6 @@ public partial class CoreConfigV2rayService
else if (!node.CertSha.IsNullOrEmpty()) else if (!node.CertSha.IsNullOrEmpty())
{ {
tlsSettings.pinnedPeerCertSha256 = node.CertSha; tlsSettings.pinnedPeerCertSha256 = node.CertSha;
tlsSettings.allowInsecure = false;
} }
streamSettings.tlsSettings = tlsSettings; streamSettings.tlsSettings = tlsSettings;
} }
@ -366,33 +366,14 @@ 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(); kcpSettings.header = new Header4Ray
if (Global.KcpHeaderMaskMap.TryGetValue(node.HeaderType, out var header))
{ {
streamSettings.finalmask.udp = type = node.HeaderType,
[ domain = host.NullIfEmpty()
new Mask4Ray };
{ if (path.IsNotEmpty())
type = header,
settings = node.HeaderType == "dns" && !host.IsNullOrEmpty() ? new MaskSettings4Ray { domain = host } : null
}
];
}
streamSettings.finalmask.udp ??= [];
if (path.IsNullOrEmpty())
{ {
streamSettings.finalmask.udp.Add(new Mask4Ray kcpSettings.seed = path;
{
type = "mkcp-original"
});
}
else
{
streamSettings.finalmask.udp.Add(new Mask4Ray
{
type = "mkcp-aes128gcm",
settings = new MaskSettings4Ray { password = path }
});
} }
streamSettings.kcpSettings = kcpSettings; streamSettings.kcpSettings = kcpSettings;
break; break;
@ -514,10 +495,10 @@ public partial class CoreConfigV2rayService
var ports = protocolExtra?.Ports; var ports = protocolExtra?.Ports;
int? upMbps = protocolExtra?.UpMbps is { } su and >= 0 int? upMbps = protocolExtra?.UpMbps is { } su and >= 0
? su ? su
: _config.HysteriaItem.UpMbps; : 0;
int? downMbps = protocolExtra?.DownMbps is { } sd and >= 0 int? downMbps = protocolExtra?.DownMbps is { } sd and >= 0
? sd ? sd
: _config.HysteriaItem.UpMbps; : 0;
var hopInterval = protocolExtra?.HopInterval is { } hi and >= 5 var hopInterval = protocolExtra?.HopInterval is { } hi and >= 5
? hi ? hi
: _config.HysteriaItem.HopInterval >= 5 ? _config.HysteriaItem.HopInterval : Global.Hysteria2DefaultHopInt; : _config.HysteriaItem.HopInterval >= 5 ? _config.HysteriaItem.HopInterval : Global.Hysteria2DefaultHopInt;
@ -531,7 +512,7 @@ public partial class CoreConfigV2rayService
interval = hopInterval, interval = hopInterval,
}; };
} }
streamSettings.hysteriaSettings = new() HysteriaSettings4Ray hysteriaSettings = new()
{ {
version = 2, version = 2,
auth = node.Password, auth = node.Password,
@ -539,17 +520,11 @@ public partial class CoreConfigV2rayService
down = downMbps > 0 ? $"{downMbps}mbps" : null, down = downMbps > 0 ? $"{downMbps}mbps" : null,
udphop = udpHop, udphop = udpHop,
}; };
if (!protocolExtra.SalamanderPass.IsNullOrEmpty()) streamSettings.hysteriaSettings = hysteriaSettings;
if (node.Path.IsNotEmpty())
{ {
streamSettings.finalmask ??= new(); streamSettings.udpmasks =
streamSettings.finalmask.udp = [new UdpMasks4Ray { type = "salamander", settings = new UdpMasksSettings4Ray { password = node.Path.TrimEx(), } }];
[
new Mask4Ray
{
type = "salamander",
settings = new MaskSettings4Ray { password = protocolExtra.SalamanderPass.TrimEx(), }
}
];
} }
break; break;

View file

@ -17,9 +17,6 @@ public class AddServerViewModel : MyReactiveObject
[Reactive] [Reactive]
public string CertSha { get; set; } public string CertSha { get; set; }
[Reactive]
public string SalamanderPass { get; set; }
[Reactive] [Reactive]
public int AlterId { get; set; } public int AlterId { get; set; }
@ -112,9 +109,8 @@ public class AddServerViewModel : MyReactiveObject
Ports = protocolExtra?.Ports ?? string.Empty; Ports = protocolExtra?.Ports ?? string.Empty;
AlterId = int.TryParse(protocolExtra?.AlterId, out var result) ? result : 0; AlterId = int.TryParse(protocolExtra?.AlterId, out var result) ? result : 0;
Flow = protocolExtra?.Flow ?? string.Empty; Flow = protocolExtra?.Flow ?? string.Empty;
SalamanderPass = protocolExtra?.SalamanderPass ?? string.Empty; UpMbps = protocolExtra?.UpMbps ?? 0;
UpMbps = protocolExtra?.UpMbps ?? _config.HysteriaItem.UpMbps; DownMbps = protocolExtra?.DownMbps ?? 0;
DownMbps = protocolExtra?.DownMbps ?? _config.HysteriaItem.DownMbps;
HopInterval = protocolExtra?.HopInterval ?? Global.Hysteria2DefaultHopInt; HopInterval = protocolExtra?.HopInterval ?? Global.Hysteria2DefaultHopInt;
VmessSecurity = protocolExtra?.VmessSecurity?.IsNullOrEmpty() == false ? protocolExtra.VmessSecurity : Global.DefaultSecurity; VmessSecurity = protocolExtra?.VmessSecurity?.IsNullOrEmpty() == false ? protocolExtra.VmessSecurity : Global.DefaultSecurity;
VlessEncryption = protocolExtra?.VlessEncryption.IsNullOrEmpty() == false ? protocolExtra.VlessEncryption : Global.None; VlessEncryption = protocolExtra?.VlessEncryption.IsNullOrEmpty() == false ? protocolExtra.VlessEncryption : Global.None;
@ -172,20 +168,19 @@ public class AddServerViewModel : MyReactiveObject
SelectedSource.CertSha = CertSha.IsNullOrEmpty() ? string.Empty : CertSha; SelectedSource.CertSha = CertSha.IsNullOrEmpty() ? string.Empty : CertSha;
SelectedSource.SetProtocolExtra(SelectedSource.GetProtocolExtra() with SelectedSource.SetProtocolExtra(SelectedSource.GetProtocolExtra() with
{ {
Ports = Ports.NullIfEmpty(), Ports = Ports.IsNullOrEmpty() ? null : Ports,
AlterId = AlterId > 0 ? AlterId.ToString() : null, AlterId = AlterId > 0 ? AlterId.ToString() : string.Empty,
Flow = Flow.NullIfEmpty(), Flow = Flow.IsNullOrEmpty() ? null : Flow,
SalamanderPass = SalamanderPass.NullIfEmpty(), UpMbps = UpMbps > 0 ? UpMbps : null,
UpMbps = UpMbps >= 0 ? UpMbps : null, DownMbps = DownMbps > 0 ? DownMbps : null,
DownMbps = DownMbps >= 0 ? DownMbps : null,
HopInterval = HopInterval >= 5 ? HopInterval : null, HopInterval = HopInterval >= 5 ? HopInterval : null,
VmessSecurity = VmessSecurity.NullIfEmpty(), VmessSecurity = VmessSecurity.IsNullOrEmpty() ? null : VmessSecurity,
VlessEncryption = VlessEncryption.NullIfEmpty(), VlessEncryption = VlessEncryption.IsNullOrEmpty() ? null : VlessEncryption,
SsMethod = SsMethod.NullIfEmpty(), SsMethod = SsMethod.IsNullOrEmpty() ? null : SsMethod,
Username = Username.NullIfEmpty(), Username = Username.IsNullOrEmpty() ? null : Username,
WgPublicKey = WgPublicKey.NullIfEmpty(), WgPublicKey = WgPublicKey.IsNullOrEmpty() ? null : WgPublicKey,
WgInterfaceAddress = WgInterfaceAddress.NullIfEmpty(), WgInterfaceAddress = WgInterfaceAddress.IsNullOrEmpty() ? null : WgInterfaceAddress,
WgReserved = WgReserved.NullIfEmpty(), WgReserved = WgReserved.IsNullOrEmpty() ? null : WgReserved,
WgMtu = WgMtu >= 576 ? WgMtu : null, WgMtu = WgMtu >= 576 ? WgMtu : null,
}); });

View file

@ -9,12 +9,11 @@ public class DNSSettingViewModel : MyReactiveObject
[Reactive] public string? DirectDNS { get; set; } [Reactive] public string? DirectDNS { get; set; }
[Reactive] public string? RemoteDNS { get; set; } [Reactive] public string? RemoteDNS { get; set; }
[Reactive] public string? BootstrapDNS { get; set; } [Reactive] public string? BootstrapDNS { get; set; }
[Reactive] public string? Strategy4Freedom { get; set; } [Reactive] public string? RayStrategy4Freedom { get; set; }
[Reactive] public string? Strategy4Proxy { get; set; } [Reactive] public string? SingboxStrategy4Direct { get; set; }
[Reactive] public string? SingboxStrategy4Proxy { get; set; }
[Reactive] public string? Hosts { get; set; } [Reactive] public string? Hosts { get; set; }
[Reactive] public string? DirectExpectedIPs { get; set; } [Reactive] public string? DirectExpectedIPs { get; set; }
[Reactive] public bool? ParallelQuery { get; set; }
[Reactive] public bool? ServeStale { get; set; }
[Reactive] public bool UseSystemHostsCompatible { get; set; } [Reactive] public bool UseSystemHostsCompatible { get; set; }
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } [Reactive] public string DomainStrategy4FreedomCompatible { get; set; }
@ -71,12 +70,11 @@ public class DNSSettingViewModel : MyReactiveObject
DirectDNS = item.DirectDNS; DirectDNS = item.DirectDNS;
RemoteDNS = item.RemoteDNS; RemoteDNS = item.RemoteDNS;
BootstrapDNS = item.BootstrapDNS; BootstrapDNS = item.BootstrapDNS;
Strategy4Freedom = item.Strategy4Freedom; RayStrategy4Freedom = item.RayStrategy4Freedom;
Strategy4Proxy = item.Strategy4Proxy; SingboxStrategy4Direct = item.SingboxStrategy4Direct;
SingboxStrategy4Proxy = item.SingboxStrategy4Proxy;
Hosts = item.Hosts; Hosts = item.Hosts;
DirectExpectedIPs = item.DirectExpectedIPs; DirectExpectedIPs = item.DirectExpectedIPs;
ParallelQuery = item.ParallelQuery;
ServeStale = item.ServeStale;
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray); var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
RayCustomDNSEnableCompatible = item1.Enabled; RayCustomDNSEnableCompatible = item1.Enabled;
@ -102,12 +100,11 @@ public class DNSSettingViewModel : MyReactiveObject
_config.SimpleDNSItem.DirectDNS = DirectDNS; _config.SimpleDNSItem.DirectDNS = DirectDNS;
_config.SimpleDNSItem.RemoteDNS = RemoteDNS; _config.SimpleDNSItem.RemoteDNS = RemoteDNS;
_config.SimpleDNSItem.BootstrapDNS = BootstrapDNS; _config.SimpleDNSItem.BootstrapDNS = BootstrapDNS;
_config.SimpleDNSItem.Strategy4Freedom = Strategy4Freedom; _config.SimpleDNSItem.RayStrategy4Freedom = RayStrategy4Freedom;
_config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy; _config.SimpleDNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct;
_config.SimpleDNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy;
_config.SimpleDNSItem.Hosts = Hosts; _config.SimpleDNSItem.Hosts = Hosts;
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs; _config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
_config.SimpleDNSItem.ParallelQuery = ParallelQuery;
_config.SimpleDNSItem.ServeStale = ServeStale;
if (NormalDNSCompatible.IsNotEmpty()) if (NormalDNSCompatible.IsNotEmpty())
{ {

View file

@ -144,7 +144,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
case EConfigType.Hysteria2: case EConfigType.Hysteria2:
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SalamanderPass, v => v.txtPath7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Ports, v => v.txtPorts7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Ports, v => v.txtPorts7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.HopInterval, v => v.txtHopInt7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.HopInterval, v => v.txtHopInt7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.UpMbps, v => v.txtUpMbps7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.UpMbps, v => v.txtUpMbps7.Text).DisposeWith(disposables);
@ -152,8 +152,8 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
break; break;
case EConfigType.TUIC: case EConfigType.TUIC:
this.Bind(ViewModel, vm => vm.Username, v => v.txtId8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Username, v => v.txtSecurity8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables);
break; break;

View file

@ -61,15 +61,7 @@
Grid.Column="1" Grid.Column="1"
Width="300" Width="300"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
IsEditable="True" /> IsEditable="True" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbDomesticDNSTips}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@ -83,7 +75,6 @@
Grid.Column="1" Grid.Column="1"
Width="300" Width="300"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
IsEditable="True" /> IsEditable="True" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@ -105,7 +96,6 @@
Grid.Column="1" Grid.Column="1"
Width="300" Width="300"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
IsEditable="True" /> IsEditable="True" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@ -115,77 +105,60 @@
Text="{x:Static resx:ResUI.TbBootstrapDNSTips}" Text="{x:Static resx:ResUI.TbBootstrapDNSTips}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbXrayFreedomStrategy}" />
<ComboBox
x:Name="cmbRayFreedomDNSStrategy"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
PlaceholderText="Default" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbDirectResolveStrategy}" /> Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
<ComboBox <ComboBox
x:Name="cmbDirectDNSStrategy" x:Name="cmbSBDirectDNSStrategy"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
PlaceholderText="Default" /> PlaceholderText="Default" />
<TextBlock
Grid.Row="5"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbDirectResolveStrategyTips}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="6"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRemoteResolveStrategy}" /> Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
<ComboBox <ComboBox
x:Name="cmbRemoteDNSStrategy" x:Name="cmbSBRemoteDNSStrategy"
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
PlaceholderText="Default" /> PlaceholderText="Default" />
<TextBlock
Grid.Row="6"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRemoteResolveStrategyTips}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbParallelQuery}" /> Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
<ToggleSwitch <ToggleSwitch
x:Name="togParallelQuery" x:Name="togAddCommonHosts"
Grid.Row="7" Grid.Row="7"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left" />
VerticalAlignment="Center" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbServeStale}" />
<ToggleSwitch
x:Name="togServeStale"
Grid.Row="8"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@ -196,7 +169,7 @@
x:Name="gridAdvancedDNSSettings" x:Name="gridAdvancedDNSSettings"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
ColumnDefinitions="Auto,Auto,*" ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,*"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,*">
<TextBlock <TextBlock
x:Name="txtAdvancedDNSSettingsInvalid" x:Name="txtAdvancedDNSSettingsInvalid"
@ -217,38 +190,22 @@
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left" />
VerticalAlignment="Center" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
<ToggleSwitch
x:Name="togAddCommonHosts"
Grid.Row="2"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFakeIP}" /> Text="{x:Static resx:ResUI.TbFakeIP}" />
<ToggleSwitch <ToggleSwitch
x:Name="togFakeIP" x:Name="togFakeIP"
Grid.Row="3" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left" />
VerticalAlignment="Center" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -256,20 +213,19 @@
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="3"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" /> Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
<ToggleSwitch <ToggleSwitch
x:Name="togBlockBindingQuery" x:Name="togBlockBindingQuery"
Grid.Row="4" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left" />
VerticalAlignment="Center" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="3"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -277,21 +233,20 @@
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" /> Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
<ComboBox <ComboBox
x:Name="cmbDirectExpectedIPs" x:Name="cmbDirectExpectedIPs"
Grid.Row="5" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
IsEditable="True" /> IsEditable="True" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="4"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -299,7 +254,7 @@
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
@ -308,7 +263,7 @@
<TextBox <TextBox
x:Name="txtHosts" x:Name="txtHosts"
Grid.Row="7" Grid.Row="6"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"

View file

@ -15,15 +15,16 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
btnCancel.Click += (s, e) => Close(); btnCancel.Click += (s, e) => Close();
ViewModel = new DNSSettingViewModel(UpdateViewHandler); ViewModel = new DNSSettingViewModel(UpdateViewHandler);
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy; cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms;
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy; cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress; cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress; cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs; cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy; cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4OutCompatible.ItemsSource = Global.DomainStrategies4Sbox; cmbdomainStrategy4OutCompatible.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress; cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress;
cmbdomainDNSAddress2Compatible.ItemsSource = Global.DomainPureIPDNSAddress; cmbdomainDNSAddress2Compatible.ItemsSource = Global.DomainPureIPDNSAddress;
@ -36,12 +37,11 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);

View file

@ -26,7 +26,7 @@ public partial class RoutingRuleSettingWindow : WindowBase<RoutingRuleSettingVie
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler); ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty(); cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty();
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Sbox; cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {

View file

@ -22,7 +22,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
ViewModel = new RoutingSettingViewModel(UpdateViewHandler); ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies; cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Sbox; cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {

View file

@ -139,7 +139,7 @@ public partial class AddServerWindow
case EConfigType.Hysteria2: case EConfigType.Hysteria2:
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SalamanderPass, v => v.txtPath7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Ports, v => v.txtPorts7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Ports, v => v.txtPorts7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.HopInterval, v => v.txtHopInt7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.HopInterval, v => v.txtHopInt7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.UpMbps, v => v.txtUpMbps7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.UpMbps, v => v.txtUpMbps7.Text).DisposeWith(disposables);
@ -147,8 +147,8 @@ public partial class AddServerWindow
break; break;
case EConfigType.TUIC: case EConfigType.TUIC:
this.Bind(ViewModel, vm => vm.Username, v => v.txtId8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Username, v => v.txtSecurity8.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.Text).DisposeWith(disposables);
break; break;

View file

@ -84,14 +84,6 @@
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
IsEditable="True" IsEditable="True"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbDomesticDNSTips}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@ -141,29 +133,37 @@
Text="{x:Static resx:ResUI.TbBootstrapDNSTips}" Text="{x:Static resx:ResUI.TbBootstrapDNSTips}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbXrayFreedomStrategy}" />
<ComboBox
x:Name="cmbRayFreedomDNSStrategy"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbDirectResolveStrategy}" /> Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
<ComboBox <ComboBox
x:Name="cmbDirectDNSStrategy" x:Name="cmbSBDirectDNSStrategy"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="Default" materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="5"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbDirectResolveStrategyTips}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="6"
@ -171,23 +171,15 @@
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRemoteResolveStrategy}" /> Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
<ComboBox <ComboBox
x:Name="cmbRemoteDNSStrategy" x:Name="cmbSBRemoteDNSStrategy"
Grid.Row="6" Grid.Row="6"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
materialDesign:HintAssist.Hint="Default" materialDesign:HintAssist.Hint="Default"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="6"
Grid.Column="2"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRemoteResolveStrategyTips}"
TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="7" Grid.Row="7"
@ -195,27 +187,13 @@
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbParallelQuery}" /> Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
<ToggleButton <ToggleButton
x:Name="togParallelQuery" x:Name="togAddCommonHosts"
Grid.Row="7" Grid.Row="7"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbServeStale}" />
<ToggleButton
x:Name="togServeStale"
Grid.Row="8"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@ -229,7 +207,6 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@ -268,29 +245,15 @@
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" /> Text="{x:Static resx:ResUI.TbFakeIP}" />
<ToggleButton <ToggleButton
x:Name="togAddCommonHosts" x:Name="togFakeIP"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFakeIP}" />
<ToggleButton
x:Name="togFakeIP"
Grid.Row="3"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="3"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -299,7 +262,7 @@
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="3"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -307,12 +270,12 @@
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" /> Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueries}" />
<ToggleButton <ToggleButton
x:Name="togBlockBindingQuery" x:Name="togBlockBindingQuery"
Grid.Row="4" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="3"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -321,7 +284,7 @@
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -329,14 +292,14 @@
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" /> Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPs}" />
<ComboBox <ComboBox
x:Name="cmbDirectExpectedIPs" x:Name="cmbDirectExpectedIPs"
Grid.Row="5" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
IsEditable="True" IsEditable="True"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="4"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -345,7 +308,7 @@
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock <TextBlock
Grid.Row="6" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
@ -354,7 +317,7 @@
Text="{x:Static resx:ResUI.TbDNSHostsConfig}" /> Text="{x:Static resx:ResUI.TbDNSHostsConfig}" />
<TextBox <TextBox
x:Name="txtHosts" x:Name="txtHosts"
Grid.Row="7" Grid.Row="6"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"

View file

@ -13,15 +13,16 @@ public partial class DNSSettingWindow
ViewModel = new DNSSettingViewModel(UpdateViewHandler); ViewModel = new DNSSettingViewModel(UpdateViewHandler);
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy; cmbRayFreedomDNSStrategy.ItemsSource = Global.DomainStrategy4Freedoms;
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy; cmbSBDirectDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress; cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress; cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress; cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs; cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy; cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
cmbdomainStrategy4OutCompatible.ItemsSource = Global.DomainStrategies4Sbox; cmbdomainStrategy4OutCompatible.ItemsSource = Global.SingboxDomainStrategy4Out;
cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress; cmbdomainDNSAddressCompatible.ItemsSource = Global.DomainPureIPDNSAddress;
cmbdomainDNSAddress2Compatible.ItemsSource = Global.DomainPureIPDNSAddress; cmbdomainDNSAddress2Compatible.ItemsSource = Global.DomainPureIPDNSAddress;
@ -34,12 +35,11 @@ public partial class DNSSettingWindow
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);

View file

@ -18,7 +18,7 @@ public partial class RoutingRuleSettingWindow
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler); ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty(); cmbdomainStrategy.ItemsSource = Global.DomainStrategies.AppendEmpty();
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Sbox; cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {

View file

@ -17,7 +17,7 @@ public partial class RoutingSettingWindow
ViewModel = new RoutingSettingViewModel(UpdateViewHandler); ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies; cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Sbox; cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {