mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-11 06:54:58 +03:00
Compare commits
37 Commits
165e0bf9e9
...
7.24.4
| Author | SHA1 | Date | |
|---|---|---|---|
| 635a04d74c | |||
| 2e1bb23da7 | |||
| 6f3bacd5b4 | |||
| 074ce5de04 | |||
| 02df430172 | |||
| 611ce0fd2c | |||
| a846e74e8f | |||
| 92c3df45ae | |||
| ee7e21268a | |||
| dc216c2b02 | |||
| beffa919d3 | |||
| a654826231 | |||
| b01476d147 | |||
| cf8dd45abe | |||
| 9bba6f53f8 | |||
| cd77f1d882 | |||
| 0427037638 | |||
| e749b81ecf | |||
| fd2c942231 | |||
| fa42eb670f | |||
| 0d42996573 | |||
| a37772f12b | |||
| 531e0e9443 | |||
| 984c77f0c4 | |||
| b5e0be47a5 | |||
| 6df0e6de1b | |||
| 2b5328665f | |||
| 4584ecc5c9 | |||
| d9dc2d7cf5 | |||
| 36f8565b7a | |||
| f55d8b2565 | |||
| 09ea4890a7 | |||
| 5cc2aaba13 | |||
| b8889bad86 | |||
| 5dd5b25869 | |||
| fafdb4a0b6 | |||
| 223642dd67 |
@@ -1,3 +1,49 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
THIRD-PARTY CA CERTIFICATE DATA ATTRIBUTION
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This component includes CA certificate data obtained from third-party sources.
|
||||||
|
|
||||||
|
1. Common CA Database (CCADB)
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Website:
|
||||||
|
https://www.ccadb.org/
|
||||||
|
|
||||||
|
Data source:
|
||||||
|
https://ccadb.my.salesforce-sites.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites
|
||||||
|
|
||||||
|
License:
|
||||||
|
Community Data License Agreement – Permissive, Version 2.0 (CDLA-2.0 Permissive)
|
||||||
|
|
||||||
|
The names and trademarks of CCADB contributors may not be used to endorse or
|
||||||
|
promote products derived from this data without prior written permission.
|
||||||
|
|
||||||
|
License text:
|
||||||
|
https://cdla.dev/permissive-2-0/
|
||||||
|
|
||||||
|
|
||||||
|
2. Chromium Root Store
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Source:
|
||||||
|
Chromium Project
|
||||||
|
|
||||||
|
Data source:
|
||||||
|
https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT
|
||||||
|
|
||||||
|
License:
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright:
|
||||||
|
Copyright (c) The Chromium Authors
|
||||||
|
|
||||||
|
The Chromium Root Store data is distributed under the BSD 3-Clause License.
|
||||||
|
|
||||||
|
License text:
|
||||||
|
https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -27,68 +73,23 @@ Console.WriteLine("\nAll done!");
|
|||||||
|
|
||||||
async Task ProcessMozillaAsync(string outputDir)
|
async Task ProcessMozillaAsync(string outputDir)
|
||||||
{
|
{
|
||||||
const string certdataUrl = "https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt";
|
const string certdataUrl = "https://ccadb.my.salesforce-sites.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites";
|
||||||
var outputFile = Path.Combine(outputDir, "mozilla_roots_pem");
|
var outputFile = Path.Combine(outputDir, "mozilla_roots_pem");
|
||||||
|
|
||||||
Console.WriteLine("Downloading Mozilla certdata.txt...");
|
Console.WriteLine("Downloading Mozilla certdata.txt...");
|
||||||
var content = await client.GetStringAsync(certdataUrl);
|
var content = await client.GetStringAsync(certdataUrl);
|
||||||
|
|
||||||
Console.WriteLine("Parsing MULTILINE_OCTAL to PEM...");
|
var pemMatches = Regex.Matches(content, @"(-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----)");
|
||||||
var pems = ParseMozillaCertData(content);
|
var pems = new List<string>();
|
||||||
|
foreach (Match m in pemMatches)
|
||||||
|
{
|
||||||
|
pems.Add(m.Groups[1].Value.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
await File.WriteAllTextAsync(outputFile, string.Join("\n\n", pems));
|
await File.WriteAllTextAsync(outputFile, string.Join("\n\n", pems));
|
||||||
Console.WriteLine($"Mozilla roots saved to: {outputFile} ({pems.Count} certificates)");
|
Console.WriteLine($"Mozilla roots saved to: {outputFile} ({pems.Count} certificates)");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> ParseMozillaCertData(string text)
|
|
||||||
{
|
|
||||||
var pems = new List<string>();
|
|
||||||
|
|
||||||
var matches = Regex.Matches(text,
|
|
||||||
@"CKA_VALUE MULTILINE_OCTAL\s*([\s\S]*?)\s*END",
|
|
||||||
RegexOptions.Multiline);
|
|
||||||
|
|
||||||
foreach (Match m in matches)
|
|
||||||
{
|
|
||||||
var octalBlock = m.Groups[1].Value.Trim();
|
|
||||||
var der = OctalToBytes(octalBlock);
|
|
||||||
if (der.Length > 0)
|
|
||||||
{
|
|
||||||
var pem = ConvertToPem(der);
|
|
||||||
pems.Add(pem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pems;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] OctalToBytes(string octalBlock)
|
|
||||||
{
|
|
||||||
var bytes = new List<byte>();
|
|
||||||
var matches = Regex.Matches(octalBlock, @"\\(\d{1,3})");
|
|
||||||
foreach (Match m in matches)
|
|
||||||
{
|
|
||||||
bytes.Add((byte)Convert.ToInt32(m.Groups[1].Value, 8));
|
|
||||||
}
|
|
||||||
return bytes.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
string ConvertToPem(byte[] der)
|
|
||||||
{
|
|
||||||
var base64 = Convert.ToBase64String(der);
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append("-----BEGIN CERTIFICATE-----\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < base64.Length; i += 64)
|
|
||||||
{
|
|
||||||
var length = Math.Min(64, base64.Length - i);
|
|
||||||
sb.Append(base64.Substring(i, length));
|
|
||||||
sb.Append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Append("-----END CERTIFICATE-----\n");
|
|
||||||
return sb.ToString().TrimEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task ProcessChromeAsync(string outputDir)
|
async Task ProcessChromeAsync(string outputDir)
|
||||||
{
|
{
|
||||||
const string chromeCertsUrl = "https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT";
|
const string chromeCertsUrl = "https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT";
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
deb-loong64:
|
deb-loong64:
|
||||||
name: build and release deb loong64
|
name: build and release deb loong64
|
||||||
if: (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
if: (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-26.04-arm
|
||||||
env:
|
env:
|
||||||
RELEASE_TAG: ${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}
|
RELEASE_TAG: ${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}
|
||||||
QCOW2_URL: https://github.com/xujiegb/debian-loong64-qcow2/releases/download/13.5/debian13-loong64.qcow2
|
QCOW2_URL: https://github.com/xujiegb/debian-loong64-qcow2/releases/download/13.5/debian13-loong64.qcow2
|
||||||
@@ -234,10 +234,10 @@ jobs:
|
|||||||
- name: Download QEMU prebuild
|
- name: Download QEMU prebuild
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
wget -O qemu-linux-x64-v3.tar.gz "https://github.com/xujiegb/qemu-linux-prebuild/releases/download/${QEMU_VERSION}/qemu-linux-x64-v3.tar.gz"
|
wget -O qemu-linux-arm64-v8.2.tar.gz "https://github.com/xujiegb/qemu-linux-prebuild/releases/download/${QEMU_VERSION}/qemu-linux-arm64-v8.2.tar.gz"
|
||||||
tar -xzf qemu-linux-x64-v3.tar.gz
|
tar -xzf qemu-linux-arm64-v8.2.tar.gz
|
||||||
mkdir -p "$HOME/qemu-install"
|
mkdir -p "$HOME/qemu-install"
|
||||||
rsync -a qemu-linux-x64-v3/ "$HOME/qemu-install/"
|
rsync -a qemu-linux-arm64-v8.2/ "$HOME/qemu-install/"
|
||||||
"$HOME/qemu-install/bin/qemu-system-loongarch64" --version
|
"$HOME/qemu-install/bin/qemu-system-loongarch64" --version
|
||||||
- name: Download loong64 qcow2 and EFI firmware
|
- name: Download loong64 qcow2 and EFI firmware
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -355,7 +355,7 @@ jobs:
|
|||||||
rpm-loong64:
|
rpm-loong64:
|
||||||
name: build and release rpm loong64
|
name: build and release rpm loong64
|
||||||
if: (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
if: (github.event_name == 'workflow_dispatch' && inputs.release_tag != '') || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-26.04-arm
|
||||||
env:
|
env:
|
||||||
RELEASE_TAG: ${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}
|
RELEASE_TAG: ${{ case(inputs.release_tag != '', inputs.release_tag, github.ref_name) }}
|
||||||
QCOW2_URL: https://github.com/xujiegb/fedora-loong64-qcow2/releases/download/43/fedora43-loong64.qcow2
|
QCOW2_URL: https://github.com/xujiegb/fedora-loong64-qcow2/releases/download/43/fedora43-loong64.qcow2
|
||||||
@@ -384,10 +384,10 @@ jobs:
|
|||||||
- name: Download QEMU prebuild
|
- name: Download QEMU prebuild
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
wget -O qemu-linux-x64-v3.tar.gz "https://github.com/xujiegb/qemu-linux-prebuild/releases/download/${QEMU_VERSION}/qemu-linux-x64-v3.tar.gz"
|
wget -O qemu-linux-arm64-v8.2.tar.gz "https://github.com/xujiegb/qemu-linux-prebuild/releases/download/${QEMU_VERSION}/qemu-linux-arm64-v8.2.tar.gz"
|
||||||
tar -xzf qemu-linux-x64-v3.tar.gz
|
tar -xzf qemu-linux-arm64-v8.2.tar.gz
|
||||||
mkdir -p "$HOME/qemu-install"
|
mkdir -p "$HOME/qemu-install"
|
||||||
rsync -a qemu-linux-x64-v3/ "$HOME/qemu-install/"
|
rsync -a qemu-linux-arm64-v8.2/ "$HOME/qemu-install/"
|
||||||
"$HOME/qemu-install/bin/qemu-system-loongarch64" --version
|
"$HOME/qemu-install/bin/qemu-system-loongarch64" --version
|
||||||
- name: Download loong64 qcow2 and EFI firmware
|
- name: Download loong64 qcow2 and EFI firmware
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
||||||
|
|
||||||
- name: Setup .NET 10.0.1xx
|
- name: Setup .NET 10.0.1xx
|
||||||
uses: actions/setup-dotnet@v5.4.0
|
uses: actions/setup-dotnet@v6.0.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: 10.0.1xx
|
dotnet-version: 10.0.1xx
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ jobs:
|
|||||||
$xrayTag = "v$xrayVer"
|
$xrayTag = "v$xrayVer"
|
||||||
$singTag = "v$singVer"
|
$singTag = "v$singVer"
|
||||||
|
|
||||||
$xrayUrl = "https://github.com/autorepobot/Xray-core/releases/download/$xrayTag/Xray-windows-32.zip"
|
$xrayUrl = "https://github.com/XTLS/Xray-core/releases/download/$xrayTag/Xray-windows-32.zip"
|
||||||
$singUrl = "https://github.com/SagerNet/sing-box/releases/download/$singTag/sing-box-$singVer-windows-386.zip"
|
$singUrl = "https://github.com/SagerNet/sing-box/releases/download/$singTag/sing-box-$singVer-windows-386.zip"
|
||||||
|
|
||||||
Write-Host "Bundled Xray version: $xrayVer"
|
Write-Host "Bundled Xray version: $xrayVer"
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v5.4.0
|
uses: actions/setup-dotnet@v6.0.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: '10.0.1xx'
|
dotnet-version: '10.0.1xx'
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
fetch-depth: '0'
|
fetch-depth: '0'
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v5.4.0
|
uses: actions/setup-dotnet@v6.0.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: '8.0.x'
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ PKGROOT="v2rayN-publish"
|
|||||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||||
OUTPUT_DIR="${HOME}/debbuild"
|
OUTPUT_DIR="${HOME}/debbuild"
|
||||||
DOTNET_TFM="net10.0"
|
DOTNET_TFM="net10.0"
|
||||||
DOTNET_LOONGARCH_VERSION="10.0.109"
|
DOTNET_LOONGARCH_VERSION="10.0.110"
|
||||||
DOTNET_LOONGARCH_TAG="v10.0.109-loongarch64"
|
DOTNET_LOONGARCH_TAG="v10.0.110-loongarch64"
|
||||||
DOTNET_LOONGARCH_BASE="https://github.com/loongson/dotnet/releases/download"
|
DOTNET_LOONGARCH_BASE="https://github.com/loongson/dotnet/releases/download"
|
||||||
DOTNET_LOONGARCH_FILE="dotnet-sdk-${DOTNET_LOONGARCH_VERSION}-linux-loongarch64.tar.gz"
|
DOTNET_LOONGARCH_FILE="dotnet-sdk-${DOTNET_LOONGARCH_VERSION}-linux-loongarch64.tar.gz"
|
||||||
DOTNET_SDK_URL="${DOTNET_LOONGARCH_BASE}/${DOTNET_LOONGARCH_TAG}/${DOTNET_LOONGARCH_FILE}"
|
DOTNET_SDK_URL="${DOTNET_LOONGARCH_BASE}/${DOTNET_LOONGARCH_TAG}/${DOTNET_LOONGARCH_FILE}"
|
||||||
@@ -597,7 +597,7 @@ package_binary() {
|
|||||||
write_desktop_file "$stage"
|
write_desktop_file "$stage"
|
||||||
write_maintainer_scripts "$debian_dir"
|
write_maintainer_scripts "$debian_dir"
|
||||||
|
|
||||||
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)"
|
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
|
||||||
|
|
||||||
mkdir -p "$workdir/debian"
|
mkdir -p "$workdir/debian"
|
||||||
cat > "$workdir/debian/control" <<EOF
|
cat > "$workdir/debian/control" <<EOF
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ MIN_KERNEL="5.10"
|
|||||||
PKGROOT="v2rayN-publish"
|
PKGROOT="v2rayN-publish"
|
||||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||||
OUTPUT_DIR="${HOME}/debbuild"
|
OUTPUT_DIR="${HOME}/debbuild"
|
||||||
DOTNET_RISCV_VERSION="10.0.109"
|
DOTNET_RISCV_VERSION="10.0.110"
|
||||||
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
||||||
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
||||||
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
||||||
@@ -595,7 +595,7 @@ package_binary() {
|
|||||||
write_desktop_file "$stage"
|
write_desktop_file "$stage"
|
||||||
write_maintainer_scripts "$debian_dir"
|
write_maintainer_scripts "$debian_dir"
|
||||||
|
|
||||||
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)"
|
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
|
||||||
|
|
||||||
mkdir -p "$workdir/debian"
|
mkdir -p "$workdir/debian"
|
||||||
cat > "$workdir/debian/control" <<EOF
|
cat > "$workdir/debian/control" <<EOF
|
||||||
|
|||||||
+1
-1
@@ -609,7 +609,7 @@ package_binary() {
|
|||||||
write_desktop_file "$stage"
|
write_desktop_file "$stage"
|
||||||
write_maintainer_scripts "$debian_dir"
|
write_maintainer_scripts "$debian_dir"
|
||||||
|
|
||||||
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)"
|
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
|
||||||
|
|
||||||
mkdir -p "$workdir/debian"
|
mkdir -p "$workdir/debian"
|
||||||
cat > "$workdir/debian/control" <<EOF
|
cat > "$workdir/debian/control" <<EOF
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ MIN_KERNEL="6.12"
|
|||||||
PKGROOT="v2rayN-publish"
|
PKGROOT="v2rayN-publish"
|
||||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||||
RPM_TOPDIR="${HOME}/rpmbuild"
|
RPM_TOPDIR="${HOME}/rpmbuild"
|
||||||
DOTNET_LOONGARCH_VERSION="10.0.109"
|
DOTNET_LOONGARCH_VERSION="10.0.110"
|
||||||
DOTNET_LOONGARCH_TAG="v10.0.109-loongarch64"
|
DOTNET_LOONGARCH_TAG="v10.0.110-loongarch64"
|
||||||
DOTNET_LOONGARCH_BASE="https://github.com/loongson/dotnet/releases/download"
|
DOTNET_LOONGARCH_BASE="https://github.com/loongson/dotnet/releases/download"
|
||||||
DOTNET_LOONGARCH_FILE="dotnet-sdk-${DOTNET_LOONGARCH_VERSION}-linux-loongarch64.tar.gz"
|
DOTNET_LOONGARCH_FILE="dotnet-sdk-${DOTNET_LOONGARCH_VERSION}-linux-loongarch64.tar.gz"
|
||||||
DOTNET_SDK_URL="${DOTNET_LOONGARCH_BASE}/${DOTNET_LOONGARCH_TAG}/${DOTNET_LOONGARCH_FILE}"
|
DOTNET_SDK_URL="${DOTNET_LOONGARCH_BASE}/${DOTNET_LOONGARCH_TAG}/${DOTNET_LOONGARCH_FILE}"
|
||||||
@@ -513,9 +513,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
|||||||
Requires: glibc >= 2.39
|
Requires: glibc >= 2.39
|
||||||
Requires: fontconfig >= 2.15.0
|
Requires: fontconfig >= 2.15.0
|
||||||
Requires: desktop-file-utils >= 0.26
|
Requires: desktop-file-utils >= 0.26
|
||||||
Requires: xdg-utils >= 1.2.0
|
Requires: xdg-utils >= 1.1.3
|
||||||
Requires: coreutils >= 9.5
|
Requires: coreutils >= 9.4
|
||||||
Requires: bash >= 5.2.26
|
Requires: bash >= 5.2.21
|
||||||
Requires: freetype >= 2.13
|
Requires: freetype >= 2.13
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ MIN_KERNEL="5.10"
|
|||||||
PKGROOT="v2rayN-publish"
|
PKGROOT="v2rayN-publish"
|
||||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||||
RPM_TOPDIR="${HOME}/rpmbuild"
|
RPM_TOPDIR="${HOME}/rpmbuild"
|
||||||
DOTNET_RISCV_VERSION="10.0.109"
|
DOTNET_RISCV_VERSION="10.0.110"
|
||||||
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
||||||
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
||||||
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
||||||
@@ -512,9 +512,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
|||||||
Requires: glibc >= 2.39
|
Requires: glibc >= 2.39
|
||||||
Requires: fontconfig >= 2.15.0
|
Requires: fontconfig >= 2.15.0
|
||||||
Requires: desktop-file-utils >= 0.26
|
Requires: desktop-file-utils >= 0.26
|
||||||
Requires: xdg-utils >= 1.2.0
|
Requires: xdg-utils >= 1.1.3
|
||||||
Requires: coreutils >= 9.5
|
Requires: coreutils >= 9.4
|
||||||
Requires: bash >= 5.2.26
|
Requires: bash >= 5.2.21
|
||||||
Requires: freetype >= 2.13
|
Requires: freetype >= 2.13
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|||||||
+3
-3
@@ -501,9 +501,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
|||||||
Requires: glibc >= 2.39
|
Requires: glibc >= 2.39
|
||||||
Requires: fontconfig >= 2.15.0
|
Requires: fontconfig >= 2.15.0
|
||||||
Requires: desktop-file-utils >= 0.26
|
Requires: desktop-file-utils >= 0.26
|
||||||
Requires: xdg-utils >= 1.2.0
|
Requires: xdg-utils >= 1.1.3
|
||||||
Requires: coreutils >= 9.5
|
Requires: coreutils >= 9.4
|
||||||
Requires: bash >= 5.2.26
|
Requires: bash >= 5.2.21
|
||||||
Requires: freetype >= 2.13
|
Requires: freetype >= 2.13
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.23.4</Version>
|
<Version>7.24.4</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="12.1.0" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="12.1.0" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="12.1.0" />
|
<PackageVersion Include="Avalonia.Desktop" Version="12.1.0" />
|
||||||
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.3" />
|
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.3" />
|
||||||
<PackageVersion Include="AwesomeAssertions" Version="9.4.0" />
|
<PackageVersion Include="AwesomeAssertions" Version="9.5.0" />
|
||||||
<PackageVersion Include="DialogHost.Avalonia" Version="0.12.2" />
|
<PackageVersion Include="DialogHost.Avalonia" Version="0.12.3" />
|
||||||
<PackageVersion Include="IPNetwork2" Version="4.3.0" />
|
<PackageVersion Include="IPNetwork2" Version="4.3.0" />
|
||||||
<PackageVersion Include="ReactiveUI.Avalonia" Version="12.0.3" />
|
<PackageVersion Include="ReactiveUI.Avalonia" Version="12.0.3" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.10.2" />
|
<PackageVersion Include="CliWrap" Version="3.10.2" />
|
||||||
<PackageVersion Include="Downloader" Version="5.9.4" />
|
<PackageVersion Include="Downloader" Version="5.9.5" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.7.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
|
||||||
<PackageVersion Include="MaterialDesignThemes" Version="5.3.2" />
|
<PackageVersion Include="MaterialDesignThemes" Version="5.3.2" />
|
||||||
<PackageVersion Include="QRCoder" Version="1.8.0" />
|
<PackageVersion Include="QRCoder" Version="1.8.0" />
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="12.1.0" />
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="12.1.0" />
|
||||||
<PackageVersion Include="NLog" Version="6.1.4" />
|
<PackageVersion Include="NLog" Version="6.1.4" />
|
||||||
<PackageVersion Include="sqlite-net-e" Version="1.11.285" />
|
<PackageVersion Include="sqlite-net-e" Version="1.11.285" />
|
||||||
<PackageVersion Include="Repobot.SQLite.Unofficial" Version="3.53.3.8" />
|
<PackageVersion Include="Repobot.SQLite.Unofficial" Version="3.53.3.10" />
|
||||||
<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" />
|
||||||
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
|
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ internal static class CoreConfigTestFactory
|
|||||||
},
|
},
|
||||||
WebDavItem = new WebDavItem(),
|
WebDavItem = new WebDavItem(),
|
||||||
CheckUpdateItem = new CheckUpdateItem(),
|
CheckUpdateItem = new CheckUpdateItem(),
|
||||||
Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Length = "100-200", Interval = "10-20" },
|
Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Lengths = ["100-200"], Delays = ["10-20"] },
|
||||||
Inbound =
|
Inbound =
|
||||||
[
|
[
|
||||||
new InItem
|
new InItem
|
||||||
@@ -84,6 +84,7 @@ internal static class CoreConfigTestFactory
|
|||||||
ParallelQuery = false,
|
ParallelQuery = false,
|
||||||
Strategy4Freedom = Global.AsIs,
|
Strategy4Freedom = Global.AsIs,
|
||||||
Strategy4Proxy = Global.AsIs,
|
Strategy4Proxy = Global.AsIs,
|
||||||
|
Strategy4ProxyDial = Global.AsIs,
|
||||||
},
|
},
|
||||||
IndexId = string.Empty,
|
IndexId = string.Empty,
|
||||||
SubIndexId = string.Empty,
|
SubIndexId = string.Empty,
|
||||||
|
|||||||
@@ -592,4 +592,38 @@ public class CoreConfigSingboxServiceTests
|
|||||||
proxy.realm.stun_servers.Should().Contain("turn.cloudflare.com:3478");
|
proxy.realm.stun_servers.Should().Contain("turn.cloudflare.com:3478");
|
||||||
proxy.server.Should().BeNull();
|
proxy.server.Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GenerateClientConfigContent_TunSystemStackWithIpv6_ShouldUsePrefixWithPeerAddress()
|
||||||
|
{
|
||||||
|
// Regression test for #9820: sing-box fails with "need one more IPv6 address in
|
||||||
|
// first prefix for system stack" when the TUN inbound uses a /128 IPv6 prefix.
|
||||||
|
var config = CoreConfigTestFactory.CreateConfig(ECoreType.sing_box);
|
||||||
|
config.TunModeItem.EnableTun = true;
|
||||||
|
config.TunModeItem.Stack = "system";
|
||||||
|
config.TunModeItem.EnableIPv6Address = true;
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||||
|
|
||||||
|
var node = CoreConfigTestFactory.CreateVmessNode(ECoreType.sing_box);
|
||||||
|
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.sing_box) with
|
||||||
|
{
|
||||||
|
IsTunEnabled = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = new CoreConfigSingboxService(context).GenerateClientConfigContent();
|
||||||
|
|
||||||
|
result.Success.Should().BeTrue($"ret msg: {result.Msg}");
|
||||||
|
var cfg = JsonUtils.Deserialize<SingboxConfig>(result.Data!.ToString())!;
|
||||||
|
var tun = cfg.inbounds.First(i => i.type == "tun");
|
||||||
|
|
||||||
|
tun.address.Should().NotBeNullOrEmpty();
|
||||||
|
foreach (var address in tun.address!)
|
||||||
|
{
|
||||||
|
var prefixLength = int.Parse(address[(address.LastIndexOf('/') + 1)..]);
|
||||||
|
var isIpv6 = address.Contains(':');
|
||||||
|
prefixLength.Should().BeLessThanOrEqualTo(isIpv6 ? 126 : 30,
|
||||||
|
$"'{address}' must leave room for the peer address the system stack derives");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ public class CoreConfigV2rayServiceTests
|
|||||||
|
|
||||||
var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom");
|
var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom");
|
||||||
directOutbound.Should().NotBeNull();
|
directOutbound.Should().NotBeNull();
|
||||||
directOutbound!.settings.domainStrategy.Should().Be("UseIPv4");
|
directOutbound!.streamSettings.sockopt!.domainStrategy.Should().Be("UseIPv4");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using AwesomeAssertions;
|
||||||
|
using ServiceLib.Enums;
|
||||||
|
using ServiceLib.Manager;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ServiceLib.Tests.Manager;
|
||||||
|
|
||||||
|
public class CoreManagerTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(ECoreType.sing_box)]
|
||||||
|
[InlineData(ECoreType.mihomo)]
|
||||||
|
[InlineData(ECoreType.Xray)]
|
||||||
|
public void ShouldRunAsSudo_TunLaunchOnNonWindows_RequiresElevation(ECoreType coreType)
|
||||||
|
{
|
||||||
|
CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ShouldRunAsSudo_NonTunLaunch_ShouldNotElevate()
|
||||||
|
{
|
||||||
|
// Regression guard for the macOS TUN failure: the elevation decision must follow
|
||||||
|
// the context snapshot that generated the config. A launch whose snapshot has TUN
|
||||||
|
// disabled must never elevate, and a launch whose snapshot has TUN enabled must
|
||||||
|
// elevate regardless of later changes to the live config.
|
||||||
|
CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.sing_box, isNonWindows: true).Should().BeFalse();
|
||||||
|
CoreManager.ShouldRunAsSudo(isTunLaunch: false, ECoreType.Xray, isNonWindows: true).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ShouldRunAsSudo_OnWindows_ShouldNotElevate()
|
||||||
|
{
|
||||||
|
CoreManager.ShouldRunAsSudo(isTunLaunch: true, ECoreType.sing_box, isNonWindows: false).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(ECoreType.v2fly)]
|
||||||
|
[InlineData(ECoreType.hysteria)]
|
||||||
|
[InlineData(null)]
|
||||||
|
public void ShouldRunAsSudo_UnsupportedCoreType_ShouldNotElevate(ECoreType? coreType)
|
||||||
|
{
|
||||||
|
CoreManager.ShouldRunAsSudo(isTunLaunch: true, coreType, isNonWindows: true).Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -485,12 +485,17 @@ public class Utils
|
|||||||
|
|
||||||
public static string? DomainStrategy4Sbox(string? strategy)
|
public static string? DomainStrategy4Sbox(string? strategy)
|
||||||
{
|
{
|
||||||
|
if (strategy is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return strategy switch
|
return strategy switch
|
||||||
{
|
{
|
||||||
not null when strategy.StartsWith("UseIPv4") => "prefer_ipv4",
|
_ when strategy.StartsWith("UseIPv6") => "prefer_ipv6",
|
||||||
not null when strategy.StartsWith("UseIPv6") => "prefer_ipv6",
|
_ when strategy.StartsWith("UseIP") => "prefer_ipv4",
|
||||||
not null when strategy.StartsWith("ForceIPv4") => "ipv4_only",
|
_ when strategy.StartsWith("ForceIPv6") => "ipv6_only",
|
||||||
not null when strategy.StartsWith("ForceIPv6") => "ipv6_only",
|
_ when strategy.StartsWith("ForceIP") => "ipv4_only",
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ namespace ServiceLib;
|
|||||||
|
|
||||||
public class Global
|
public class Global
|
||||||
{
|
{
|
||||||
#region const
|
|
||||||
|
|
||||||
public const string AppName = "v2rayN";
|
public const string AppName = "v2rayN";
|
||||||
public const string GithubUrl = "https://github.com";
|
public const string GithubUrl = "https://github.com";
|
||||||
public const string GithubApiUrl = "https://api.github.com/repos";
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
@@ -106,9 +104,7 @@ public class Global
|
|||||||
public const string SingboxFakeDNSTag = "fake_dns";
|
public const string SingboxFakeDNSTag = "fake_dns";
|
||||||
|
|
||||||
public const int Hysteria2DefaultHopInt = 30;
|
public const int Hysteria2DefaultHopInt = 30;
|
||||||
|
|
||||||
public const string PolicyGroupExcludeKeywords = @"剩余|过期|到期|重置|[Rr]emaining|[Ee]xpir|[Rr]eset";
|
public const string PolicyGroupExcludeKeywords = @"剩余|过期|到期|重置|[Rr]emaining|[Ee]xpir|[Rr]eset";
|
||||||
|
|
||||||
public const string PolicyGroupDefaultAllFilter = $"^(?!.*(?:{PolicyGroupExcludeKeywords})).*$";
|
public const string PolicyGroupDefaultAllFilter = $"^(?!.*(?:{PolicyGroupExcludeKeywords})).*$";
|
||||||
|
|
||||||
public static readonly List<string> PolicyGroupDefaultFilterList =
|
public static readonly List<string> PolicyGroupDefaultFilterList =
|
||||||
@@ -557,7 +553,6 @@ public class Global
|
|||||||
"http",
|
"http",
|
||||||
"tls",
|
"tls",
|
||||||
"quic",
|
"quic",
|
||||||
"fakedns",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<int> TunMtus =
|
public static readonly List<int> TunMtus =
|
||||||
@@ -737,6 +732,12 @@ public class Global
|
|||||||
"reply",
|
"reply",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> FakeIPRanges =
|
||||||
|
[
|
||||||
|
"198.18.0.0/15",
|
||||||
|
"11.0.0.0/8",
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly List<string> RootCertProviders =
|
public static readonly List<string> RootCertProviders =
|
||||||
[
|
[
|
||||||
"system",
|
"system",
|
||||||
@@ -744,5 +745,29 @@ public class Global
|
|||||||
MozillaRootProvider,
|
MozillaRootProvider,
|
||||||
];
|
];
|
||||||
|
|
||||||
#endregion const
|
public static readonly IReadOnlyList<string> TunIPv4Address =
|
||||||
|
[
|
||||||
|
"172.18.0.1/30",
|
||||||
|
"172.31.0.1/30",
|
||||||
|
"172.20.0.1/30",
|
||||||
|
"172.16.0.1/30",
|
||||||
|
"192.168.100.1/30",
|
||||||
|
"10.10.14.1/30",
|
||||||
|
"10.1.0.1/30",
|
||||||
|
"10.0.0.1/30",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Prefixes must leave room for a peer address (max /126); the sing-box system
|
||||||
|
// stack derives a gateway from the first prefix and rejects single-address prefixes.
|
||||||
|
public static readonly IReadOnlyList<string> TunIPv6Address =
|
||||||
|
[
|
||||||
|
"fc00::172:18:0:1/126",
|
||||||
|
"fc00::172:31:0:1/126",
|
||||||
|
"fc00::172:20:0:1/126",
|
||||||
|
"fc00::172:16:0:1/126",
|
||||||
|
"fc00::192:168:100:1/126",
|
||||||
|
"fc00::10:10:14:1/126",
|
||||||
|
"fc00::10:1:0:1/126",
|
||||||
|
"fc00::10:0:0:1/126",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ global using ServiceLib.Handler.Fmt;
|
|||||||
global using ServiceLib.Handler.SysProxy;
|
global using ServiceLib.Handler.SysProxy;
|
||||||
global using ServiceLib.Helper;
|
global using ServiceLib.Helper;
|
||||||
global using ServiceLib.Manager;
|
global using ServiceLib.Manager;
|
||||||
global using ServiceLib.Models.CoreConfigs;
|
|
||||||
global using ServiceLib.Models.Configs;
|
global using ServiceLib.Models.Configs;
|
||||||
|
global using ServiceLib.Models.CoreConfigs;
|
||||||
global using ServiceLib.Models.Dto;
|
global using ServiceLib.Models.Dto;
|
||||||
global using ServiceLib.Models.Entities;
|
global using ServiceLib.Models.Entities;
|
||||||
global using ServiceLib.Resx;
|
global using ServiceLib.Resx;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ public class CoreConfigContextBuilder
|
|||||||
RoutingItem = await ConfigHandler.GetDefaultRouting(config),
|
RoutingItem = await ConfigHandler.GetDefaultRouting(config),
|
||||||
IsWindows = Utils.IsWindows(),
|
IsWindows = Utils.IsWindows(),
|
||||||
IsMacOS = Utils.IsMacOS(),
|
IsMacOS = Utils.IsMacOS(),
|
||||||
|
ProtectCoreTypeList = config.TunModeItem.EnableTun ? [ECoreType.Xray, ECoreType.sing_box] : []
|
||||||
};
|
};
|
||||||
var validatorResult = NodeValidatorResult.Empty();
|
var validatorResult = NodeValidatorResult.Empty();
|
||||||
var (actNode, nodeValidatorResult) = await ResolveNodeAsync(context, node);
|
var (actNode, nodeValidatorResult) = await ResolveNodeAsync(context, node);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public static class ConfigHandler
|
|||||||
EnableTun = false,
|
EnableTun = false,
|
||||||
Mtu = 9000,
|
Mtu = 9000,
|
||||||
IcmpRouting = Global.TunIcmpRoutingPolicies.First(),
|
IcmpRouting = Global.TunIcmpRoutingPolicies.First(),
|
||||||
EnableLegacyProtect = false,
|
EnableLegacyProtect = true,
|
||||||
};
|
};
|
||||||
config.GuiItem ??= new();
|
config.GuiItem ??= new();
|
||||||
if (!Global.RootCertProviders.Contains(config.GuiItem.RootCertProvider))
|
if (!Global.RootCertProviders.Contains(config.GuiItem.RootCertProvider))
|
||||||
@@ -115,10 +115,12 @@ public static class ConfigHandler
|
|||||||
config.ConstItem ??= new ConstItem();
|
config.ConstItem ??= new ConstItem();
|
||||||
|
|
||||||
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
||||||
|
config.SimpleDNSItem.FakeIPRange ??= Global.FakeIPRanges.FirstOrDefault();
|
||||||
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.ServeStale ??= false;
|
||||||
config.SimpleDNSItem.ParallelQuery ??= false;
|
config.SimpleDNSItem.ParallelQuery ??= false;
|
||||||
|
config.SimpleDNSItem.EnableHappyEyeballs ??= false;
|
||||||
|
|
||||||
config.SpeedTestItem ??= new();
|
config.SpeedTestItem ??= new();
|
||||||
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
||||||
@@ -168,10 +170,24 @@ public static class ConfigHandler
|
|||||||
config.Fragment4RayItem ??= new()
|
config.Fragment4RayItem ??= new()
|
||||||
{
|
{
|
||||||
Packets = "tlshello",
|
Packets = "tlshello",
|
||||||
Length = "50-100",
|
|
||||||
Interval = "10-20",
|
|
||||||
MaxSplit = "0"
|
|
||||||
};
|
};
|
||||||
|
config.Fragment4RayItem.MaxSplit ??= "0";
|
||||||
|
|
||||||
|
config.HappyEyeballs4RayItem ??= new()
|
||||||
|
{
|
||||||
|
TryDelayMs = 250,
|
||||||
|
PrioritizeIPv6 = false,
|
||||||
|
Interleave = 1,
|
||||||
|
MaxConcurrentTry = 4,
|
||||||
|
};
|
||||||
|
if ((config.Fragment4RayItem.Lengths ?? []).Count == 0)
|
||||||
|
{
|
||||||
|
config.Fragment4RayItem.Lengths = [config.Fragment4RayItem.Length ?? "50-100"];
|
||||||
|
}
|
||||||
|
if ((config.Fragment4RayItem.Delays ?? []).Count == 0)
|
||||||
|
{
|
||||||
|
config.Fragment4RayItem.Delays = [config.Fragment4RayItem.Interval ?? "10-20"];
|
||||||
|
}
|
||||||
config.GlobalHotkeys ??= [];
|
config.GlobalHotkeys ??= [];
|
||||||
|
|
||||||
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public static class CoreConfigHandler
|
|||||||
{
|
{
|
||||||
result = node.CoreType switch
|
result = node.CoreType switch
|
||||||
{
|
{
|
||||||
ECoreType.mihomo => await new CoreConfigClashService(config).GenerateClientCustomConfig(node, fileName),
|
ECoreType.mihomo => await new CoreConfigClashService(config, context.IsTunEnabled).GenerateClientCustomConfig(node, fileName),
|
||||||
_ => await GenerateClientCustomConfig(node, fileName)
|
_ => await GenerateClientCustomConfig(node, fileName)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ public static class SysProxyHandler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
var port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
var exceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
|
||||||
if (port <= 0)
|
if (port <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -24,17 +23,18 @@ public static class SysProxyHandler
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case ESysProxyType.ForcedChange when Utils.IsWindows():
|
case ESysProxyType.ForcedChange when Utils.IsWindows():
|
||||||
{
|
var (strProxy, strExceptions) = GetWindowsProxyString(config, port);
|
||||||
GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
|
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
||||||
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ESysProxyType.ForcedChange when Utils.IsLinux():
|
case ESysProxyType.ForcedChange when Utils.IsLinux():
|
||||||
|
var exceptions = SanitizeExceptions(config);
|
||||||
await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
|
await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESysProxyType.ForcedChange when Utils.IsMacOS():
|
case ESysProxyType.ForcedChange when Utils.IsMacOS():
|
||||||
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
|
var exceptions2 = SanitizeExceptions(config);
|
||||||
|
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESysProxyType.ForcedClear when Utils.IsWindows():
|
case ESysProxyType.ForcedClear when Utils.IsWindows():
|
||||||
@@ -66,15 +66,31 @@ public static class SysProxyHandler
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
|
private static string SanitizeExceptions(Config config)
|
||||||
{
|
{
|
||||||
strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
var exceptions = config.SystemProxyItem.SystemProxyExceptions;
|
||||||
|
if (exceptions.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var items = exceptions
|
||||||
|
.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(item => item.Replace(" ", string.Empty))
|
||||||
|
.Where(item => item.Length > 0);
|
||||||
|
|
||||||
|
return string.Join(',', items);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (string strProxy, string strExceptions) GetWindowsProxyString(Config config, int port)
|
||||||
|
{
|
||||||
|
var strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||||
if (config.SystemProxyItem.NotProxyLocalAddress)
|
if (config.SystemProxyItem.NotProxyLocalAddress)
|
||||||
{
|
{
|
||||||
strExceptions = $"<local>;{strExceptions}";
|
strExceptions = $"<local>;{strExceptions}";
|
||||||
}
|
}
|
||||||
|
|
||||||
strProxy = string.Empty;
|
var strProxy = string.Empty;
|
||||||
if (config.SystemProxyItem.SystemProxyAdvancedProtocol.IsNullOrEmpty())
|
if (config.SystemProxyItem.SystemProxyAdvancedProtocol.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
strProxy = $"{Global.Loopback}:{port}";
|
strProxy = $"{Global.Loopback}:{port}";
|
||||||
@@ -86,6 +102,8 @@ public static class SysProxyHandler
|
|||||||
.Replace("{http_port}", port.ToString())
|
.Replace("{http_port}", port.ToString())
|
||||||
.Replace("{socks_port}", port.ToString());
|
.Replace("{socks_port}", port.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (strProxy, strExceptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
|
|||||||
@@ -34,7 +34,18 @@ public class CoreAdminManager
|
|||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
sb.AppendLine("#!/bin/bash");
|
sb.AppendLine("#!/bin/bash");
|
||||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
||||||
sb.AppendLine($"exec sudo -S -- {cmdLine}");
|
|
||||||
|
// Passing environment variables to the sudo command, here it only xray or sing-box.
|
||||||
|
if (coreInfo.Environment.Count > 0)
|
||||||
|
{
|
||||||
|
var envArgs = string.Join(" ", coreInfo.Environment.Where(kv => kv.Value.IsNotEmpty()).Select(kv => $"{kv.Key}={kv.Value.AppendQuotes()}"));
|
||||||
|
sb.AppendLine($"exec sudo -S -- env {envArgs} {cmdLine}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.AppendLine($"exec sudo -S -- {cmdLine}");
|
||||||
|
}
|
||||||
|
|
||||||
var shFilePath = await FileUtils.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
|
var shFilePath = await FileUtils.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
|
||||||
|
|
||||||
var procService = new ProcessService(
|
var procService = new ProcessService(
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class CoreManager
|
|||||||
await CoreStop();
|
await CoreStop();
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
|
|
||||||
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
|
if (Utils.IsWindows() && (mainContext?.IsTunEnabled == true || preContext?.IsTunEnabled == true))
|
||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
await WindowsUtils.RemoveTunDevice();
|
await WindowsUtils.RemoveTunDevice();
|
||||||
@@ -183,7 +183,7 @@ public class CoreManager
|
|||||||
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(coreType);
|
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(coreType);
|
||||||
|
|
||||||
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
||||||
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
|
var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true, context.IsTunEnabled);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -201,7 +201,7 @@ public class CoreManager
|
|||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
|
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
|
||||||
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true, preContext.IsTunEnabled);
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -222,7 +222,7 @@ public class CoreManager
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!preContext.AppConfig.TunModeItem.EnableTun)
|
if (!preContext.IsTunEnabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,20 @@ public class CoreManager
|
|||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
|
|
||||||
private async Task<ProcessService?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
|
/// <summary>
|
||||||
|
/// Decides whether a core launch must be elevated on non-Windows platforms.
|
||||||
|
/// The TUN state comes from the immutable <see cref="CoreConfigContext" /> snapshot that
|
||||||
|
/// generated the config, never from the live mutable config: the generated config and the
|
||||||
|
/// launch mode must always agree, even if TUN is toggled while a reload is in flight.
|
||||||
|
/// </summary>
|
||||||
|
public static bool ShouldRunAsSudo(bool isTunLaunch, ECoreType? coreType, bool isNonWindows)
|
||||||
|
{
|
||||||
|
return isTunLaunch
|
||||||
|
&& coreType is ECoreType.sing_box or ECoreType.mihomo or ECoreType.Xray
|
||||||
|
&& isNonWindows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ProcessService?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo, bool isTunLaunch = false)
|
||||||
{
|
{
|
||||||
var fileName = CoreInfoManager.Instance.GetCoreExecFile(coreInfo, out var msg);
|
var fileName = CoreInfoManager.Instance.GetCoreExecFile(coreInfo, out var msg);
|
||||||
if (fileName.IsNullOrEmpty())
|
if (fileName.IsNullOrEmpty())
|
||||||
@@ -301,9 +314,7 @@ public class CoreManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (mayNeedSudo
|
if (mayNeedSudo
|
||||||
&& _config.TunModeItem.EnableTun
|
&& ShouldRunAsSudo(isTunLaunch, coreInfo.CoreType, Utils.IsNonWindows()))
|
||||||
&& (coreInfo.CoreType is ECoreType.sing_box or ECoreType.mihomo or ECoreType.Xray)
|
|
||||||
&& Utils.IsNonWindows())
|
|
||||||
{
|
{
|
||||||
_linuxSudo = true;
|
_linuxSudo = true;
|
||||||
await CoreAdminManager.Instance.Init(_config, _updateFunc);
|
await CoreAdminManager.Instance.Init(_config, _updateFunc);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public class Config
|
|||||||
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||||
public SimpleDNSItem SimpleDNSItem { get; set; }
|
public SimpleDNSItem SimpleDNSItem { get; set; }
|
||||||
|
public HappyEyeballs4RayItem HappyEyeballs4RayItem { get; set; }
|
||||||
|
|
||||||
#endregion other entities
|
#endregion other entities
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,8 +147,10 @@ public class TunModeItem
|
|||||||
public int Mtu { get; set; }
|
public int Mtu { get; set; }
|
||||||
public bool EnableIPv6Address { get; set; }
|
public bool EnableIPv6Address { get; set; }
|
||||||
public string IcmpRouting { get; set; }
|
public string IcmpRouting { get; set; }
|
||||||
public bool EnableLegacyProtect { get; set; }
|
public bool EnableLegacyProtect { get; set; } = true;
|
||||||
public List<string>? RouteExcludeAddress { get; set; }
|
public List<string>? RouteExcludeAddress { get; set; }
|
||||||
|
public string IPv4Address { get; set; }
|
||||||
|
public string IPv6Address { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -249,9 +251,15 @@ public class CheckUpdateItem
|
|||||||
public class Fragment4RayItem
|
public class Fragment4RayItem
|
||||||
{
|
{
|
||||||
public string? Packets { get; set; }
|
public string? Packets { get; set; }
|
||||||
public string? Length { get; set; }
|
public List<string>? Lengths { get; set; }
|
||||||
public string? Interval { get; set; }
|
public List<string>? Delays { get; set; }
|
||||||
public string? MaxSplit { get; set; }
|
public string? MaxSplit { get; set; }
|
||||||
|
|
||||||
|
// For migration from old version, remove those properties in the future
|
||||||
|
public string? Length { get; set; }
|
||||||
|
|
||||||
|
public string? Interval { get; set; }
|
||||||
|
// migration end
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -269,14 +277,26 @@ public class SimpleDNSItem
|
|||||||
public bool? AddCommonHosts { get; set; }
|
public bool? AddCommonHosts { get; set; }
|
||||||
public bool? FakeIP { get; set; }
|
public bool? FakeIP { get; set; }
|
||||||
public bool? GlobalFakeIp { get; set; }
|
public bool? GlobalFakeIp { get; set; }
|
||||||
|
public string? FakeIPRange { get; set; }
|
||||||
public bool? BlockBindingQuery { get; set; }
|
public bool? BlockBindingQuery { get; set; }
|
||||||
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? Strategy4Freedom { get; set; }
|
||||||
public string? Strategy4Proxy { get; set; }
|
public string? Strategy4Proxy { get; set; }
|
||||||
|
public string? Strategy4ProxyDial { get; set; }
|
||||||
public bool? ServeStale { get; set; }
|
public bool? ServeStale { get; set; }
|
||||||
public bool? ParallelQuery { 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; }
|
||||||
|
public bool? EnableHappyEyeballs { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class HappyEyeballs4RayItem
|
||||||
|
{
|
||||||
|
public int? TryDelayMs { get; set; }
|
||||||
|
public bool? PrioritizeIPv6 { get; set; }
|
||||||
|
public int? Interleave { get; set; }
|
||||||
|
public int? MaxConcurrentTry { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ public class V2rayConfig
|
|||||||
{
|
{
|
||||||
public Log4Ray log { get; set; }
|
public Log4Ray log { get; set; }
|
||||||
public object dns { get; set; }
|
public object dns { get; set; }
|
||||||
|
public FakeDns4Ray? fakedns { 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; }
|
||||||
@@ -43,6 +44,12 @@ public class Log4Ray
|
|||||||
public string? loglevel { get; set; }
|
public string? loglevel { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class FakeDns4Ray
|
||||||
|
{
|
||||||
|
public string? ipPool { get; set; }
|
||||||
|
public long? poolSize { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Inbounds4Ray
|
public class Inbounds4Ray
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
@@ -136,8 +143,6 @@ public class Outboundsettings4Ray
|
|||||||
|
|
||||||
public Response4Ray? response { get; set; }
|
public Response4Ray? response { get; set; }
|
||||||
|
|
||||||
public string? domainStrategy { get; set; }
|
|
||||||
|
|
||||||
public int? userLevel { get; set; }
|
public int? userLevel { get; set; }
|
||||||
|
|
||||||
public string? secretKey { get; set; }
|
public string? secretKey { get; set; }
|
||||||
@@ -516,6 +521,8 @@ public class MaskSettings4Ray
|
|||||||
|
|
||||||
public string? length { get; set; }
|
public string? length { get; set; }
|
||||||
public string? delay { get; set; }
|
public string? delay { get; set; }
|
||||||
|
public List<string>? lengths { get; set; }
|
||||||
|
public List<string>? delays { get; set; }
|
||||||
public int? maxSplit { get; set; }
|
public int? maxSplit { get; set; }
|
||||||
|
|
||||||
// noise
|
// noise
|
||||||
@@ -547,15 +554,20 @@ public class AccountsItem4Ray
|
|||||||
|
|
||||||
public class Sockopt4Ray
|
public class Sockopt4Ray
|
||||||
{
|
{
|
||||||
|
public string? domainStrategy { get; set; }
|
||||||
|
|
||||||
public string? dialerProxy { get; set; }
|
public string? dialerProxy { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("interface")]
|
[JsonPropertyName("interface")]
|
||||||
public string? Interface { get; set; }
|
public string? Interface { get; set; }
|
||||||
|
|
||||||
|
public HappyEyeballs4Ray? happyEyeballs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FragmentItem4Ray
|
public class HappyEyeballs4Ray
|
||||||
{
|
{
|
||||||
public string? packets { get; set; }
|
public int? tryDelayMs { get; set; }
|
||||||
public string? length { get; set; }
|
public bool? prioritizeIPv6 { get; set; }
|
||||||
public string? interval { get; set; }
|
public int? interleave { get; set; }
|
||||||
|
public int? maxConcurrentTry { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+55
-1
@@ -3060,6 +3060,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Enable Happy Eyeballs 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbEnableHappyEyeballs {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbEnableHappyEyeballs", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbEnableHappyEyeballsTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbEnableHappyEyeballsTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 DNS via Bridge 的本地化字符串。
|
/// 查找类似 DNS via Bridge 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3088,7 +3106,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Applies globally by default, with built-in FakeIP filtering (sing-box only). 的本地化字符串。
|
/// 查找类似 Applies globally by default, and built-in FakeIP filtering is only built into sing-box. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbFakeIPTips {
|
public static string TbFakeIPTips {
|
||||||
get {
|
get {
|
||||||
@@ -3330,6 +3348,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Ipv4 Address 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbIpv4Address {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbIpv4Address", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Ipv6 Address 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbIpv6Address {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbIpv6Address", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Most Stable 的本地化字符串。
|
/// 查找类似 Most Stable 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3528,6 +3564,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Proxy Dial Resolution Strategy 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbProxyDialResolveStrategy {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbProxyDialResolveStrategy", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Not recommended; may cause routing loops. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbProxyDialResolveStrategyTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbProxyDialResolveStrategyTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Public Key 的本地化字符串。
|
/// 查找类似 Public Key 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1495,7 +1495,7 @@
|
|||||||
<value>Select Profile</value>
|
<value>Select Profile</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Please Add At Least One Configuration</value>
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
|||||||
@@ -1492,7 +1492,7 @@
|
|||||||
<value>Choisir une config.</value>
|
<value>Choisir une config.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Actif globalement par défaut, avec filtre FakeIP intégré ; ne fonctionne que dans sing-box</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Veuillez ajouter au moins une configuration</value>
|
<value>Veuillez ajouter au moins une configuration</value>
|
||||||
|
|||||||
@@ -1495,7 +1495,7 @@
|
|||||||
<value>Select Profile</value>
|
<value>Select Profile</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Please Add At Least One Configuration</value>
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
|||||||
@@ -1495,7 +1495,7 @@
|
|||||||
<value>Pilih profil</value>
|
<value>Pilih profil</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Berlaku secara global secara default, dengan filter FakeIP bawaan (hanya sing-box).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Silakan tambahkan setidaknya satu konfigurasi.</value>
|
<value>Silakan tambahkan setidaknya satu konfigurasi.</value>
|
||||||
|
|||||||
@@ -1501,7 +1501,7 @@
|
|||||||
<value>Select Profile</value>
|
<value>Select Profile</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Please Add At Least One Configuration</value>
|
<value>Please Add At Least One Configuration</value>
|
||||||
@@ -1780,7 +1780,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<value>New Update</value>
|
<value>New Update</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgAllowInsecureDeprecated" xml:space="preserve">
|
<data name="MsgAllowInsecureDeprecated" xml:space="preserve">
|
||||||
<value>Warning: Xray will disable allowInsecure (skip certificate verification) in August 2026. Please switch to pinnedPeerCertSha256 (fixed certificate fingerprint) as soon as possible. allowInsecure will not be usable after its expiration.</value>
|
<value>The current node uses an unencrypted connection, meaning your communications could be directly monitored by network intermediaries controlled by authoritarian governments. For security reasons, nodes of this type cannot connect via Xray-core versions 26.2.6 or higher. If this is a self-built node, please enable TLS or other secure encryption, or pin the certificate using pinSHA256. If this is an airport/provider node, please contact your service provider for a technical upgrade. If the provider refuses to cooperate, it is recommended to switch to a service provider that prioritizes user security. For more information, please visit https://github.com/2dust/v2rayN/discussions/9460.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbRouteExcludeAddress" xml:space="preserve">
|
<data name="TbRouteExcludeAddress" xml:space="preserve">
|
||||||
<value>Route Exclude Address</value>
|
<value>Route Exclude Address</value>
|
||||||
@@ -1830,4 +1830,22 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||||
<value>Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation.</value>
|
<value>Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
|
||||||
|
<value>Proxy Dial Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||||
|
<value>Not recommended; may cause routing loops.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||||
|
<value>Enable Happy Eyeballs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||||
|
<value>Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbIpv6Address" xml:space="preserve">
|
||||||
|
<value>Ipv6 Address</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbIpv4Address" xml:space="preserve">
|
||||||
|
<value>Ipv4 Address</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1501,7 +1501,7 @@
|
|||||||
<value>Выбрать профиль</value>
|
<value>Выбрать профиль</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>По умолчанию применяется глобально, со встроенной фильтрацией FakeIP (только sing-box).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Добавьте хотя бы одну конфигурацию</value>
|
<value>Добавьте хотя бы одну конфигурацию</value>
|
||||||
|
|||||||
@@ -1498,7 +1498,7 @@
|
|||||||
<value>选择配置</value>
|
<value>选择配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>默认全局生效,内置 FakeIP 过滤,仅在 sing-box 中生效</value>
|
<value>默认全局生效,仅在 sing-box 中内置 FakeIP 过滤。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>请至少添加一个配置</value>
|
<value>请至少添加一个配置</value>
|
||||||
@@ -1774,7 +1774,11 @@
|
|||||||
<value>有更新</value>
|
<value>有更新</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgAllowInsecureDeprecated" xml:space="preserve">
|
<data name="MsgAllowInsecureDeprecated" xml:space="preserve">
|
||||||
<value>警告:Xray 将在 2026.8.1 禁用跳过证书验证 allowInsecure ,请尽快改用证书固定指纹 pinnedPeerCertSha256。到期后无法使用 </value>
|
<value>当前节点使用未加密连接,您的通信可能会被威权政府掌控的网络中间设施直接查看
|
||||||
|
为了安全,此类节点无法通过 26.2.6+ 版本的Xray核心连接
|
||||||
|
如果是自建节点请启用 TLS 等安全加密,或固定证书 pinSHA256
|
||||||
|
如果机场节点请联系服务商完成技术升级,如服务商拒绝配合,建议更换更重视用户安全的服务商
|
||||||
|
更多的信息,请访问 https://github.com/2dust/v2rayN/discussions/9460</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbVerifyPeerCertByName" xml:space="preserve">
|
<data name="TbVerifyPeerCertByName" xml:space="preserve">
|
||||||
<value>Verify Peer Cert By Name</value>
|
<value>Verify Peer Cert By Name</value>
|
||||||
@@ -1827,4 +1831,22 @@
|
|||||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||||
<value>仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。</value>
|
<value>仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
|
||||||
|
<value>连接代理解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||||
|
<value>不建议开启,特殊情况可能回环。</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||||
|
<value>启用 Happy Eyeballs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||||
|
<value>需配合 UseIP 策略使用。启用后将同时尝试 IPv4 和 IPv6 连接,并自动选择更快可用的路径。</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbIpv6Address" xml:space="preserve">
|
||||||
|
<value>Ipv6 地址</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbIpv4Address" xml:space="preserve">
|
||||||
|
<value>Ipv4 地址</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1498,7 +1498,7 @@
|
|||||||
<value>選擇節點</value>
|
<value>選擇節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>默認全域生效,內置 FakeIP 過濾,僅在 sing-box 中生效</value>
|
<value>默認全局生效,僅在 sing-box 中內置 FakeIP 過濾。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>請至少添加一個節點</value>
|
<value>請至少添加一個節點</value>
|
||||||
@@ -1774,7 +1774,11 @@
|
|||||||
<value>有更新</value>
|
<value>有更新</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgAllowInsecureDeprecated" xml:space="preserve">
|
<data name="MsgAllowInsecureDeprecated" xml:space="preserve">
|
||||||
<value>警告:Xray 將在 2026.8.1 停用跳過憑證驗證 allowInsecure ,請盡快改用憑證固定指紋 pinnedPeerCertSha256。到期後無法使用 allowInsecure。</value>
|
<value>目前節點使用未加密連接,您的通訊可能會被威權政府掌控的網路中間設施直接查看
|
||||||
|
為了安全,此類節點無法透過 26.2.6+ 版本的Xray核心連接
|
||||||
|
如果是自建節點請啟用 TLS 等安全加密,或固定憑證 pinSHA256
|
||||||
|
若機場節點請聯絡服務商完成技術升級,如服務商拒絕配合,建議更換更重視用戶安全的服務商
|
||||||
|
更多的信息,請訪問 https://github.com/2dust/v2rayN/discussions/9460</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbVerifyPeerCertByName" xml:space="preserve">
|
<data name="TbVerifyPeerCertByName" xml:space="preserve">
|
||||||
<value>Verify Peer Cert By Name</value>
|
<value>Verify Peer Cert By Name</value>
|
||||||
@@ -1827,4 +1831,22 @@
|
|||||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||||
<value>僅適用於 v2rayN GUI 的下載與網路請求,不影響核心的憑證驗證</value>
|
<value>僅適用於 v2rayN GUI 的下載與網路請求,不影響核心的憑證驗證</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
|
||||||
|
<value>連線代理解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||||
|
<value>不建議啟用,特殊情況可能造成連線循環</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||||
|
<value>啟用 Happy Eyeballs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||||
|
<value>需搭配 UseIP 策略,啟用後會同時嘗試 IPv4 與 IPv6 連線,並自動選擇速度較快的路徑</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbIpv6Address" xml:space="preserve">
|
||||||
|
<value>Ipv6 位址</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbIpv4Address" xml:space="preserve">
|
||||||
|
<value>Ipv4 位址</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,27 +1,28 @@
|
|||||||
{
|
{
|
||||||
"tag": "tun",
|
"tag": "tun",
|
||||||
"protocol": "tun",
|
"protocol": "tun",
|
||||||
"settings": {
|
"settings": {
|
||||||
"name": "xray_tun",
|
"name": "xray_tun",
|
||||||
"MTU": 9000,
|
"MTU": 9000,
|
||||||
"gateway": [
|
"gateway": [
|
||||||
"172.18.0.1/30",
|
"172.18.0.1/30",
|
||||||
"fdfe:dcba:9876::1/126"
|
"fdfe:dcba:9876::1/126"
|
||||||
],
|
],
|
||||||
"dns": [
|
"dns": [
|
||||||
"172.18.0.1"
|
"1.1.1.1",
|
||||||
],
|
"8.8.8.8"
|
||||||
"autoSystemRoutingTable": [
|
],
|
||||||
"0.0.0.0/0",
|
"autoSystemRoutingTable": [
|
||||||
"::/0"
|
"0.0.0.0/0",
|
||||||
],
|
"::/0"
|
||||||
"autoOutboundsInterface": "auto"
|
],
|
||||||
},
|
"autoOutboundsInterface": "auto"
|
||||||
"sniffing": {
|
},
|
||||||
"enabled": true,
|
"sniffing": {
|
||||||
"destOverride": [
|
"enabled": true,
|
||||||
"http",
|
"destOverride": [
|
||||||
"tls"
|
"http",
|
||||||
]
|
"tls"
|
||||||
}
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2342
-3553
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,11 @@
|
|||||||
namespace ServiceLib.Services.CoreConfig;
|
namespace ServiceLib.Services.CoreConfig;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Core configuration file processing class
|
/// Core configuration file processing class.
|
||||||
|
/// The TUN state is taken as a snapshot so the generated config always agrees
|
||||||
|
/// with the launch elevation decision (see CoreManager.ShouldRunAsSudo).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CoreConfigClashService(Config config)
|
public class CoreConfigClashService(Config config, bool isTunEnabled)
|
||||||
{
|
{
|
||||||
private static readonly string _tag = "CoreConfigClashService";
|
private static readonly string _tag = "CoreConfigClashService";
|
||||||
|
|
||||||
@@ -102,7 +104,7 @@ public class CoreConfigClashService(Config config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//enable tun mode
|
//enable tun mode
|
||||||
if (config.TunModeItem.EnableTun)
|
if (isTunEnabled)
|
||||||
{
|
{
|
||||||
var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
||||||
if (tun.IsNotEmpty())
|
if (tun.IsNotEmpty())
|
||||||
@@ -171,7 +173,7 @@ public class CoreConfigClashService(Config config)
|
|||||||
}
|
}
|
||||||
foreach (var item in mixinContent)
|
foreach (var item in mixinContent)
|
||||||
{
|
{
|
||||||
if (!config.TunModeItem.EnableTun && item.Key == "tun")
|
if (!isTunEnabled && item.Key == "tun")
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,12 +137,12 @@ public partial class CoreConfigSingboxService
|
|||||||
// fake ip
|
// fake ip
|
||||||
if (simpleDnsItem.FakeIP == true)
|
if (simpleDnsItem.FakeIP == true)
|
||||||
{
|
{
|
||||||
|
var fakeipRange = simpleDnsItem.FakeIPRange.IsNullOrEmpty() ? Global.FakeIPRanges.First() : simpleDnsItem.FakeIPRange;
|
||||||
var fakeip = new Server4Sbox
|
var fakeip = new Server4Sbox
|
||||||
{
|
{
|
||||||
tag = Global.SingboxFakeDNSTag,
|
tag = Global.SingboxFakeDNSTag,
|
||||||
type = "fakeip",
|
type = "fakeip",
|
||||||
inet4_range = "198.18.0.0/15",
|
inet4_range = fakeipRange,
|
||||||
inet6_range = "fc00::/18",
|
|
||||||
};
|
};
|
||||||
_coreConfig.dns.servers.Add(fakeip);
|
_coreConfig.dns.servers.Add(fakeip);
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ public partial class CoreConfigSingboxService
|
|||||||
_coreConfig.dns.rules.Add(new()
|
_coreConfig.dns.rules.Add(new()
|
||||||
{
|
{
|
||||||
server = Global.SingboxDirectDNSTag,
|
server = Global.SingboxDirectDNSTag,
|
||||||
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom),
|
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial),
|
||||||
domain = context.ProtectDomainList.ToList(),
|
domain = context.ProtectDomainList.ToList(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ public partial class CoreConfigSingboxService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simpleDnsItem.FakeIP == true && simpleDnsItem.GlobalFakeIp == true)
|
if (simpleDnsItem.FakeIP == true && simpleDnsItem.GlobalFakeIp != false)
|
||||||
{
|
{
|
||||||
var fakeipFilterRule = JsonUtils.Deserialize<Rule4Sbox>(EmbedUtils.GetEmbedText(Global.SingboxFakeIPFilterFileName));
|
var fakeipFilterRule = JsonUtils.Deserialize<Rule4Sbox>(EmbedUtils.GetEmbedText(Global.SingboxFakeIPFilterFileName));
|
||||||
fakeipFilterRule.invert = true;
|
fakeipFilterRule.invert = true;
|
||||||
|
|||||||
@@ -67,9 +67,13 @@ public partial class CoreConfigSingboxService
|
|||||||
tunInbound.auto_route = _config.TunModeItem.AutoRoute;
|
tunInbound.auto_route = _config.TunModeItem.AutoRoute;
|
||||||
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
|
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
|
||||||
tunInbound.stack = _config.TunModeItem.Stack;
|
tunInbound.stack = _config.TunModeItem.Stack;
|
||||||
if (_config.TunModeItem.EnableIPv6Address == false)
|
|
||||||
|
var address = _config.TunModeItem.IPv4Address.NullIfEmpty() ?? Global.TunIPv4Address.First();
|
||||||
|
tunInbound.address = [address];
|
||||||
|
if (_config.TunModeItem.EnableIPv6Address == true)
|
||||||
{
|
{
|
||||||
tunInbound.address = ["172.18.0.1/30"];
|
var address6 = _config.TunModeItem.IPv6Address.NullIfEmpty() ?? Global.TunIPv6Address.First();
|
||||||
|
tunInbound.address.Add(address6);
|
||||||
}
|
}
|
||||||
tunInbound.route_exclude_address = _config.TunModeItem.RouteExcludeAddress;
|
tunInbound.route_exclude_address = _config.TunModeItem.RouteExcludeAddress;
|
||||||
|
|
||||||
|
|||||||
@@ -417,11 +417,15 @@ public partial class CoreConfigSingboxService
|
|||||||
var tls = new Tls4Sbox()
|
var tls = new Tls4Sbox()
|
||||||
{
|
{
|
||||||
enabled = true,
|
enabled = true,
|
||||||
record_fragment = _config.CoreBasicItem.EnableFragment ? true : null,
|
|
||||||
server_name = serverName,
|
server_name = serverName,
|
||||||
insecure = _node.GetAllowInsecure(),
|
insecure = _node.GetAllowInsecure(),
|
||||||
alpn = _node.GetAlpn(),
|
alpn = _node.GetAlpn(),
|
||||||
};
|
};
|
||||||
|
if (_config.CoreBasicItem.EnableFragment == true)
|
||||||
|
{
|
||||||
|
tls.fragment = true;
|
||||||
|
tls.record_fragment = true;
|
||||||
|
}
|
||||||
if (_node.Fingerprint.IsNotEmpty())
|
if (_node.Fingerprint.IsNotEmpty())
|
||||||
{
|
{
|
||||||
tls.utls = new Utls4Sbox()
|
tls.utls = new Utls4Sbox()
|
||||||
|
|||||||
@@ -10,18 +10,27 @@ public partial class CoreConfigSingboxService
|
|||||||
var simpleDnsItem = context.SimpleDnsItem;
|
var simpleDnsItem = context.SimpleDnsItem;
|
||||||
|
|
||||||
var defaultDomainResolverTag = Global.SingboxDirectDNSTag;
|
var defaultDomainResolverTag = Global.SingboxDirectDNSTag;
|
||||||
var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom);
|
var dialDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial);
|
||||||
|
|
||||||
var rawDNSItem = context.RawDnsItem;
|
var rawDNSItem = context.RawDnsItem;
|
||||||
if (rawDNSItem is { Enabled: true })
|
if (rawDNSItem is { Enabled: true })
|
||||||
{
|
{
|
||||||
defaultDomainResolverTag = Global.SingboxLocalDNSTag;
|
defaultDomainResolverTag = Global.SingboxLocalDNSTag;
|
||||||
directDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom;
|
dialDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom;
|
||||||
|
}
|
||||||
|
else if (!simpleDnsItem.Strategy4Freedom.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
var directOutbound = _coreConfig.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag);
|
||||||
|
directOutbound?.domain_resolver = new()
|
||||||
|
{
|
||||||
|
server = defaultDomainResolverTag,
|
||||||
|
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_coreConfig.route.default_domain_resolver = new()
|
_coreConfig.route.default_domain_resolver = new()
|
||||||
{
|
{
|
||||||
server = defaultDomainResolverTag,
|
server = defaultDomainResolverTag,
|
||||||
strategy = directDnsStrategy
|
strategy = dialDnsStrategy
|
||||||
};
|
};
|
||||||
|
|
||||||
if (context.IsTunEnabled)
|
if (context.IsTunEnabled)
|
||||||
@@ -35,18 +44,21 @@ public partial class CoreConfigSingboxService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lstDirectExe = BuildRoutingDirectExe();
|
var lstDirectExe = BuildRoutingDirectExe();
|
||||||
_coreConfig.route.rules.Add(new()
|
if (lstDirectExe.Count > 0)
|
||||||
{
|
{
|
||||||
port = [53],
|
_coreConfig.route.rules.Add(new()
|
||||||
action = "hijack-dns",
|
{
|
||||||
process_path = lstDirectExe
|
port = [53],
|
||||||
});
|
action = "hijack-dns",
|
||||||
|
process_path = lstDirectExe,
|
||||||
|
});
|
||||||
|
|
||||||
_coreConfig.route.rules.Add(new()
|
_coreConfig.route.rules.Add(new()
|
||||||
{
|
{
|
||||||
outbound = Global.DirectTag,
|
outbound = Global.DirectTag,
|
||||||
process_path = lstDirectExe
|
process_path = lstDirectExe,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ICMP Routing
|
// ICMP Routing
|
||||||
var icmpRouting = _config.TunModeItem.IcmpRouting ?? "";
|
var icmpRouting = _config.TunModeItem.IcmpRouting ?? "";
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public partial class CoreConfigV2rayService
|
|||||||
_coreConfig.routing.rules.Add(new RulesItem4Ray
|
_coreConfig.routing.rules.Add(new RulesItem4Ray
|
||||||
{
|
{
|
||||||
type = "field",
|
type = "field",
|
||||||
inboundTag = new List<string> { Global.DnsTag },
|
inboundTag = [Global.DnsTag],
|
||||||
outboundTag = Global.ProxyTag,
|
outboundTag = Global.ProxyTag,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -43,11 +43,7 @@ public partial class CoreConfigV2rayService
|
|||||||
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
||||||
if (outbound != null)
|
if (outbound != null)
|
||||||
{
|
{
|
||||||
outbound.settings = new()
|
FillSockoptDomainStrategy(outbound, strategy4Freedom);
|
||||||
{
|
|
||||||
domainStrategy = strategy4Freedom,
|
|
||||||
userLevel = 0
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +60,22 @@ public partial class CoreConfigV2rayService
|
|||||||
.ForEach(outbound => outbound.targetStrategy = strategy4Proxy);
|
.ForEach(outbound => outbound.targetStrategy = strategy4Proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var strategy4DialProxy = simpleDnsItem?.Strategy4ProxyDial ?? Global.AsIs;
|
||||||
|
//Outbound DialProxy domainStrategy
|
||||||
|
if (strategy4DialProxy.IsNotEmpty() && strategy4DialProxy != Global.AsIs)
|
||||||
|
{
|
||||||
|
var xraySupportConfigTypeNames = Global.XraySupportConfigType
|
||||||
|
.Select(x => x == EConfigType.Hysteria2 ? "hysteria" : Global.ProtocolTypes[x])
|
||||||
|
.ToHashSet();
|
||||||
|
_coreConfig.outbounds
|
||||||
|
.Where(t => xraySupportConfigTypeNames.Contains(t.protocol))
|
||||||
|
.ToList()
|
||||||
|
.ForEach(outbound =>
|
||||||
|
{
|
||||||
|
FillSockoptDomainStrategy(outbound, strategy4DialProxy);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
FillDnsServers(dnsItem);
|
FillDnsServers(dnsItem);
|
||||||
FillDnsHosts(dnsItem);
|
FillDnsHosts(dnsItem);
|
||||||
|
|
||||||
@@ -108,6 +120,33 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GenFakeDns()
|
||||||
|
{
|
||||||
|
var fakeipRange = _config.SimpleDNSItem.FakeIPRange.IsNullOrEmpty() ? Global.FakeIPRanges.First() : _config.SimpleDNSItem.FakeIPRange;
|
||||||
|
var poolSize = 65535L;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fakeipNetwork = IPNetwork2.Parse(fakeipRange);
|
||||||
|
var totalIPs = fakeipNetwork.Total;
|
||||||
|
// see https://github.com/XTLS/Xray-core/blob/6e3322d219140a025285ded1114fe17a5edb74d8/app/dns/fakedns/fake.go#L88
|
||||||
|
// if math.Log2(float64(lruSize)) >= float64(rooms) { return errors.New("LRU size is bigger than subnet size").AtError() }
|
||||||
|
totalIPs -= 1;
|
||||||
|
if (totalIPs > 0)
|
||||||
|
{
|
||||||
|
poolSize = (totalIPs >= long.MaxValue) ? long.MaxValue : (long)totalIPs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
_coreConfig.fakedns = new()
|
||||||
|
{
|
||||||
|
ipPool = fakeipRange,
|
||||||
|
poolSize = poolSize,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void FillDnsServers(Dns4Ray dnsItem)
|
private void FillDnsServers(Dns4Ray dnsItem)
|
||||||
{
|
{
|
||||||
var simpleDNSItem = context.SimpleDnsItem;
|
var simpleDNSItem = context.SimpleDnsItem;
|
||||||
@@ -234,6 +273,23 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
var directDnsTagIndex = 1;
|
var directDnsTagIndex = 1;
|
||||||
|
|
||||||
|
if (simpleDNSItem.FakeIP == true)
|
||||||
|
{
|
||||||
|
var fakeIPMatchDomain = new HashSet<string>(proxyDomainList);
|
||||||
|
fakeIPMatchDomain.UnionWith(proxyGeositeList);
|
||||||
|
if (simpleDNSItem.GlobalFakeIp != false)
|
||||||
|
{
|
||||||
|
fakeIPMatchDomain.UnionWith(directDomainList);
|
||||||
|
fakeIPMatchDomain.UnionWith(directGeositeList);
|
||||||
|
fakeIPMatchDomain.UnionWith(expectedDomainList);
|
||||||
|
}
|
||||||
|
if (fakeIPMatchDomain.Count > 0)
|
||||||
|
{
|
||||||
|
GenFakeDns();
|
||||||
|
AddDnsServers(["fakedns"], fakeIPMatchDomain.ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
||||||
AddDnsServers(directDNSAddress, directDomainList, true);
|
AddDnsServers(directDNSAddress, directDomainList, true);
|
||||||
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
||||||
@@ -384,11 +440,9 @@ public partial class CoreConfigV2rayService
|
|||||||
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
||||||
if (outbound != null)
|
if (outbound != null)
|
||||||
{
|
{
|
||||||
outbound.settings = new()
|
outbound.streamSettings ??= new();
|
||||||
{
|
outbound.streamSettings.sockopt ??= new();
|
||||||
domainStrategy = domainStrategy4Freedom,
|
outbound.streamSettings.sockopt.domainStrategy = domainStrategy4Freedom;
|
||||||
userLevel = 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,4 +525,28 @@ public partial class CoreConfigV2rayService
|
|||||||
};
|
};
|
||||||
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FillSockoptDomainStrategy(Outbounds4Ray outbound, string? domainStrategy, bool skipHappyEyeballs = false)
|
||||||
|
{
|
||||||
|
if (domainStrategy.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outbound.streamSettings ??= new();
|
||||||
|
outbound.streamSettings.sockopt ??= new();
|
||||||
|
var sockopt = outbound.streamSettings.sockopt;
|
||||||
|
sockopt.domainStrategy = domainStrategy;
|
||||||
|
|
||||||
|
if (skipHappyEyeballs || _config.SimpleDNSItem.EnableHappyEyeballs != true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var happyEyeballsItem = _config.HappyEyeballs4RayItem;
|
||||||
|
sockopt.happyEyeballs ??= new();
|
||||||
|
var happyEyeballs = sockopt.happyEyeballs;
|
||||||
|
happyEyeballs.tryDelayMs = happyEyeballsItem.TryDelayMs;
|
||||||
|
happyEyeballs.prioritizeIPv6 = happyEyeballsItem.PrioritizeIPv6;
|
||||||
|
happyEyeballs.interleave = happyEyeballsItem.Interleave;
|
||||||
|
happyEyeballs.maxConcurrentTry = happyEyeballsItem.MaxConcurrentTry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,11 +63,17 @@ public partial class CoreConfigV2rayService
|
|||||||
new Inbounds4Ray();
|
new Inbounds4Ray();
|
||||||
tunInbound.settings.name = context.IsMacOS ? $"utun{new Random().Next(99)}" : "xray_tun";
|
tunInbound.settings.name = context.IsMacOS ? $"utun{new Random().Next(99)}" : "xray_tun";
|
||||||
tunInbound.settings.MTU = _config.TunModeItem.Mtu;
|
tunInbound.settings.MTU = _config.TunModeItem.Mtu;
|
||||||
if (!_config.TunModeItem.EnableIPv6Address)
|
|
||||||
|
var address = _config.TunModeItem.IPv4Address.NullIfEmpty() ?? Global.TunIPv4Address.First();
|
||||||
|
tunInbound.settings.gateway = [address];
|
||||||
|
tunInbound.settings.autoSystemRoutingTable = ["0.0.0.0/0"];
|
||||||
|
if (_config.TunModeItem.EnableIPv6Address == true)
|
||||||
{
|
{
|
||||||
tunInbound.settings.gateway = ["172.18.0.1/30"];
|
var address6 = _config.TunModeItem.IPv6Address.NullIfEmpty() ?? Global.TunIPv6Address.First();
|
||||||
tunInbound.settings.autoSystemRoutingTable = ["0.0.0.0/0"];
|
tunInbound.settings.gateway.Add(address6);
|
||||||
|
tunInbound.settings.autoSystemRoutingTable.Add("::/0");
|
||||||
}
|
}
|
||||||
|
|
||||||
var bindInterface = _config.CoreBasicItem.BindInterface?.TrimEx();
|
var bindInterface = _config.CoreBasicItem.BindInterface?.TrimEx();
|
||||||
if (!bindInterface.IsNullOrEmpty())
|
if (!bindInterface.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
@@ -152,6 +158,16 @@ public partial class CoreConfigV2rayService
|
|||||||
inbound.sniffing.destOverride = inItem.DestOverride;
|
inbound.sniffing.destOverride = inItem.DestOverride;
|
||||||
inbound.sniffing.routeOnly = inItem.RouteOnly;
|
inbound.sniffing.routeOnly = inItem.RouteOnly;
|
||||||
|
|
||||||
|
if (_config.SimpleDNSItem.FakeIP == true)
|
||||||
|
{
|
||||||
|
// Ensure destOverride contains "fakedns" if FakeIP is enabled
|
||||||
|
inbound.sniffing.destOverride ??= [];
|
||||||
|
if (!inbound.sniffing.destOverride.Contains("fakedns"))
|
||||||
|
{
|
||||||
|
inbound.sniffing.destOverride.Add("fakedns");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return inbound;
|
return inbound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -865,21 +865,10 @@ public partial class CoreConfigV2rayService
|
|||||||
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
|
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var (fragmentMask, noiseMask) = BuildFragmentsMasks();
|
var fragmentMask = BuildFragmentsMasks();
|
||||||
|
|
||||||
foreach (var outbound in actOutboundWithTlsList)
|
foreach (var outbound in actOutboundWithTlsList)
|
||||||
{
|
{
|
||||||
//var packets = configPackets;
|
|
||||||
//if (outbound.streamSettings.security == Global.StreamSecurityReality
|
|
||||||
// && packets == "tlshello")
|
|
||||||
//{
|
|
||||||
// packets = "1-3";
|
|
||||||
//}
|
|
||||||
//else if (outbound.streamSettings.security == Global.StreamSecurity
|
|
||||||
// && packets != "tlshello")
|
|
||||||
//{
|
|
||||||
// packets = "tlshello";
|
|
||||||
//}
|
|
||||||
var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject();
|
var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject();
|
||||||
// tcp fragment
|
// tcp fragment
|
||||||
var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? [];
|
var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? [];
|
||||||
@@ -888,13 +877,6 @@ public partial class CoreConfigV2rayService
|
|||||||
tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask));
|
tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask));
|
||||||
finalMaskJsonObj["tcp"] = tcpFinalmaskList;
|
finalMaskJsonObj["tcp"] = tcpFinalmaskList;
|
||||||
}
|
}
|
||||||
// udp noise
|
|
||||||
var udpFinalmaskList = finalMaskJsonObj["udp"] as JsonArray ?? [];
|
|
||||||
if (udpFinalmaskList.Count == 0)
|
|
||||||
{
|
|
||||||
udpFinalmaskList.Add(JsonUtils.SerializeToNode(noiseMask));
|
|
||||||
finalMaskJsonObj["udp"] = udpFinalmaskList;
|
|
||||||
}
|
|
||||||
// write back
|
// write back
|
||||||
outbound.streamSettings.finalmask = finalMaskJsonObj;
|
outbound.streamSettings.finalmask = finalMaskJsonObj;
|
||||||
}
|
}
|
||||||
@@ -902,7 +884,7 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
private void ApplyFinalFragment()
|
private void ApplyFinalFragment()
|
||||||
{
|
{
|
||||||
var (fragmentMask, noiseMask) = BuildFragmentsMasks();
|
var fragmentMask = BuildFragmentsMasks();
|
||||||
var actOutboundList = _coreConfig.outbounds.Where(n => n.tag.StartsWith(Global.ProxyTag)).ToList();
|
var actOutboundList = _coreConfig.outbounds.Where(n => n.tag.StartsWith(Global.ProxyTag)).ToList();
|
||||||
|
|
||||||
var fragmentFreedom = new Outbounds4Ray()
|
var fragmentFreedom = new Outbounds4Ray()
|
||||||
@@ -914,9 +896,8 @@ public partial class CoreConfigV2rayService
|
|||||||
finalmask = new Finalmask4Ray
|
finalmask = new Finalmask4Ray
|
||||||
{
|
{
|
||||||
tcp = [fragmentMask],
|
tcp = [fragmentMask],
|
||||||
udp = [noiseMask],
|
},
|
||||||
}
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var outbound in actOutboundList)
|
foreach (var outbound in actOutboundList)
|
||||||
@@ -934,13 +915,22 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Mask4Ray tcpFragment, Mask4Ray udpNoise) BuildFragmentsMasks()
|
private Mask4Ray BuildFragmentsMasks()
|
||||||
{
|
{
|
||||||
var configPackets = _config.Fragment4RayItem?.Packets.NullIfEmpty() ?? "tlshello";
|
var configPackets = _config.Fragment4RayItem?.Packets.NullIfEmpty() ?? "tlshello";
|
||||||
var configLength = _config.Fragment4RayItem?.Length.NullIfEmpty() ?? "50-100";
|
var configLengths = _config.Fragment4RayItem?.Lengths ?? [];
|
||||||
var configDelay = _config.Fragment4RayItem?.Interval.NullIfEmpty() ?? "10-20";
|
var configDelays = _config.Fragment4RayItem?.Delays ?? [];
|
||||||
var configMaxSplit = _config.Fragment4RayItem?.MaxSplit.NullIfEmpty() ?? "0";
|
var configMaxSplit = _config.Fragment4RayItem?.MaxSplit.NullIfEmpty() ?? "0";
|
||||||
|
|
||||||
|
if (configLengths.Count == 0)
|
||||||
|
{
|
||||||
|
configLengths = ["50-100"];
|
||||||
|
}
|
||||||
|
if (configDelays.Count == 0)
|
||||||
|
{
|
||||||
|
configDelays = ["10-20"];
|
||||||
|
}
|
||||||
|
|
||||||
var maxSplit = 0;
|
var maxSplit = 0;
|
||||||
var parts = configMaxSplit.Split('-');
|
var parts = configMaxSplit.Split('-');
|
||||||
if (parts.Length > 0 && int.TryParse(parts[0], out var ms))
|
if (parts.Length > 0 && int.TryParse(parts[0], out var ms))
|
||||||
@@ -954,21 +944,15 @@ public partial class CoreConfigV2rayService
|
|||||||
settings = new MaskSettings4Ray
|
settings = new MaskSettings4Ray
|
||||||
{
|
{
|
||||||
packets = configPackets,
|
packets = configPackets,
|
||||||
length = configLength,
|
lengths = configLengths,
|
||||||
delay = configDelay,
|
delays = configDelays,
|
||||||
maxSplit = maxSplit,
|
maxSplit = maxSplit,
|
||||||
}
|
// For legacy xray compatibility, remove this in the future
|
||||||
};
|
length = configLengths.FirstOrDefault(),
|
||||||
var noiseMask = new Mask4Ray
|
delay = configDelays.FirstOrDefault(),
|
||||||
{
|
},
|
||||||
type = "noise",
|
|
||||||
settings = new MaskSettings4Ray
|
|
||||||
{
|
|
||||||
length = "10-20",
|
|
||||||
delay = "10-16",
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (fragmentMask, noiseMask);
|
return fragmentMask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,20 @@ public partial class CoreConfigV2rayService
|
|||||||
_coreConfig.routing.rules.AddRange(tunRules);
|
_coreConfig.routing.rules.AddRange(tunRules);
|
||||||
}
|
}
|
||||||
var lstDirectExe = BuildRoutingDirectExe();
|
var lstDirectExe = BuildRoutingDirectExe();
|
||||||
_coreConfig.routing.rules.Add(new()
|
if (lstDirectExe.Count > 0)
|
||||||
{
|
{
|
||||||
port = "53",
|
_coreConfig.routing.rules.Add(new()
|
||||||
process = lstDirectExe,
|
{
|
||||||
outboundTag = Global.DnsOutboundTag,
|
port = "53",
|
||||||
});
|
process = lstDirectExe,
|
||||||
_coreConfig.routing.rules.Add(new()
|
outboundTag = Global.DnsOutboundTag,
|
||||||
{
|
});
|
||||||
process = lstDirectExe,
|
_coreConfig.routing.rules.Add(new()
|
||||||
outboundTag = Global.DirectTag,
|
{
|
||||||
});
|
process = lstDirectExe,
|
||||||
|
outboundTag = Global.DirectTag,
|
||||||
|
});
|
||||||
|
}
|
||||||
_coreConfig.routing.rules.Add(new()
|
_coreConfig.routing.rules.Add(new()
|
||||||
{
|
{
|
||||||
inboundTag = ["tun"],
|
inboundTag = ["tun"],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ namespace ServiceLib.ViewModels;
|
|||||||
public class AddServer2ViewModel : MyReactiveObject, ICloseable
|
public class AddServer2ViewModel : MyReactiveObject, ICloseable
|
||||||
{
|
{
|
||||||
public event EventHandler? RequestClose;
|
public event EventHandler? RequestClose;
|
||||||
|
|
||||||
public Interaction<Unit, string?> BrowseConfigFileInteraction { get; } = new();
|
public Interaction<Unit, string?> BrowseConfigFileInteraction { get; } = new();
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
|
|||||||
@@ -4,19 +4,22 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
{
|
{
|
||||||
public event EventHandler? RequestClose;
|
public event EventHandler? RequestClose;
|
||||||
|
|
||||||
[Reactive] public bool? UseSystemHosts { get; set; }
|
[Reactive] public bool UseSystemHosts { get; set; }
|
||||||
[Reactive] public bool? AddCommonHosts { get; set; }
|
[Reactive] public bool AddCommonHosts { get; set; }
|
||||||
[Reactive] public bool? FakeIP { get; set; }
|
[Reactive] public bool FakeIP { get; set; }
|
||||||
[Reactive] public bool? BlockBindingQuery { get; set; }
|
[Reactive] public string FakeIPRange { get; set; }
|
||||||
[Reactive] public string? DirectDNS { get; set; }
|
[Reactive] public bool BlockBindingQuery { get; set; }
|
||||||
[Reactive] public string? RemoteDNS { get; set; }
|
[Reactive] public string DirectDNS { get; set; }
|
||||||
[Reactive] public string? BootstrapDNS { get; set; }
|
[Reactive] public string RemoteDNS { get; set; }
|
||||||
[Reactive] public string? Strategy4Freedom { get; set; }
|
[Reactive] public string BootstrapDNS { get; set; }
|
||||||
[Reactive] public string? Strategy4Proxy { get; set; }
|
[Reactive] public string Strategy4Freedom { get; set; }
|
||||||
[Reactive] public string? Hosts { get; set; }
|
[Reactive] public string Strategy4Proxy { get; set; }
|
||||||
[Reactive] public string? DirectExpectedIPs { get; set; }
|
[Reactive] public string Strategy4ProxyDial { get; set; }
|
||||||
[Reactive] public bool? ParallelQuery { get; set; }
|
[Reactive] public string Hosts { get; set; }
|
||||||
[Reactive] public bool? ServeStale { get; set; }
|
[Reactive] public string DirectExpectedIPs { get; set; }
|
||||||
|
[Reactive] public bool ParallelQuery { get; set; }
|
||||||
|
[Reactive] public bool ServeStale { get; set; }
|
||||||
|
[Reactive] public bool EnableHappyEyeballs { get; set; }
|
||||||
|
|
||||||
[Reactive] public bool UseSystemHostsCompatible { get; set; }
|
[Reactive] public bool UseSystemHostsCompatible { get; set; }
|
||||||
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty;
|
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty;
|
||||||
@@ -67,20 +70,22 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
{
|
{
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
var item = _config.SimpleDNSItem;
|
var item = _config.SimpleDNSItem;
|
||||||
UseSystemHosts = item.UseSystemHosts;
|
UseSystemHosts = item.UseSystemHosts ?? false;
|
||||||
AddCommonHosts = item.AddCommonHosts;
|
AddCommonHosts = item.AddCommonHosts ?? false;
|
||||||
FakeIP = item.FakeIP;
|
FakeIP = item.FakeIP ?? false;
|
||||||
BlockBindingQuery = item.BlockBindingQuery;
|
FakeIPRange = item.FakeIPRange ?? string.Empty;
|
||||||
DirectDNS = item.DirectDNS;
|
BlockBindingQuery = item.BlockBindingQuery ?? false;
|
||||||
RemoteDNS = item.RemoteDNS;
|
DirectDNS = item.DirectDNS ?? string.Empty;
|
||||||
BootstrapDNS = item.BootstrapDNS;
|
RemoteDNS = item.RemoteDNS ?? string.Empty;
|
||||||
Strategy4Freedom = item.Strategy4Freedom;
|
BootstrapDNS = item.BootstrapDNS ?? string.Empty;
|
||||||
Strategy4Proxy = item.Strategy4Proxy;
|
Strategy4Freedom = item.Strategy4Freedom ?? string.Empty;
|
||||||
Hosts = item.Hosts;
|
Strategy4Proxy = item.Strategy4Proxy ?? string.Empty;
|
||||||
DirectExpectedIPs = item.DirectExpectedIPs;
|
Strategy4ProxyDial = item.Strategy4ProxyDial ?? string.Empty;
|
||||||
ParallelQuery = item.ParallelQuery;
|
Hosts = item.Hosts ?? string.Empty;
|
||||||
ServeStale = item.ServeStale;
|
DirectExpectedIPs = item.DirectExpectedIPs ?? string.Empty;
|
||||||
|
ParallelQuery = item.ParallelQuery ?? false;
|
||||||
|
ServeStale = item.ServeStale ?? false;
|
||||||
|
EnableHappyEyeballs = item.EnableHappyEyeballs ?? false;
|
||||||
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
|
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
RayCustomDNSEnableCompatible = item1.Enabled;
|
RayCustomDNSEnableCompatible = item1.Enabled;
|
||||||
UseSystemHostsCompatible = item1.UseSystemHosts;
|
UseSystemHostsCompatible = item1.UseSystemHosts;
|
||||||
@@ -102,17 +107,19 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
_config.SimpleDNSItem.UseSystemHosts = UseSystemHosts;
|
_config.SimpleDNSItem.UseSystemHosts = UseSystemHosts;
|
||||||
_config.SimpleDNSItem.AddCommonHosts = AddCommonHosts;
|
_config.SimpleDNSItem.AddCommonHosts = AddCommonHosts;
|
||||||
_config.SimpleDNSItem.FakeIP = FakeIP;
|
_config.SimpleDNSItem.FakeIP = FakeIP;
|
||||||
|
_config.SimpleDNSItem.FakeIPRange = FakeIPRange;
|
||||||
_config.SimpleDNSItem.BlockBindingQuery = BlockBindingQuery;
|
_config.SimpleDNSItem.BlockBindingQuery = BlockBindingQuery;
|
||||||
_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.Strategy4Freedom = Strategy4Freedom;
|
||||||
_config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy;
|
_config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy;
|
||||||
|
_config.SimpleDNSItem.Strategy4ProxyDial = Strategy4ProxyDial;
|
||||||
_config.SimpleDNSItem.Hosts = Hosts;
|
_config.SimpleDNSItem.Hosts = Hosts;
|
||||||
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
|
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
|
||||||
_config.SimpleDNSItem.ParallelQuery = ParallelQuery;
|
_config.SimpleDNSItem.ParallelQuery = ParallelQuery;
|
||||||
_config.SimpleDNSItem.ServeStale = ServeStale;
|
_config.SimpleDNSItem.ServeStale = ServeStale;
|
||||||
|
_config.SimpleDNSItem.EnableHappyEyeballs = EnableHappyEyeballs;
|
||||||
if (NormalDNSCompatible.IsNotEmpty())
|
if (NormalDNSCompatible.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var obj = JsonUtils.ParseJson(NormalDNSCompatible);
|
var obj = JsonUtils.ParseJson(NormalDNSCompatible);
|
||||||
|
|||||||
@@ -263,6 +263,11 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
|
|
||||||
#endregion AppEvents
|
#endregion AppEvents
|
||||||
|
|
||||||
|
ProfilesViewModel.RefreshServersRequested
|
||||||
|
.AsObservable()
|
||||||
|
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||||
|
.Subscribe(async _ => await RefreshServers());
|
||||||
|
|
||||||
var vmReloadRequestedList = new List<IObservable<Unit>>
|
var vmReloadRequestedList = new List<IObservable<Unit>>
|
||||||
{
|
{
|
||||||
ProfilesViewModel.ReloadRequested.AsObservable(),
|
ProfilesViewModel.ReloadRequested.AsObservable(),
|
||||||
@@ -394,8 +399,8 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private async Task RefreshServers()
|
private async Task RefreshServers()
|
||||||
{
|
{
|
||||||
await ProfilesViewModel.RefreshServers();
|
await ProfilesViewModel.RefreshServersBiz();
|
||||||
await StatusBarViewModel.RefreshServers();
|
await StatusBarViewModel.RefreshServersBiz();
|
||||||
|
|
||||||
// await Task.Delay(200);
|
// await Task.Delay(200);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,24 +29,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
[Reactive] public bool EnableFragment { get; set; }
|
[Reactive] public bool EnableFragment { get; set; }
|
||||||
[Reactive] public bool EnableFinalFragment { get; set; }
|
[Reactive] public bool EnableFinalFragment { get; set; }
|
||||||
[Reactive] public string FragmentPackets { get; set; }
|
[Reactive] public string FragmentPackets { get; set; }
|
||||||
[Reactive] public string FragmentLength { get; set; }
|
[Reactive] public string FragmentLengths { get; set; }
|
||||||
[Reactive] public string FragmentInterval { get; set; }
|
[Reactive] public string FragmentDelays { get; set; }
|
||||||
[Reactive] public string FragmentMaxSplit { get; set; }
|
[Reactive] public string FragmentMaxSplit { get; set; }
|
||||||
|
|
||||||
#endregion Core
|
#endregion Core
|
||||||
|
|
||||||
#region Core KCP
|
|
||||||
|
|
||||||
//[Reactive] public int Kcpmtu { get; set; }
|
|
||||||
//[Reactive] public int Kcptti { get; set; }
|
|
||||||
//[Reactive] public int KcpuplinkCapacity { get; set; }
|
|
||||||
//[Reactive] public int KcpdownlinkCapacity { get; set; }
|
|
||||||
//[Reactive] public int KcpreadBufferSize { get; set; }
|
|
||||||
//[Reactive] public int KcpwriteBufferSize { get; set; }
|
|
||||||
//[Reactive] public bool Kcpcongestion { get; set; }
|
|
||||||
|
|
||||||
#endregion Core KCP
|
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
|
|
||||||
[Reactive] public bool AutoRun { get; set; }
|
[Reactive] public bool AutoRun { get; set; }
|
||||||
@@ -107,6 +95,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
[Reactive] public string TunIcmpRouting { get; set; }
|
[Reactive] public string TunIcmpRouting { get; set; }
|
||||||
[Reactive] public bool TunEnableLegacyProtect { get; set; }
|
[Reactive] public bool TunEnableLegacyProtect { get; set; }
|
||||||
[Reactive] public string TunRouteExcludeAddress { get; set; }
|
[Reactive] public string TunRouteExcludeAddress { get; set; }
|
||||||
|
[Reactive] public string TunIPv4Address { get; set; }
|
||||||
|
[Reactive] public string TunIPv6Address { get; set; }
|
||||||
|
|
||||||
#endregion Tun mode
|
#endregion Tun mode
|
||||||
|
|
||||||
@@ -150,6 +140,7 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
SecondLocalPortEnabled = inbound.SecondLocalPortEnabled;
|
SecondLocalPortEnabled = inbound.SecondLocalPortEnabled;
|
||||||
UdpEnabled = inbound.UdpEnabled;
|
UdpEnabled = inbound.UdpEnabled;
|
||||||
SniffingEnabled = inbound.SniffingEnabled;
|
SniffingEnabled = inbound.SniffingEnabled;
|
||||||
|
DestOverride = inbound.DestOverride ?? [];
|
||||||
RouteOnly = inbound.RouteOnly;
|
RouteOnly = inbound.RouteOnly;
|
||||||
AllowLANConn = inbound.AllowLANConn;
|
AllowLANConn = inbound.AllowLANConn;
|
||||||
NewPort4LAN = inbound.NewPort4LAN;
|
NewPort4LAN = inbound.NewPort4LAN;
|
||||||
@@ -168,24 +159,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
EnableFragment = _config.CoreBasicItem.EnableFragment;
|
EnableFragment = _config.CoreBasicItem.EnableFragment;
|
||||||
EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment;
|
EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment;
|
||||||
FragmentPackets = _config.Fragment4RayItem?.Packets;
|
FragmentPackets = _config.Fragment4RayItem?.Packets;
|
||||||
FragmentLength = _config.Fragment4RayItem?.Length;
|
FragmentLengths = Utils.List2String(_config.Fragment4RayItem?.Lengths);
|
||||||
FragmentInterval = _config.Fragment4RayItem?.Interval;
|
FragmentDelays = Utils.List2String(_config.Fragment4RayItem?.Delays);
|
||||||
FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit;
|
FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit;
|
||||||
|
|
||||||
#endregion Core
|
#endregion Core
|
||||||
|
|
||||||
#region Core KCP
|
|
||||||
|
|
||||||
//Kcpmtu = _config.kcpItem.mtu;
|
|
||||||
//Kcptti = _config.kcpItem.tti;
|
|
||||||
//KcpuplinkCapacity = _config.kcpItem.uplinkCapacity;
|
|
||||||
//KcpdownlinkCapacity = _config.kcpItem.downlinkCapacity;
|
|
||||||
//KcpreadBufferSize = _config.kcpItem.readBufferSize;
|
|
||||||
//KcpwriteBufferSize = _config.kcpItem.writeBufferSize;
|
|
||||||
//Kcpcongestion = _config.kcpItem.congestion;
|
|
||||||
|
|
||||||
#endregion Core KCP
|
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
|
|
||||||
AutoRun = _config.GuiItem.AutoRun;
|
AutoRun = _config.GuiItem.AutoRun;
|
||||||
@@ -237,6 +216,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
TunIcmpRouting = _config.TunModeItem.IcmpRouting;
|
TunIcmpRouting = _config.TunModeItem.IcmpRouting;
|
||||||
TunEnableLegacyProtect = _config.TunModeItem.EnableLegacyProtect;
|
TunEnableLegacyProtect = _config.TunModeItem.EnableLegacyProtect;
|
||||||
TunRouteExcludeAddress = Utils.List2String(_config.TunModeItem.RouteExcludeAddress, true);
|
TunRouteExcludeAddress = Utils.List2String(_config.TunModeItem.RouteExcludeAddress, true);
|
||||||
|
TunIPv4Address = _config.TunModeItem.IPv4Address;
|
||||||
|
TunIPv6Address = _config.TunModeItem.IPv6Address;
|
||||||
|
|
||||||
#endregion Tun mode
|
#endregion Tun mode
|
||||||
|
|
||||||
@@ -309,34 +290,33 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
|
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var fragmentLengths = Utils.String2List(FragmentLengths) ?? [];
|
||||||
|
var fragmentDelays = Utils.String2List(FragmentDelays) ?? [];
|
||||||
|
if (fragmentLengths.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _))
|
||||||
|
|| fragmentDelays.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _))
|
||||||
|
|| (FragmentMaxSplit.IsNotEmpty() && !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _)))
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics
|
var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics
|
||||||
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|
||||||
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
|
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
|
||||||
|| EnableHWA != _config.GuiItem.EnableHWA
|
|| EnableHWA != _config.GuiItem.EnableHWA
|
||||||
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily;
|
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily;
|
||||||
|
|
||||||
//if (Utile.IsNullOrEmpty(Kcpmtu.ToString()) || !Utile.IsNumeric(Kcpmtu.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(Kcptti.ToString()) || !Utile.IsNumeric(Kcptti.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpuplinkCapacity.ToString()) || !Utile.IsNumeric(KcpuplinkCapacity.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpdownlinkCapacity.ToString()) || !Utile.IsNumeric(KcpdownlinkCapacity.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpreadBufferSize.ToString()) || !Utile.IsNumeric(KcpreadBufferSize.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpwriteBufferSize.ToString()) || !Utile.IsNumeric(KcpwriteBufferSize.ToString()))
|
|
||||||
//{
|
|
||||||
// NoticeHandler.Instance.Enqueue(ResUI.FillKcpParameters);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//Core
|
//Core
|
||||||
_config.Inbound.First().LocalPort = LocalPort;
|
var inbound = _config.Inbound.First();
|
||||||
_config.Inbound.First().SecondLocalPortEnabled = SecondLocalPortEnabled;
|
inbound.LocalPort = LocalPort;
|
||||||
_config.Inbound.First().UdpEnabled = UdpEnabled;
|
inbound.SecondLocalPortEnabled = SecondLocalPortEnabled;
|
||||||
_config.Inbound.First().SniffingEnabled = SniffingEnabled;
|
inbound.UdpEnabled = UdpEnabled;
|
||||||
_config.Inbound.First().DestOverride = DestOverride?.ToList();
|
inbound.SniffingEnabled = SniffingEnabled;
|
||||||
_config.Inbound.First().RouteOnly = RouteOnly;
|
inbound.DestOverride = DestOverride?.ToList();
|
||||||
_config.Inbound.First().AllowLANConn = AllowLANConn;
|
inbound.RouteOnly = RouteOnly;
|
||||||
_config.Inbound.First().NewPort4LAN = NewPort4LAN;
|
inbound.AllowLANConn = AllowLANConn;
|
||||||
_config.Inbound.First().User = User;
|
inbound.NewPort4LAN = NewPort4LAN;
|
||||||
_config.Inbound.First().Pass = Pass;
|
inbound.User = User;
|
||||||
|
inbound.Pass = Pass;
|
||||||
if (_config.Inbound.Count > 1)
|
if (_config.Inbound.Count > 1)
|
||||||
{
|
{
|
||||||
_config.Inbound.RemoveAt(1);
|
_config.Inbound.RemoveAt(1);
|
||||||
@@ -351,30 +331,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
_config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox;
|
_config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox;
|
||||||
_config.HysteriaItem.UpMbps = HyUpMbps ?? 0;
|
_config.HysteriaItem.UpMbps = HyUpMbps ?? 0;
|
||||||
_config.HysteriaItem.DownMbps = HyDownMbps ?? 0;
|
_config.HysteriaItem.DownMbps = HyDownMbps ?? 0;
|
||||||
if (EnableFragment)
|
|
||||||
{
|
|
||||||
if (!Utils.TryParseRange(FragmentLength, 0, int.MaxValue, out _, out _))
|
|
||||||
{
|
|
||||||
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!Utils.TryParseRange(FragmentInterval, 1, 100, out _, out _))
|
|
||||||
{
|
|
||||||
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (FragmentMaxSplit.IsNotEmpty()
|
|
||||||
&& !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _))
|
|
||||||
{
|
|
||||||
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_config.CoreBasicItem.EnableFragment = EnableFragment;
|
_config.CoreBasicItem.EnableFragment = EnableFragment;
|
||||||
_config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment;
|
_config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment;
|
||||||
|
_config.Fragment4RayItem ??= new();
|
||||||
_config.Fragment4RayItem.Packets = FragmentPackets;
|
_config.Fragment4RayItem.Packets = FragmentPackets;
|
||||||
_config.Fragment4RayItem.Length = FragmentLength;
|
_config.Fragment4RayItem.Lengths = fragmentLengths;
|
||||||
_config.Fragment4RayItem.Interval = FragmentInterval;
|
_config.Fragment4RayItem.Delays = fragmentDelays;
|
||||||
_config.Fragment4RayItem.MaxSplit = FragmentMaxSplit;
|
_config.Fragment4RayItem.MaxSplit = FragmentMaxSplit;
|
||||||
|
|
||||||
_config.GuiItem.AutoRun = AutoRun;
|
_config.GuiItem.AutoRun = AutoRun;
|
||||||
@@ -420,6 +382,8 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
_config.TunModeItem.IcmpRouting = TunIcmpRouting;
|
_config.TunModeItem.IcmpRouting = TunIcmpRouting;
|
||||||
_config.TunModeItem.EnableLegacyProtect = TunEnableLegacyProtect;
|
_config.TunModeItem.EnableLegacyProtect = TunEnableLegacyProtect;
|
||||||
_config.TunModeItem.RouteExcludeAddress = Utils.String2List(TunRouteExcludeAddress);
|
_config.TunModeItem.RouteExcludeAddress = Utils.String2List(TunRouteExcludeAddress);
|
||||||
|
_config.TunModeItem.IPv4Address = TunIPv4Address;
|
||||||
|
_config.TunModeItem.IPv6Address = TunIPv6Address;
|
||||||
|
|
||||||
//coreType
|
//coreType
|
||||||
await SaveCoreType();
|
await SaveCoreType();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ namespace ServiceLib.ViewModels;
|
|||||||
public class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
public class ProfilesSelectViewModel : MyReactiveObject, ICloseable
|
||||||
{
|
{
|
||||||
public event EventHandler? RequestClose;
|
public event EventHandler? RequestClose;
|
||||||
|
|
||||||
public Interaction<Unit, Unit> ProfilesFocusInteraction { get; } = new();
|
public Interaction<Unit, Unit> ProfilesFocusInteraction { get; } = new();
|
||||||
|
|
||||||
#region private prop
|
#region private prop
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
public Interaction<Unit, Unit> AdjustMainLvColWidthInteraction { get; } = new();
|
public Interaction<Unit, Unit> AdjustMainLvColWidthInteraction { get; } = new();
|
||||||
|
|
||||||
public EventChannel<Unit> ReloadRequested { get; } = new();
|
public EventChannel<Unit> ReloadRequested { get; } = new();
|
||||||
|
public EventChannel<Unit> RefreshServersRequested { get; } = new();
|
||||||
|
|
||||||
#region private prop
|
#region private prop
|
||||||
|
|
||||||
@@ -368,12 +369,14 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
|
|
||||||
public async Task RefreshServers()
|
public async Task RefreshServers()
|
||||||
{
|
{
|
||||||
await RefreshServersBiz();
|
RefreshServersRequested.Publish();
|
||||||
|
|
||||||
// await Task.Delay(200);
|
// await Task.Delay(200);
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshServersBiz()
|
public async Task RefreshServersBiz()
|
||||||
{
|
{
|
||||||
var lstModel = await GetProfileItemsEx(_config.SubIndexId, _serverFilter);
|
var lstModel = await GetProfileItemsEx(_config.SubIndexId, _serverFilter);
|
||||||
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
|
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ namespace ServiceLib.ViewModels;
|
|||||||
public class RoutingRuleSettingViewModel : MyReactiveObject, ICloseable
|
public class RoutingRuleSettingViewModel : MyReactiveObject, ICloseable
|
||||||
{
|
{
|
||||||
public event EventHandler? RequestClose;
|
public event EventHandler? RequestClose;
|
||||||
|
|
||||||
public Interaction<string, bool> ShowYesNoInteraction { get; } = new();
|
public Interaction<string, bool> ShowYesNoInteraction { get; } = new();
|
||||||
public Interaction<string, Unit> SetClipboardDataInteraction { get; } = new();
|
public Interaction<string, Unit> SetClipboardDataInteraction { get; } = new();
|
||||||
public Interaction<Unit, string?> ReadTextFromClipboardInteraction { get; } = new();
|
public Interaction<Unit, string?> ReadTextFromClipboardInteraction { get; } = new();
|
||||||
|
|||||||
@@ -264,12 +264,7 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RefreshServers()
|
public async Task RefreshServersBiz()
|
||||||
{
|
|
||||||
await RefreshServersBiz();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RefreshServersBiz()
|
|
||||||
{
|
{
|
||||||
await RefreshServersMenu();
|
await RefreshServersMenu();
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,14 @@
|
|||||||
<StyleInclude Source="Assets/GlobalStyles.axaml" />
|
<StyleInclude Source="Assets/GlobalStyles.axaml" />
|
||||||
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
||||||
<dialogHost:DialogHostStyles />
|
<dialogHost:DialogHostStyles />
|
||||||
|
|
||||||
|
<Style Selector="dialogHost|DialogHost">
|
||||||
|
<Setter Property="OverlayBackground" Value="{DynamicResource SemiColorOverlayBackground}" />
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SemiColorFill0}" />
|
||||||
|
|
||||||
|
<Setter Property="dialogHost:DialogHostStyle.BoxShadow" Value="{DynamicResource SemiShadowElevated}" />
|
||||||
|
<Setter Property="dialogHost:DialogHostStyle.CornerRadius" Value="6" />
|
||||||
|
</Style>
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
|
|
||||||
<TrayIcon.Icons>
|
<TrayIcon.Icons>
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -43,11 +48,6 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Context menu actions that require custom logic (Add, SelectAll)
|
// Context menu actions that require custom logic (Add, SelectAll)
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -188,11 +193,6 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
x:Name="gridBasicDNSSettings"
|
x:Name="gridBasicDNSSettings"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
ColumnDefinitions="Auto,Auto,*"
|
ColumnDefinitions="Auto,Auto,*"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="txtBasicDNSSettingsInvalid"
|
x:Name="txtBasicDNSSettingsInvalid"
|
||||||
@@ -167,28 +167,71 @@
|
|||||||
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.TbProxyDialResolveStrategy}" />
|
||||||
<ToggleSwitch
|
<ComboBox
|
||||||
x:Name="togParallelQuery"
|
x:Name="cmbProxyDialDNSStrategy"
|
||||||
Grid.Row="7"
|
Grid.Row="7"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
VerticalAlignment="Center"
|
||||||
VerticalAlignment="Center" />
|
PlaceholderText="Default" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategyTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbServeStale}" />
|
Text="{x:Static resx:ResUI.TbParallelQuery}" />
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
x:Name="togServeStale"
|
x:Name="togParallelQuery"
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center" />
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbServeStale}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togServeStale"
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togEnableHappyEyeballs"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -243,13 +286,24 @@
|
|||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
||||||
<ToggleSwitch
|
<Grid
|
||||||
x:Name="togFakeIP"
|
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin4}"
|
ColumnDefinitions="Auto,*">
|
||||||
HorizontalAlignment="Left"
|
<ToggleSwitch
|
||||||
VerticalAlignment="Center" />
|
x:Name="togFakeIP"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbFakeIPRange"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsEditable="True" />
|
||||||
|
</Grid>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
@@ -318,8 +372,8 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
TextWrapping="Wrap"
|
PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}"
|
||||||
PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}" />
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
|||||||
|
|
||||||
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
|
cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
||||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||||
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
|
cmbFakeIPRange.ItemsSource = Global.FakeIPRanges;
|
||||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||||
|
|
||||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
||||||
@@ -31,16 +33,19 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.FakeIPRange, v => v.cmbFakeIPRange.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||||
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.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.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.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.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);
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,7 @@
|
|||||||
ShowInTaskbar="True"
|
ShowInTaskbar="True"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<dialogHost:DialogHost
|
<dialogHost:DialogHost CloseOnClickAway="True" DisableOpeningAnimation="True">
|
||||||
Background="Gray"
|
|
||||||
CloseOnClickAway="True"
|
|
||||||
DisableOpeningAnimation="True">
|
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<DockPanel Margin="{StaticResource Margin8}" DockPanel.Dock="Top">
|
<DockPanel Margin="{StaticResource Margin8}" DockPanel.Dock="Top">
|
||||||
<ContentControl x:Name="conTheme" DockPanel.Dock="Right" />
|
<ContentControl x:Name="conTheme" DockPanel.Dock="Right" />
|
||||||
|
|||||||
@@ -347,7 +347,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" />
|
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentLength"
|
x:Name="txtFragmentLengths"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="120"
|
Width="120"
|
||||||
@@ -369,7 +369,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}" />
|
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentInterval"
|
x:Name="txtFragmentDelays"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="120"
|
Width="120"
|
||||||
@@ -961,7 +961,7 @@
|
|||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
ColumnDefinitions="Auto,Auto,Auto"
|
ColumnDefinitions="Auto,Auto,Auto"
|
||||||
DockPanel.Dock="Top"
|
DockPanel.Dock="Top"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
@@ -1087,6 +1087,34 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbRouteExcludeAddressTip}"
|
Text="{x:Static resx:ResUI.TbRouteExcludeAddressTip}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbIpv4Address}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbIpv4Address"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="11"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbIpv6Address}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbIpv6Address"
|
||||||
|
Grid.Row="11"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
|||||||
cmbMtu.ItemsSource = Global.TunMtus;
|
cmbMtu.ItemsSource = Global.TunMtus;
|
||||||
cmbStack.ItemsSource = Global.TunStacks;
|
cmbStack.ItemsSource = Global.TunStacks;
|
||||||
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
|
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
|
||||||
|
cmbIpv4Address.ItemsSource = Global.TunIPv4Address;
|
||||||
|
cmbIpv6Address.ItemsSource = Global.TunIPv6Address;
|
||||||
cmbFragmentPackets.ItemsSource = Global.FragmentPacketsOptions;
|
cmbFragmentPackets.ItemsSource = Global.FragmentPacketsOptions;
|
||||||
|
|
||||||
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
||||||
@@ -86,8 +88,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentDelays, v => v.txtFragmentDelays.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
||||||
@@ -129,6 +131,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunRouteExcludeAddress, v => v.txtRouteExcludeAddress.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunRouteExcludeAddress, v => v.txtRouteExcludeAddress.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TunIPv4Address, v => v.cmbIpv4Address.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TunIPv6Address, v => v.cmbIpv6Address.SelectedValue).DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
@@ -35,11 +40,6 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
|
|||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<dialogHost:DialogHost
|
<dialogHost:DialogHost
|
||||||
Background="Gray"
|
|
||||||
CloseOnClickAway="True"
|
CloseOnClickAway="True"
|
||||||
DisableOpeningAnimation="True"
|
DisableOpeningAnimation="True"
|
||||||
Identifier="dialogHostSub">
|
Identifier="dialogHostSub">
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ public partial class AddGroupServerWindow
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.Text).DisposeWith(disposables);
|
||||||
@@ -45,11 +50,6 @@ public partial class AddGroupServerWindow
|
|||||||
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ public partial class AddServerWindow
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
||||||
@@ -186,11 +191,6 @@ public partial class AddServerWindow
|
|||||||
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
||||||
|
|||||||
@@ -52,6 +52,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@@ -195,13 +197,23 @@
|
|||||||
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.TbProxyDialResolveStrategy}" />
|
||||||
<ToggleButton
|
<ComboBox
|
||||||
x:Name="togParallelQuery"
|
x:Name="cmbProxyDialDNSStrategy"
|
||||||
Grid.Row="7"
|
Grid.Row="7"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
HorizontalAlignment="Left" />
|
materialDesign:HintAssist.Hint="Default"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategyTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
@@ -209,13 +221,49 @@
|
|||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbServeStale}" />
|
Text="{x:Static resx:ResUI.TbParallelQuery}" />
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
x:Name="togServeStale"
|
x:Name="togParallelQuery"
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbServeStale}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togServeStale"
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togEnableHappyEyeballs"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -283,12 +331,25 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
||||||
<ToggleButton
|
<Grid Grid.Row="3" Grid.Column="1">
|
||||||
x:Name="togFakeIP"
|
<Grid.ColumnDefinitions>
|
||||||
Grid.Row="3"
|
<ColumnDefinition Width="Auto" />
|
||||||
Grid.Column="1"
|
<ColumnDefinition Width="*" />
|
||||||
Margin="{StaticResource Margin8}"
|
</Grid.ColumnDefinitions>
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togFakeIP"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbFakeIPRange"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
IsEditable="True"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</Grid>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ public partial class DNSSettingWindow
|
|||||||
|
|
||||||
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
|
cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
||||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||||
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
|
cmbFakeIPRange.ItemsSource = Global.FakeIPRanges;
|
||||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||||
|
|
||||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
||||||
@@ -27,16 +29,19 @@ public partial class DNSSettingWindow
|
|||||||
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.FakeIPRange, v => v.cmbFakeIPRange.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||||
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.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.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.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.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);
|
||||||
|
|
||||||
|
|||||||
@@ -419,7 +419,7 @@
|
|||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}"
|
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentLength"
|
x:Name="txtFragmentLengths"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
@@ -437,7 +437,7 @@
|
|||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}"
|
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentInterval"
|
x:Name="txtFragmentDelays"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
@@ -1198,6 +1198,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@@ -1346,6 +1348,39 @@
|
|||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbRouteExcludeAddressTip}"
|
Text="{x:Static resx:ResUI.TbRouteExcludeAddressTip}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbIpv4Address}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbIpv4Address"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="11"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbIpv6Address}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbIpv6Address"
|
||||||
|
Grid.Row="11"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ public partial class OptionSettingWindow
|
|||||||
cmbMtu.ItemsSource = Global.TunMtus;
|
cmbMtu.ItemsSource = Global.TunMtus;
|
||||||
cmbStack.ItemsSource = Global.TunStacks;
|
cmbStack.ItemsSource = Global.TunStacks;
|
||||||
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
|
cmbIcmpRoutingPolicy.ItemsSource = Global.TunIcmpRoutingPolicies;
|
||||||
|
cmbIpv4Address.ItemsSource = Global.TunIPv4Address;
|
||||||
|
cmbIpv6Address.ItemsSource = Global.TunIPv6Address;
|
||||||
cmbFragmentPackets.ItemsSource = Global.FragmentPacketsOptions;
|
cmbFragmentPackets.ItemsSource = Global.FragmentPacketsOptions;
|
||||||
|
|
||||||
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
cmbCoreType1.ItemsSource = Global.CoreTypes;
|
||||||
@@ -82,18 +84,10 @@ public partial class OptionSettingWindow
|
|||||||
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentDelays, v => v.txtFragmentDelays.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
//this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables);
|
|
||||||
//this.Bind(ViewModel, vm => vm.Kcptti, v => v.txtKcptti.Text).DisposeWith(disposables);
|
|
||||||
//this.Bind(ViewModel, vm => vm.KcpuplinkCapacity, v => v.txtKcpuplinkCapacity.Text).DisposeWith(disposables);
|
|
||||||
//this.Bind(ViewModel, vm => vm.KcpdownlinkCapacity, v => v.txtKcpdownlinkCapacity.Text).DisposeWith(disposables);
|
|
||||||
//this.Bind(ViewModel, vm => vm.KcpreadBufferSize, v => v.txtKcpreadBufferSize.Text).DisposeWith(disposables);
|
|
||||||
//this.Bind(ViewModel, vm => vm.KcpwriteBufferSize, v => v.txtKcpwriteBufferSize.Text).DisposeWith(disposables);
|
|
||||||
//this.Bind(ViewModel, vm => vm.Kcpcongestion, v => v.togKcpcongestion.IsChecked).DisposeWith(disposables);
|
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DisplayRealTimeSpeed, v => v.togDisplayRealTimeSpeed.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DisplayRealTimeSpeed, v => v.togDisplayRealTimeSpeed.IsChecked).DisposeWith(disposables);
|
||||||
@@ -132,6 +126,8 @@ public partial class OptionSettingWindow
|
|||||||
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunIcmpRouting, v => v.cmbIcmpRoutingPolicy.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunEnableLegacyProtect, v => v.togEnableLegacyProtect.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunRouteExcludeAddress, v => v.txtRouteExcludeAddress.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunRouteExcludeAddress, v => v.txtRouteExcludeAddress.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TunIPv4Address, v => v.cmbIpv4Address.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TunIPv6Address, v => v.cmbIpv6Address.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.Text).DisposeWith(disposables);
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ public partial class RoutingRuleDetailsWindow
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
||||||
@@ -31,11 +36,6 @@ public partial class RoutingRuleDetailsWindow
|
|||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ public partial class StatusBarView
|
|||||||
interaction.SetOutput(Unit.Default);
|
interaction.SetOutput(Unit.Default);
|
||||||
}).DisposeWith(disposables);
|
}).DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_ = RefreshIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshIcon()
|
private async Task RefreshIcon()
|
||||||
|
|||||||
Reference in New Issue
Block a user