mirror of
https://github.com/2dust/v2rayN.git
synced 2026-02-28 05:03:02 +00:00
Compare commits
14 commits
bbbe18ba88
...
22e9713fdc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22e9713fdc | ||
|
|
9824bb12ed | ||
|
|
f11c2214be | ||
|
|
67c4ae02ba | ||
|
|
ed1275e29f | ||
|
|
0cf07e925f | ||
|
|
49e487886d | ||
|
|
ad07f281c7 | ||
|
|
f98f517368 | ||
|
|
7931058342 | ||
|
|
b53507f486 | ||
|
|
68ea10158a | ||
|
|
2f35e7a99c | ||
|
|
3c1ecf085b |
56 changed files with 1157 additions and 608 deletions
6
.github/workflows/build-linux.yml
vendored
6
.github/workflows/build-linux.yml
vendored
|
|
@ -50,7 +50,7 @@ jobs:
|
|||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 -p:SelfContained=true -p:PublishTrimmed=true -o "$OutputPathArm64"
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v6.0.0
|
||||
uses: actions/upload-artifact@v7.0.0
|
||||
with:
|
||||
name: v2rayN-linux
|
||||
path: |
|
||||
|
|
@ -169,7 +169,7 @@ jobs:
|
|||
fetch-depth: '0'
|
||||
|
||||
- name: Restore build artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: v2rayN-linux
|
||||
path: ${{ github.workspace }}/v2rayN/Release
|
||||
|
|
@ -190,7 +190,7 @@ jobs:
|
|||
ls -R "$GITHUB_WORKSPACE/dist/rpm" || true
|
||||
|
||||
- name: Upload RPM artifacts
|
||||
uses: actions/upload-artifact@v6.0.0
|
||||
uses: actions/upload-artifact@v7.0.0
|
||||
with:
|
||||
name: v2rayN-rpm
|
||||
path: dist/rpm/**/*.rpm
|
||||
|
|
|
|||
2
.github/workflows/build-osx.yml
vendored
2
.github/workflows/build-osx.yml
vendored
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 -p:SelfContained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v6.0.0
|
||||
uses: actions/upload-artifact@v7.0.0
|
||||
with:
|
||||
name: v2rayN-macos
|
||||
path: |
|
||||
|
|
|
|||
2
.github/workflows/build-windows-desktop.yml
vendored
2
.github/workflows/build-windows-desktop.yml
vendored
|
|
@ -45,7 +45,7 @@ jobs:
|
|||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v6.0.0
|
||||
uses: actions/upload-artifact@v7.0.0
|
||||
with:
|
||||
name: v2rayN-windows-desktop
|
||||
path: |
|
||||
|
|
|
|||
2
.github/workflows/build-windows.yml
vendored
2
.github/workflows/build-windows.yml
vendored
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 -p:SelfContained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v6.0.0
|
||||
uses: actions/upload-artifact@v7.0.0
|
||||
with:
|
||||
name: v2rayN-windows
|
||||
path: |
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ cp -rf $OutputPath "${PackagePath}/opt/v2rayN"
|
|||
echo "When this file exists, app will not store configs under this folder" > "${PackagePath}/opt/v2rayN/NotStoreConfigHere.txt"
|
||||
|
||||
if [ $Arch = "linux-64" ]; then
|
||||
Arch2="amd64"
|
||||
Arch2="amd64"
|
||||
else
|
||||
Arch2="arm64"
|
||||
fi
|
||||
|
|
@ -32,9 +32,8 @@ Depends: libc6 (>= 2.34), fontconfig (>= 2.13.1), desktop-file-utils (>= 0.26),
|
|||
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
EOF
|
||||
|
||||
cat >"${PackagePath}/DEBIAN/postinst" <<-EOF
|
||||
if [ ! -s /usr/share/applications/v2rayN.desktop ]; then
|
||||
cat >/usr/share/applications/v2rayN.desktop<<-END
|
||||
mkdir -p "${PackagePath}/usr/share/applications"
|
||||
cat >"${PackagePath}/usr/share/applications/v2rayN.desktop" <<-EOF
|
||||
[Desktop Entry]
|
||||
Name=v2rayN
|
||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
|
|
@ -43,10 +42,12 @@ Icon=/opt/v2rayN/v2rayN.png
|
|||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;Application;
|
||||
END
|
||||
fi
|
||||
EOF
|
||||
|
||||
update-desktop-database
|
||||
cat >"${PackagePath}/DEBIAN/postinst" <<-'EOF'
|
||||
set -e
|
||||
update-desktop-database || true
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
sudo chmod 0755 "${PackagePath}/DEBIAN/postinst"
|
||||
|
|
|
|||
370
package-rhel.sh
370
package-rhel.sh
|
|
@ -1,45 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ====== Require Red Hat Enterprise Linux/FedoraLinux/RockyLinux/AlmaLinux/CentOS ======
|
||||
if [[ -r /etc/os-release ]]; then
|
||||
. /etc/os-release
|
||||
case "$ID" in
|
||||
rhel|rocky|almalinux|fedora|centos)
|
||||
echo "[OK] Detected supported system: $NAME $VERSION_ID"
|
||||
;;
|
||||
*)
|
||||
echo "[ERROR] Unsupported system: $NAME ($ID)."
|
||||
echo "This script only supports Red Hat Enterprise Linux/RockyLinux/AlmaLinux/CentOS."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "[ERROR] Cannot detect system (missing /etc/os-release)."
|
||||
exit 1
|
||||
# Require Red Hat base branch
|
||||
. /etc/os-release
|
||||
|
||||
case "${ID:-}" in
|
||||
rhel|rocky|almalinux|fedora|centos)
|
||||
echo "Detected supported system: ${NAME:-$ID} ${VERSION_ID:-}"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported system: ${NAME:-unknown} (${ID:-unknown})."
|
||||
echo "This script only supports: RHEL / Rocky / AlmaLinux / Fedora / CentOS."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Kernel version
|
||||
MIN_KERNEL="6.11"
|
||||
CURRENT_KERNEL="$(uname -r)"
|
||||
|
||||
lowest="$(printf '%s\n%s\n' "$MIN_KERNEL" "$CURRENT_KERNEL" | sort -V | head -n1)"
|
||||
|
||||
if [[ "$lowest" != "$MIN_KERNEL" ]]; then
|
||||
echo "Kernel $CURRENT_KERNEL is below $MIN_KERNEL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ======================== Kernel version check (require >= 6.11) =======================
|
||||
MIN_KERNEL_MAJOR=6
|
||||
MIN_KERNEL_MINOR=11
|
||||
KERNEL_FULL=$(uname -r)
|
||||
KERNEL_MAJOR=$(echo "$KERNEL_FULL" | cut -d. -f1)
|
||||
KERNEL_MINOR=$(echo "$KERNEL_FULL" | cut -d. -f2)
|
||||
echo "[OK] Kernel $CURRENT_KERNEL verified."
|
||||
|
||||
echo "[INFO] Detected kernel version: $KERNEL_FULL"
|
||||
|
||||
if (( KERNEL_MAJOR < MIN_KERNEL_MAJOR )) || { (( KERNEL_MAJOR == MIN_KERNEL_MAJOR )) && (( KERNEL_MINOR < MIN_KERNEL_MINOR )); }; then
|
||||
echo "[ERROR] Kernel $KERNEL_FULL is too old. Requires Linux >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
||||
echo "Please upgrade your system or use a newer container (e.g. Fedora 42+, RHEL 10+)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[OK] Kernel version >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
||||
|
||||
# ===== Config & Parse arguments =========================================================
|
||||
# Config & Parse arguments
|
||||
VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty
|
||||
WITH_CORE="both" # Default: bundle both xray+sing-box
|
||||
AUTOSTART=0 # 1 = enable system-wide autostart (/etc/xdg/autostart)
|
||||
FORCE_NETCORE=0 # --netcore => skip archive bundle, use separate downloads
|
||||
ARCH_OVERRIDE="" # --arch x64|arm64|all (optional compile target)
|
||||
BUILD_FROM="" # --buildfrom 1|2|3 to select channel non-interactively
|
||||
|
|
@ -55,7 +46,6 @@ if [[ -n "${VERSION_ARG:-}" ]]; then shift || true; fi
|
|||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--with-core) WITH_CORE="${2:-both}"; shift 2;;
|
||||
--autostart) AUTOSTART=1; shift;;
|
||||
--xray-ver) XRAY_VER="${2:-}"; shift 2;;
|
||||
--singbox-ver) SING_VER="${2:-}"; shift 2;;
|
||||
--netcore) FORCE_NETCORE=1; shift;;
|
||||
|
|
@ -69,38 +59,26 @@ done
|
|||
|
||||
# Conflict: version number AND --buildfrom cannot be used together
|
||||
if [[ -n "${VERSION_ARG:-}" && -n "${BUILD_FROM:-}" ]]; then
|
||||
echo "[ERROR] You cannot specify both an explicit version and --buildfrom at the same time."
|
||||
echo "You cannot specify both an explicit version and --buildfrom at the same time."
|
||||
echo " Provide either a version (e.g. 7.14.0) OR --buildfrom 1|2|3."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ===== Environment check + Dependencies ========================================
|
||||
# Check and install dependencies
|
||||
host_arch="$(uname -m)"
|
||||
[[ "$host_arch" == "aarch64" || "$host_arch" == "x86_64" ]] || { echo "Only supports aarch64 / x86_64"; exit 1; }
|
||||
|
||||
install_ok=0
|
||||
case "$ID" in
|
||||
rhel|rocky|almalinux|centos)
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \
|
||||
sudo dnf -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync
|
||||
install_ok=1
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
sudo yum -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync || \
|
||||
sudo yum -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync
|
||||
install_ok=1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$install_ok" -ne 1 ]]; then
|
||||
echo "[WARN] Could not auto-install dependencies for '$ID'. Make sure these are available:"
|
||||
echo " dotnet-sdk 8.x, curl, unzip, tar, rsync, rpm, rpmdevtools, rpm-build (on RPM-based distros)"
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
sudo dnf -y install rpm-build rpmdevtools curl unzip tar jq rsync dotnet-sdk-8.0 \
|
||||
&& install_ok=1
|
||||
fi
|
||||
|
||||
command -v curl >/dev/null
|
||||
if [[ "$install_ok" -ne 1 ]]; then
|
||||
echo "Could not auto-install dependencies for '$ID'. Make sure these are available:"
|
||||
echo "dotnet-sdk 8.x, curl, unzip, tar, rsync, rpm, rpmdevtools, rpm-build (on Red Hat branch)"
|
||||
fi
|
||||
|
||||
# Root directory
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
|
@ -119,9 +97,6 @@ if [[ ! -f "$PROJECT" ]]; then
|
|||
fi
|
||||
[[ -f "$PROJECT" ]] || { echo "v2rayN.Desktop.csproj not found"; exit 1; }
|
||||
|
||||
# Resolve GUI version & auto checkout
|
||||
VERSION=""
|
||||
|
||||
choose_channel() {
|
||||
# If --buildfrom provided, map it directly and skip interaction.
|
||||
if [[ -n "${BUILD_FROM:-}" ]]; then
|
||||
|
|
@ -135,60 +110,35 @@ choose_channel() {
|
|||
|
||||
# Print menu to stderr and read from /dev/tty so stdout only carries the token.
|
||||
local ch="latest" sel=""
|
||||
|
||||
if [[ -t 0 ]]; then
|
||||
echo "[?] Choose v2rayN release channel:" >&2
|
||||
echo " 1) Latest (stable) [default]" >&2
|
||||
echo " 2) Pre-release (preview)" >&2
|
||||
echo " 3) Keep current (do nothing)" >&2
|
||||
printf "Enter 1, 2 or 3 [default 1]: " >&2
|
||||
|
||||
if read -r sel </dev/tty; then
|
||||
case "${sel:-}" in
|
||||
2) ch="prerelease" ;;
|
||||
3) ch="keep" ;;
|
||||
*) ch="latest" ;;
|
||||
esac
|
||||
else
|
||||
ch="latest"
|
||||
fi
|
||||
else
|
||||
ch="latest"
|
||||
fi
|
||||
|
||||
echo "$ch"
|
||||
}
|
||||
|
||||
get_latest_tag_latest() {
|
||||
# Resolve /releases/latest → tag_name
|
||||
curl -fsSL "https://api.github.com/repos/2dust/v2rayN/releases/latest" \
|
||||
| grep -Eo '"tag_name":\s*"v?[^"]+"' \
|
||||
| head -n1 \
|
||||
| sed -E 's/.*"tag_name":\s*"v?([^"]+)".*/\1/'
|
||||
| jq -re '.tag_name' \
|
||||
| sed 's/^v//'
|
||||
}
|
||||
|
||||
get_latest_tag_prerelease() {
|
||||
# Resolve newest prerelease=true tag; prefer jq, fallback to sed/grep (no awk)
|
||||
local json tag
|
||||
json="$(curl -fsSL "https://api.github.com/repos/2dust/v2rayN/releases?per_page=20")" || return 1
|
||||
|
||||
# 1) Use jq if present
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
tag="$(printf '%s' "$json" \
|
||||
| jq -r '[.[] | select(.prerelease==true)][0].tag_name' 2>/dev/null \
|
||||
| sed 's/^v//')" || true
|
||||
fi
|
||||
|
||||
# 2) Fallback to sed/grep only
|
||||
if [[ -z "${tag:-}" || "${tag:-}" == "null" ]]; then
|
||||
tag="$(printf '%s' "$json" \
|
||||
| tr '\n' ' ' \
|
||||
| sed 's/},[[:space:]]*{/\n/g' \
|
||||
| grep -m1 -E '"prerelease"[[:space:]]*:[[:space:]]*true' \
|
||||
| grep -Eo '"tag_name"[[:space:]]*:[[:space:]]*"v?[^"]+"' \
|
||||
| head -n1 \
|
||||
| sed -E 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v?([^"]+)".*/\1/')" || true
|
||||
fi
|
||||
|
||||
[[ -n "${tag:-}" && "${tag:-}" != "null" ]] || return 1
|
||||
printf '%s\n' "$tag"
|
||||
curl -fsSL "https://api.github.com/repos/2dust/v2rayN/releases?per_page=20" \
|
||||
| jq -re 'first(.[] | select(.prerelease == true) | .tag_name)' \
|
||||
| sed 's/^v//'
|
||||
}
|
||||
|
||||
git_try_checkout() {
|
||||
|
|
@ -196,11 +146,7 @@ git_try_checkout() {
|
|||
local want="$1" ref=""
|
||||
if git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
git fetch --tags --force --prune --depth=1 || true
|
||||
if git rev-parse "refs/tags/v${want}" >/dev/null 2>&1; then
|
||||
ref="v${want}"
|
||||
elif git rev-parse "refs/tags/${want}" >/dev/null 2>&1; then
|
||||
ref="${want}"
|
||||
elif git rev-parse --verify "${want}" >/dev/null 2>&1; then
|
||||
if git rev-parse "refs/tags/${want}" >/dev/null 2>&1; then
|
||||
ref="${want}"
|
||||
fi
|
||||
if [[ -n "$ref" ]]; then
|
||||
|
|
@ -216,88 +162,56 @@ git_try_checkout() {
|
|||
return 1
|
||||
}
|
||||
|
||||
apply_channel_or_keep() {
|
||||
local ch="$1" tag
|
||||
|
||||
if [[ "$ch" == "keep" ]]; then
|
||||
echo "[*] Keep current repository state (no checkout)."
|
||||
VERSION="$(git describe --tags --abbrev=0 2>/dev/null || echo '0.0.0+git')"
|
||||
VERSION="${VERSION#v}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "[*] Resolving ${ch} tag from GitHub releases..."
|
||||
if [[ "$ch" == "prerelease" ]]; then
|
||||
tag="$(get_latest_tag_prerelease || true)"
|
||||
else
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
|
||||
[[ -n "$tag" ]] || { echo "Failed to resolve latest tag for channel '${ch}'."; exit 1; }
|
||||
echo "[*] Latest tag for '${ch}': ${tag}"
|
||||
git_try_checkout "$tag" || { echo "Failed to checkout '${tag}'."; exit 1; }
|
||||
VERSION="${tag#v}"
|
||||
}
|
||||
|
||||
if git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
if [[ -n "${VERSION_ARG:-}" ]]; then
|
||||
echo "[*] Trying to switch v2rayN repo to version: ${VERSION_ARG}"
|
||||
if git_try_checkout "${VERSION_ARG#v}"; then
|
||||
VERSION="${VERSION_ARG#v}"
|
||||
clean_ver="${VERSION_ARG#v}"
|
||||
if git_try_checkout "$clean_ver"; then
|
||||
VERSION="$clean_ver"
|
||||
else
|
||||
echo "[WARN] Tag '${VERSION_ARG}' not found."
|
||||
ch="$(choose_channel)"
|
||||
if [[ "$ch" == "keep" ]]; then
|
||||
echo "[*] Keep current repository state (no checkout)."
|
||||
if git describe --tags --abbrev=0 >/dev/null 2>&1; then
|
||||
VERSION="$(git describe --tags --abbrev=0)"
|
||||
else
|
||||
VERSION="0.0.0+git"
|
||||
fi
|
||||
VERSION="${VERSION#v}"
|
||||
else
|
||||
echo "[*] Resolving ${ch} tag from GitHub releases..."
|
||||
tag=""
|
||||
if [[ "$ch" == "prerelease" ]]; then
|
||||
tag="$(get_latest_tag_prerelease || true)"
|
||||
if [[ -z "$tag" ]]; then
|
||||
echo "[WARN] Failed to resolve prerelease tag, falling back to latest."
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
else
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
[[ -n "$tag" ]] || { echo "[ERROR] Failed to resolve latest tag for channel '${ch}'."; exit 1; }
|
||||
echo "[*] Latest tag for '${ch}': ${tag}"
|
||||
git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; }
|
||||
VERSION="${tag#v}"
|
||||
fi
|
||||
apply_channel_or_keep "$ch"
|
||||
fi
|
||||
else
|
||||
ch="$(choose_channel)"
|
||||
if [[ "$ch" == "keep" ]]; then
|
||||
echo "[*] Keep current repository state (no checkout)."
|
||||
if git describe --tags --abbrev=0 >/dev/null 2>&1; then
|
||||
VERSION="$(git describe --tags --abbrev=0)"
|
||||
else
|
||||
VERSION="0.0.0+git"
|
||||
fi
|
||||
VERSION="${VERSION#v}"
|
||||
else
|
||||
echo "[*] Resolving ${ch} tag from GitHub releases..."
|
||||
tag=""
|
||||
if [[ "$ch" == "prerelease" ]]; then
|
||||
tag="$(get_latest_tag_prerelease || true)"
|
||||
if [[ -z "$tag" ]]; then
|
||||
echo "[WARN] Failed to resolve prerelease tag, falling back to latest."
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
else
|
||||
tag="$(get_latest_tag_latest || true)"
|
||||
fi
|
||||
[[ -n "$tag" ]] || { echo "[ERROR] Failed to resolve latest tag for channel '${ch}'."; exit 1; }
|
||||
echo "[*] Latest tag for '${ch}': ${tag}"
|
||||
git_try_checkout "$tag" || { echo "[ERROR] Failed to checkout '${tag}'."; exit 1; }
|
||||
VERSION="${tag#v}"
|
||||
fi
|
||||
apply_channel_or_keep "$ch"
|
||||
fi
|
||||
else
|
||||
echo "[WARN] Current directory is not a git repo; cannot checkout version. Proceeding on current tree."
|
||||
VERSION="${VERSION_ARG:-}"
|
||||
if [[ -z "$VERSION" ]]; then
|
||||
if git describe --tags --abbrev=0 >/dev/null 2>&1; then
|
||||
VERSION="$(git describe --tags --abbrev=0)"
|
||||
else
|
||||
VERSION="0.0.0+git"
|
||||
fi
|
||||
fi
|
||||
VERSION="${VERSION#v}"
|
||||
echo "Current directory is not a git repo; proceeding on current tree."
|
||||
VERSION="${VERSION_ARG:-0.0.0}"
|
||||
fi
|
||||
|
||||
VERSION="${VERSION#v}"
|
||||
echo "[*] GUI version resolved as: ${VERSION}"
|
||||
|
||||
# ===== Helpers for core/rules download (use RID_DIR for arch sync) =====================
|
||||
# Helpers for core
|
||||
download_xray() {
|
||||
# Download Xray core and install to outdir/xray
|
||||
# Download Xray core
|
||||
local outdir="$1" ver="${XRAY_VER:-}" url tmp zipname="xray.zip"
|
||||
mkdir -p "$outdir"
|
||||
if [[ -n "${XRAY_VER:-}" ]]; then ver="${XRAY_VER}"; fi
|
||||
if [[ -z "$ver" ]]; then
|
||||
ver="$(curl -fsSL https://api.github.com/repos/XTLS/Xray-core/releases/latest \
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
|
|
@ -316,10 +230,9 @@ download_xray() {
|
|||
}
|
||||
|
||||
download_singbox() {
|
||||
# Download sing-box core and install to outdir/sing-box
|
||||
# Download sing-box
|
||||
local outdir="$1" ver="${SING_VER:-}" url tmp tarname="singbox.tar.gz" bin
|
||||
mkdir -p "$outdir"
|
||||
if [[ -n "${SING_VER:-}" ]]; then ver="${SING_VER}"; fi
|
||||
if [[ -z "$ver" ]]; then
|
||||
ver="$(curl -fsSL https://api.github.com/repos/SagerNet/sing-box/releases/latest \
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
|
|
@ -339,7 +252,7 @@ download_singbox() {
|
|||
install -Dm755 "$bin" "$outdir/sing-box"
|
||||
}
|
||||
|
||||
# Move geo files to a unified path: outroot/bin
|
||||
# Move geo files to outroot/bin
|
||||
unify_geo_layout() {
|
||||
local outroot="$1"
|
||||
mkdir -p "$outroot/bin"
|
||||
|
|
@ -351,18 +264,13 @@ unify_geo_layout() {
|
|||
"geoip.metadb" \
|
||||
)
|
||||
for n in "${names[@]}"; do
|
||||
# If file exists under bin/xray/, move it up to bin/
|
||||
if [[ -f "$outroot/bin/xray/$n" ]]; then
|
||||
mv -f "$outroot/bin/xray/$n" "$outroot/bin/$n"
|
||||
fi
|
||||
# If file already in bin/, leave it as-is
|
||||
if [[ -f "$outroot/bin/$n" ]]; then
|
||||
:
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Download geo/rule assets; then unify to bin/
|
||||
# Download geo/rule assets
|
||||
download_geo_assets() {
|
||||
local outroot="$1"
|
||||
local bin_dir="$outroot/bin"
|
||||
|
|
@ -396,7 +304,7 @@ download_geo_assets() {
|
|||
"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-geosite/$f" || true
|
||||
done
|
||||
|
||||
# Unify to bin/
|
||||
# Unify to bin
|
||||
unify_geo_layout "$outroot"
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +335,7 @@ download_v2rayn_bundle() {
|
|||
|
||||
local nested_dir
|
||||
nested_dir="$(find "$outroot" -maxdepth 1 -type d -name 'v2rayN-linux-*' | head -n1 || true)"
|
||||
if [[ -n "${nested_dir:-}" && -d "$nested_dir/bin" ]]; then
|
||||
if [[ -n "$nested_dir" && -d "$nested_dir/bin" ]]; then
|
||||
mkdir -p "$outroot/bin"
|
||||
rsync -a "$nested_dir/bin/" "$outroot/bin/"
|
||||
rm -rf "$nested_dir"
|
||||
|
|
@ -451,7 +359,7 @@ build_for_arch() {
|
|||
case "$short" in
|
||||
x64) rid="linux-x64"; rpm_target="x86_64"; archdir="x86_64" ;;
|
||||
arm64) rid="linux-arm64"; rpm_target="aarch64"; archdir="aarch64" ;;
|
||||
*) echo "[ERROR] Unknown arch '$short' (use x64|arm64)"; return 1;;
|
||||
*) echo "Unknown arch '$short' (use x64|arm64)"; return 1;;
|
||||
esac
|
||||
|
||||
echo "[*] Building for target: $short (RID=$rid, RPM --target $rpm_target)"
|
||||
|
|
@ -464,8 +372,7 @@ build_for_arch() {
|
|||
dotnet publish "$PROJECT" \
|
||||
-c Release -r "$rid" \
|
||||
-p:PublishSingleFile=false \
|
||||
-p:SelfContained=true \
|
||||
-p:IncludeNativeLibrariesForSelfExtract=true
|
||||
-p:SelfContained=true
|
||||
|
||||
# Per-arch variables (scoped)
|
||||
local RID_DIR="$rid"
|
||||
|
|
@ -502,28 +409,28 @@ build_for_arch() {
|
|||
mkdir -p "$WORKDIR/$PKGROOT/bin/xray" "$WORKDIR/$PKGROOT/bin/sing_box"
|
||||
|
||||
# Bundle / cores per-arch
|
||||
fetch_separate_cores_and_rules() {
|
||||
local outroot="$1"
|
||||
|
||||
if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then
|
||||
download_xray "$outroot/bin/xray" || echo "[!] xray download failed (skipped)"
|
||||
fi
|
||||
if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then
|
||||
download_singbox "$outroot/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||
fi
|
||||
download_geo_assets "$outroot" || echo "[!] Geo rules download failed (skipped)"
|
||||
}
|
||||
|
||||
if [[ "$FORCE_NETCORE" -eq 0 ]]; then
|
||||
if download_v2rayn_bundle "$WORKDIR/$PKGROOT"; then
|
||||
echo "[*] Using v2rayN bundle archive."
|
||||
else
|
||||
echo "[*] Bundle failed, fallback to separate core + rules."
|
||||
if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then
|
||||
download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)"
|
||||
fi
|
||||
if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then
|
||||
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||
fi
|
||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||
fetch_separate_cores_and_rules "$WORKDIR/$PKGROOT"
|
||||
fi
|
||||
else
|
||||
echo "[*] --netcore specified: use separate core + rules."
|
||||
if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then
|
||||
download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)"
|
||||
fi
|
||||
if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then
|
||||
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||
fi
|
||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||
fetch_separate_cores_and_rules "$WORKDIR/$PKGROOT"
|
||||
fi
|
||||
|
||||
# Tarball
|
||||
|
|
@ -577,12 +484,6 @@ https://github.com/2dust/v2rayN
|
|||
install -dm0755 %{buildroot}/opt/v2rayN
|
||||
cp -a * %{buildroot}/opt/v2rayN/
|
||||
|
||||
install -dm0755 %{buildroot}%{_sysconfdir}/sudoers.d
|
||||
cat > %{buildroot}%{_sysconfdir}/sudoers.d/v2rayn-mihomo-deny << 'EOF'
|
||||
ALL ALL=(ALL) !/home/*/.local/share/v2rayN/bin/mihomo/mihomo
|
||||
EOF
|
||||
chmod 0440 %{buildroot}%{_sysconfdir}/sudoers.d/v2rayn-mihomo-deny
|
||||
|
||||
# Launcher (prefer native ELF first, then DLL fallback)
|
||||
install -dm0755 %{buildroot}%{_bindir}
|
||||
cat > %{buildroot}%{_bindir}/v2rayn << 'EOF'
|
||||
|
|
@ -636,47 +537,13 @@ fi
|
|||
/opt/v2rayN
|
||||
%{_datadir}/applications/v2rayn.desktop
|
||||
%{_datadir}/icons/hicolor/256x256/apps/v2rayn.png
|
||||
%config(noreplace) /etc/sudoers.d/v2rayn-mihomo-deny
|
||||
SPEC
|
||||
|
||||
# Autostart injection (inside %install) and %files entry
|
||||
if [[ "$AUTOSTART" -eq 1 ]]; then
|
||||
awk '
|
||||
BEGIN{ins=0}
|
||||
/^%post$/ && !ins {
|
||||
print "# --- Autostart (.desktop) ---"
|
||||
print "install -dm0755 %{buildroot}/etc/xdg/autostart"
|
||||
print "cat > %{buildroot}/etc/xdg/autostart/v2rayn.desktop << '\''EOF'\''"
|
||||
print "[Desktop Entry]"
|
||||
print "Type=Application"
|
||||
print "Name=v2rayN (Autostart)"
|
||||
print "Exec=v2rayn"
|
||||
print "X-GNOME-Autostart-enabled=true"
|
||||
print "NoDisplay=false"
|
||||
print "EOF"
|
||||
ins=1
|
||||
}
|
||||
{print}
|
||||
' "$SPECFILE" > "${SPECFILE}.tmp" && mv "${SPECFILE}.tmp" "$SPECFILE"
|
||||
|
||||
awk '
|
||||
BEGIN{infiles=0; done=0}
|
||||
/^%files$/ {infiles=1}
|
||||
infiles && done==0 && $0 ~ /%{_datadir}\/icons\/hicolor\/256x256\/apps\/v2rayn\.png/ {
|
||||
print
|
||||
print "%config(noreplace) /etc/xdg/autostart/v2rayn.desktop"
|
||||
done=1
|
||||
next
|
||||
}
|
||||
{print}
|
||||
' "$SPECFILE" > "${SPECFILE}.tmp" && mv "${SPECFILE}.tmp" "$SPECFILE"
|
||||
fi
|
||||
|
||||
# Replace placeholders
|
||||
sed -i "s/__VERSION__/${VERSION}/g" "$SPECFILE"
|
||||
sed -i "s/__PKGROOT__/${PKGROOT}/g" "$SPECFILE"
|
||||
|
||||
# Build RPM for this arch (force rpm --target to match compile arch)
|
||||
# Build RPM for this arch
|
||||
rpmbuild -ba "$SPECFILE" --target "$rpm_target"
|
||||
|
||||
echo "Build done for $short. RPM at:"
|
||||
|
|
@ -690,33 +557,18 @@ SPEC
|
|||
|
||||
# ===== Arch selection and build orchestration =========================================
|
||||
case "${ARCH_OVERRIDE:-}" in
|
||||
"")
|
||||
# No --arch: use host architecture
|
||||
if [[ "$host_arch" == "aarch64" ]]; then
|
||||
build_for_arch arm64
|
||||
else
|
||||
build_for_arch x64
|
||||
fi
|
||||
;;
|
||||
x64|amd64)
|
||||
build_for_arch x64
|
||||
;;
|
||||
arm64|aarch64)
|
||||
build_for_arch arm64
|
||||
;;
|
||||
all)
|
||||
BUILT_ALL=1
|
||||
# Build x64 and arm64 separately; each package contains its own arch-only binaries.
|
||||
build_for_arch x64
|
||||
build_for_arch arm64
|
||||
;;
|
||||
*)
|
||||
echo "[ERROR] Unknown --arch '${ARCH_OVERRIDE}'. Use x64|arm64|all."
|
||||
exit 1
|
||||
;;
|
||||
all) targets=(x64 arm64); BUILT_ALL=1 ;;
|
||||
x64|amd64) targets=(x64) ;;
|
||||
arm64|aarch64) targets=(arm64) ;;
|
||||
"") targets=($([[ "$host_arch" == "aarch64" ]] && echo arm64 || echo x64)) ;;
|
||||
*) echo "Unknown --arch '${ARCH_OVERRIDE}'. Use x64|arm64|all."; exit 1 ;;
|
||||
esac
|
||||
|
||||
# ===== Final summary if building both arches ==========================================
|
||||
for arch in "${targets[@]}"; do
|
||||
build_for_arch "$arch"
|
||||
done
|
||||
|
||||
# Print Both arches information
|
||||
if [[ "$BUILT_ALL" -eq 1 ]]; then
|
||||
echo ""
|
||||
echo "================ Build Summary (both architectures) ================"
|
||||
|
|
@ -725,7 +577,7 @@ if [[ "$BUILT_ALL" -eq 1 ]]; then
|
|||
echo "$rp"
|
||||
done
|
||||
else
|
||||
echo "[WARN] No RPMs detected in summary (check build logs above)."
|
||||
echo "No RPMs detected in summary (check build logs above)."
|
||||
fi
|
||||
echo "==================================================================="
|
||||
echo "===================================================================="
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.18.0</Version>
|
||||
<Version>7.19.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.4.0" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.11" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.11" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.11" />
|
||||
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.4.1" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.12" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.12" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" />
|
||||
<PackageVersion Include="ReactiveUI.Avalonia" Version="11.3.8" />
|
||||
<PackageVersion Include="CliWrap" Version="3.10.0" />
|
||||
<PackageVersion Include="Downloader" Version="4.0.3" />
|
||||
<PackageVersion Include="Downloader" Version="4.1.1" />
|
||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.4.1" />
|
||||
<PackageVersion Include="MaterialDesignThemes" Version="5.3.0" />
|
||||
<PackageVersion Include="MessageBox.Avalonia" Version="3.3.1.1" />
|
||||
|
|
@ -19,9 +19,9 @@
|
|||
<PackageVersion Include="ReactiveUI" Version="22.3.1" />
|
||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||
<PackageVersion Include="ReactiveUI.WPF" Version="22.3.1" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.3.7.2" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.3.7.3" />
|
||||
<PackageVersion Include="Semi.Avalonia.AvaloniaEdit" Version="11.2.0.1" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.2" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.3.7.3" />
|
||||
<PackageVersion Include="NLog" Version="6.1.0" />
|
||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageVersion Include="TaskScheduler" Version="2.12.2" />
|
||||
|
|
|
|||
|
|
@ -629,12 +629,7 @@ public class Utils
|
|||
{
|
||||
try
|
||||
{
|
||||
List<IPEndPoint> lstIpEndPoints = new();
|
||||
List<TcpConnectionInformation> lstTcpConns = new();
|
||||
|
||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||
var (lstIpEndPoints, lstTcpConns) = GetActiveNetworkInfo();
|
||||
|
||||
if (lstIpEndPoints?.FindIndex(it => it.Port == port) >= 0)
|
||||
{
|
||||
|
|
@ -676,6 +671,27 @@ public class Utils
|
|||
return 59090;
|
||||
}
|
||||
|
||||
public static (List<IPEndPoint> endpoints, List<TcpConnectionInformation> connections) GetActiveNetworkInfo()
|
||||
{
|
||||
var endpoints = new List<IPEndPoint>();
|
||||
var connections = new List<TcpConnectionInformation>();
|
||||
|
||||
try
|
||||
{
|
||||
var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
|
||||
|
||||
endpoints.AddRange(ipGlobalProperties.GetActiveTcpListeners());
|
||||
endpoints.AddRange(ipGlobalProperties.GetActiveUdpListeners());
|
||||
connections.AddRange(ipGlobalProperties.GetActiveTcpConnections());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
return (endpoints, connections);
|
||||
}
|
||||
|
||||
#endregion Speed Test
|
||||
|
||||
#region Miscellaneous
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ public enum EConfigType
|
|||
WireGuard = 9,
|
||||
HTTP = 10,
|
||||
Anytls = 11,
|
||||
Naive = 12,
|
||||
PolicyGroup = 101,
|
||||
ProxyChain = 102,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,10 @@ public class Global
|
|||
|
||||
public const string Hysteria2ProtocolShare = "hy2://";
|
||||
|
||||
public const string NaiveHttpsProtocolShare = "naive+https://";
|
||||
|
||||
public const string NaiveQuicProtocolShare = "naive+quic://";
|
||||
|
||||
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
|
||||
{
|
||||
{ EConfigType.VMess, "vmess://" },
|
||||
|
|
@ -186,7 +190,8 @@ public class Global
|
|||
{ EConfigType.Hysteria2, "hysteria2://" },
|
||||
{ EConfigType.TUIC, "tuic://" },
|
||||
{ EConfigType.WireGuard, "wireguard://" },
|
||||
{ EConfigType.Anytls, "anytls://" }
|
||||
{ EConfigType.Anytls, "anytls://" },
|
||||
{ EConfigType.Naive, "naive://" }
|
||||
};
|
||||
|
||||
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
||||
|
|
@ -200,7 +205,8 @@ public class Global
|
|||
{ EConfigType.Hysteria2, "hysteria2" },
|
||||
{ EConfigType.TUIC, "tuic" },
|
||||
{ EConfigType.WireGuard, "wireguard" },
|
||||
{ EConfigType.Anytls, "anytls" }
|
||||
{ EConfigType.Anytls, "anytls" },
|
||||
{ EConfigType.Naive, "naive" }
|
||||
};
|
||||
|
||||
public static readonly List<string> VmessSecurities =
|
||||
|
|
@ -325,6 +331,7 @@ public class Global
|
|||
EConfigType.Hysteria2,
|
||||
EConfigType.TUIC,
|
||||
EConfigType.Anytls,
|
||||
EConfigType.Naive,
|
||||
EConfigType.WireGuard,
|
||||
EConfigType.SOCKS,
|
||||
EConfigType.HTTP,
|
||||
|
|
@ -541,6 +548,14 @@ public class Global
|
|||
"bbr"
|
||||
];
|
||||
|
||||
public static readonly List<string> NaiveCongestionControls =
|
||||
[
|
||||
"bbr",
|
||||
"bbr2",
|
||||
"cubic",
|
||||
"reno"
|
||||
];
|
||||
|
||||
public static readonly List<string> allowSelectType =
|
||||
[
|
||||
"selector",
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ public static class ConfigHandler
|
|||
item.Address = profileItem.Address;
|
||||
item.Port = profileItem.Port;
|
||||
|
||||
item.Username = profileItem.Username;
|
||||
item.Password = profileItem.Password;
|
||||
|
||||
item.Network = profileItem.Network;
|
||||
|
|
@ -270,6 +271,7 @@ public static class ConfigHandler
|
|||
EConfigType.TUIC => await AddTuicServer(config, item),
|
||||
EConfigType.WireGuard => await AddWireguardServer(config, item),
|
||||
EConfigType.Anytls => await AddAnytlsServer(config, item),
|
||||
EConfigType.Naive => await AddNaiveServer(config, item),
|
||||
_ => -1,
|
||||
};
|
||||
return ret;
|
||||
|
|
@ -807,7 +809,7 @@ public static class ConfigHandler
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add or edit a Anytls server
|
||||
/// Add or edit an Anytls server
|
||||
/// Validates and processes Anytls-specific settings
|
||||
/// </summary>
|
||||
/// <param name="config">Current configuration</param>
|
||||
|
|
@ -834,6 +836,35 @@ public static class ConfigHandler
|
|||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add or edit a Naive server
|
||||
/// Validates and processes Naive-specific settings
|
||||
/// </summary>
|
||||
/// <param name="config">Current configuration</param>
|
||||
/// <param name="profileItem">Naive profile to add</param>
|
||||
/// <param name="toFile">Whether to save to file</param>
|
||||
/// <returns>0 if successful, -1 if failed</returns>
|
||||
public static async Task<int> AddNaiveServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||
{
|
||||
profileItem.ConfigType = EConfigType.Naive;
|
||||
profileItem.CoreType = ECoreType.sing_box;
|
||||
|
||||
profileItem.Address = profileItem.Address.TrimEx();
|
||||
profileItem.Username = profileItem.Username.TrimEx();
|
||||
profileItem.Password = profileItem.Password.TrimEx();
|
||||
profileItem.Network = profileItem.Network == "quic" ? "quic" : string.Empty;
|
||||
if (profileItem.StreamSecurity.IsNullOrEmpty())
|
||||
{
|
||||
profileItem.StreamSecurity = Global.StreamSecurity;
|
||||
}
|
||||
if (profileItem.Password.IsNullOrEmpty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
await AddServerCommon(config, profileItem, toFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort the server list by the specified column
|
||||
/// Updates the sort order in the profile extension data
|
||||
|
|
@ -1080,7 +1111,8 @@ public static class ConfigHandler
|
|||
|
||||
if (toFile)
|
||||
{
|
||||
profileItem.SetProtocolExtra();
|
||||
//profileItem.SetProtocolExtra();
|
||||
profileItem.SetProtocolExtra(profileItem.GetProtocolExtra());
|
||||
await SQLiteHelper.Instance.ReplaceAsync(profileItem);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1108,6 +1140,7 @@ public static class ConfigHandler
|
|||
&& AreEqual(o.Address, n.Address)
|
||||
&& o.Port == n.Port
|
||||
&& AreEqual(o.Password, n.Password)
|
||||
&& AreEqual(o.Username, n.Username)
|
||||
&& AreEqual(oProtocolExtra.VlessEncryption, nProtocolExtra.VlessEncryption)
|
||||
&& AreEqual(oProtocolExtra.SsMethod, nProtocolExtra.SsMethod)
|
||||
&& AreEqual(oProtocolExtra.VmessSecurity, nProtocolExtra.VmessSecurity)
|
||||
|
|
@ -1235,31 +1268,63 @@ public static class ConfigHandler
|
|||
/// <returns>A SOCKS profile item or null if not needed</returns>
|
||||
public static ProfileItem? GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
|
||||
{
|
||||
if (node.ConfigType != EConfigType.Custom || !(node.PreSocksPort > 0))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ProfileItem? itemSocks = null;
|
||||
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
|
||||
var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||
itemSocks = new ProfileItem()
|
||||
{
|
||||
itemSocks = new ProfileItem()
|
||||
{
|
||||
CoreType = ECoreType.sing_box,
|
||||
ConfigType = EConfigType.SOCKS,
|
||||
Address = Global.Loopback,
|
||||
Port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||
};
|
||||
}
|
||||
else if (node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0)
|
||||
{
|
||||
var preCoreType = AppManager.Instance.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||
itemSocks = new ProfileItem()
|
||||
{
|
||||
CoreType = preCoreType,
|
||||
ConfigType = EConfigType.SOCKS,
|
||||
Address = Global.Loopback,
|
||||
Port = node.PreSocksPort.Value,
|
||||
};
|
||||
}
|
||||
CoreType = preCoreType,
|
||||
ConfigType = EConfigType.SOCKS,
|
||||
Address = Global.Loopback,
|
||||
Port = node.PreSocksPort.Value,
|
||||
};
|
||||
return itemSocks;
|
||||
}
|
||||
|
||||
public static CoreConfigContext? GetPreSocksCoreConfigContext(CoreConfigContext nodeContext)
|
||||
{
|
||||
var config = nodeContext.AppConfig;
|
||||
var node = nodeContext.Node;
|
||||
var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
|
||||
|
||||
var preSocksItem = GetPreSocksItem(config, node, coreType);
|
||||
if (preSocksItem != null)
|
||||
{
|
||||
return nodeContext with { Node = preSocksItem, };
|
||||
}
|
||||
|
||||
if ((!nodeContext.IsTunEnabled)
|
||||
|| coreType != ECoreType.Xray
|
||||
|| node.ConfigType == EConfigType.Custom)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var tunProtectSsPort = Utils.GetFreePort();
|
||||
var proxyRelaySsPort = Utils.GetFreePort();
|
||||
var preItem = new ProfileItem()
|
||||
{
|
||||
CoreType = ECoreType.sing_box,
|
||||
ConfigType = EConfigType.Shadowsocks,
|
||||
Address = Global.Loopback,
|
||||
Port = proxyRelaySsPort,
|
||||
Password = Global.None,
|
||||
};
|
||||
preItem.SetProtocolExtra(preItem.GetProtocolExtra() with
|
||||
{
|
||||
SsMethod = Global.None,
|
||||
});
|
||||
var preContext = nodeContext with
|
||||
{
|
||||
Node = preItem,
|
||||
TunProtectSsPort = tunProtectSsPort,
|
||||
ProxyRelaySsPort = proxyRelaySsPort,
|
||||
};
|
||||
return preContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove servers with invalid test results (timeout)
|
||||
/// Useful for cleaning up subscription lists
|
||||
|
|
@ -1359,6 +1424,7 @@ public static class ConfigHandler
|
|||
EConfigType.TUIC => await AddTuicServer(config, profileItem, false),
|
||||
EConfigType.WireGuard => await AddWireguardServer(config, profileItem, false),
|
||||
EConfigType.Anytls => await AddAnytlsServer(config, profileItem, false),
|
||||
EConfigType.Naive => await AddNaiveServer(config, profileItem, false),
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,8 @@ public static class CoreConfigHandler
|
|||
IsTunEnabled = config.TunModeItem.EnableTun,
|
||||
SimpleDnsItem = config.SimpleDNSItem,
|
||||
ProtectDomainList = [],
|
||||
ProtectSocksPort = 0,
|
||||
TunProtectSsPort = 0,
|
||||
ProxyRelaySsPort = 0,
|
||||
RawDnsItem = await AppManager.Instance.GetDNSItem(coreType),
|
||||
RoutingItem = await ConfigHandler.GetDefaultRouting(config),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public class FmtHandler
|
|||
EConfigType.TUIC => TuicFmt.ToUri(item),
|
||||
EConfigType.WireGuard => WireguardFmt.ToUri(item),
|
||||
EConfigType.Anytls => AnytlsFmt.ToUri(item),
|
||||
EConfigType.Naive => NaiveFmt.ToUri(item),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
|
|
@ -80,6 +81,12 @@ public class FmtHandler
|
|||
{
|
||||
return AnytlsFmt.Resolve(str, out msg);
|
||||
}
|
||||
else if (str.StartsWith(Global.ProtocolShares[EConfigType.Naive])
|
||||
|| str.StartsWith(Global.NaiveHttpsProtocolShare)
|
||||
|| str.StartsWith(Global.NaiveQuicProtocolShare))
|
||||
{
|
||||
return NaiveFmt.Resolve(str, out msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = ResUI.NonvmessOrssProtocol;
|
||||
|
|
|
|||
85
v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs
Normal file
85
v2rayN/ServiceLib/Handler/Fmt/NaiveFmt.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
namespace ServiceLib.Handler.Fmt;
|
||||
|
||||
public class NaiveFmt : BaseFmt
|
||||
{
|
||||
public static ProfileItem? Resolve(string str, out string msg)
|
||||
{
|
||||
msg = ResUI.ConfigurationFormatIncorrect;
|
||||
|
||||
var parsedUrl = Utils.TryUri(str);
|
||||
if (parsedUrl == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ProfileItem item = new()
|
||||
{
|
||||
ConfigType = EConfigType.Naive,
|
||||
Remarks = parsedUrl.GetComponents(UriComponents.Fragment, UriFormat.Unescaped),
|
||||
Address = parsedUrl.IdnHost,
|
||||
Port = parsedUrl.Port,
|
||||
};
|
||||
if (parsedUrl.Scheme.Contains("quic"))
|
||||
{
|
||||
item.Network = "quic";
|
||||
}
|
||||
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
||||
if (rawUserInfo.Contains(':'))
|
||||
{
|
||||
var split = rawUserInfo.Split(':', 2);
|
||||
item.Username = split[0];
|
||||
item.Password = split[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Password = rawUserInfo;
|
||||
}
|
||||
|
||||
var query = Utils.ParseQueryString(parsedUrl.Query);
|
||||
ResolveUriQuery(query, ref item);
|
||||
var insecureConcurrency = int.TryParse(GetQueryValue(query, "insecure-concurrency"), out var ic) ? ic : 0;
|
||||
if (insecureConcurrency > 0)
|
||||
{
|
||||
item.SetProtocolExtra(item.GetProtocolExtra() with
|
||||
{
|
||||
InsecureConcurrency = insecureConcurrency,
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string? ToUri(ProfileItem? item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var remark = string.Empty;
|
||||
if (item.Remarks.IsNotEmpty())
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||
}
|
||||
var userInfo = item.Username.IsNotEmpty() ? $"{Utils.UrlEncode(item.Username)}:{Utils.UrlEncode(item.Password)}" : Utils.UrlEncode(item.Password);
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
ToUriQuery(item, Global.None, ref dicQuery);
|
||||
if (item.GetProtocolExtra().InsecureConcurrency > 0)
|
||||
{
|
||||
dicQuery.Add("insecure-concurrency", item.GetProtocolExtra()?.InsecureConcurrency.ToString());
|
||||
}
|
||||
|
||||
var query = dicQuery.Count > 0
|
||||
? ("?" + string.Join("&", dicQuery.Select(x => x.Key + "=" + x.Value).ToArray()))
|
||||
: string.Empty;
|
||||
var url = $"{userInfo}@{GetIpv6(item.Address)}:{item.Port}";
|
||||
|
||||
if (item.Network == "quic")
|
||||
{
|
||||
return $"{Global.NaiveQuicProtocolShare}{url}{query}{remark}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{Global.NaiveHttpsProtocolShare}{url}{query}{remark}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,10 @@ public class TuicFmt : BaseFmt
|
|||
|
||||
var query = Utils.ParseQueryString(url.Query);
|
||||
ResolveUriQuery(query, ref item);
|
||||
item.HeaderType = GetQueryValue(query, "congestion_control");
|
||||
item.SetProtocolExtra(item.GetProtocolExtra() with
|
||||
{
|
||||
CongestionControl = GetQueryValue(query, "congestion_control")
|
||||
});
|
||||
|
||||
return item;
|
||||
}
|
||||
|
|
@ -51,7 +54,10 @@ public class TuicFmt : BaseFmt
|
|||
var dicQuery = new Dictionary<string, string>();
|
||||
ToUriQueryLite(item, ref dicQuery);
|
||||
|
||||
dicQuery.Add("congestion_control", item.HeaderType);
|
||||
if (!item.GetProtocolExtra().CongestionControl.IsNullOrEmpty())
|
||||
{
|
||||
dicQuery.Add("congestion_control", item.GetProtocolExtra().CongestionControl);
|
||||
}
|
||||
|
||||
return ToUri(EConfigType.TUIC, item.Address, item.Port, $"{item.Username ?? ""}:{item.Password}", dicQuery, remark);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ public class DownloaderHelper
|
|||
|
||||
var downloadOpt = new DownloadConfiguration()
|
||||
{
|
||||
Timeout = timeout * 1000,
|
||||
BlockTimeout = timeout * 1000,
|
||||
MaxTryAgainOnFailure = 2,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Headers = headers,
|
||||
UserAgent = userAgent,
|
||||
Timeout = timeout * 1000,
|
||||
ConnectTimeout = timeout * 1000,
|
||||
Proxy = webProxy
|
||||
}
|
||||
};
|
||||
|
|
@ -62,11 +62,11 @@ public class DownloaderHelper
|
|||
|
||||
var downloadOpt = new DownloadConfiguration()
|
||||
{
|
||||
Timeout = timeout * 1000,
|
||||
BlockTimeout = timeout * 1000,
|
||||
MaxTryAgainOnFailure = 2,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Timeout= timeout * 1000,
|
||||
ConnectTimeout= timeout * 1000,
|
||||
Proxy = webProxy
|
||||
}
|
||||
};
|
||||
|
|
@ -139,11 +139,11 @@ public class DownloaderHelper
|
|||
|
||||
var downloadOpt = new DownloadConfiguration()
|
||||
{
|
||||
Timeout = timeout * 1000,
|
||||
BlockTimeout = timeout * 1000,
|
||||
MaxTryAgainOnFailure = 2,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Timeout= timeout * 1000,
|
||||
ConnectTimeout= timeout * 1000,
|
||||
Proxy = webProxy
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -243,6 +243,11 @@ public class ActionPrecheckManager
|
|||
return string.Format(ResUI.CoreNotSupportNetwork, nameof(ECoreType.sing_box), net);
|
||||
}
|
||||
|
||||
if (configType == EConfigType.Naive && net == "quic")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// sing-box does not support non-tcp transports for protocols other than vmess/trojan/vless/shadowsocks
|
||||
if (!SingboxTransportSupportedProtocols.Contains(configType) && net != nameof(ETransport.tcp))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -281,12 +281,11 @@ public sealed class AppManager
|
|||
return await SQLiteHelper.Instance.TableAsync<FullConfigTemplateItem>().FirstOrDefaultAsync(it => it.CoreType == eCoreType);
|
||||
}
|
||||
|
||||
#pragma warning disable CS0618
|
||||
public async Task MigrateProfileExtra()
|
||||
{
|
||||
await MigrateProfileExtraGroup();
|
||||
|
||||
#pragma warning disable CS0618
|
||||
|
||||
const int pageSize = 100;
|
||||
var offset = 0;
|
||||
|
||||
|
|
@ -310,7 +309,6 @@ public sealed class AppManager
|
|||
}
|
||||
|
||||
//await ProfileGroupItemManager.Instance.ClearAll();
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
|
||||
private async Task<int> MigrateProfileExtraSub(List<ProfileItem> batch)
|
||||
|
|
@ -356,6 +354,7 @@ public sealed class AppManager
|
|||
break;
|
||||
|
||||
case EConfigType.TUIC:
|
||||
extra = extra with { CongestionControl = item.HeaderType.NullIfEmpty(), };
|
||||
item.Username = item.Id;
|
||||
item.Id = item.Security;
|
||||
item.Password = item.Security;
|
||||
|
|
@ -412,7 +411,6 @@ public sealed class AppManager
|
|||
|
||||
private async Task<bool> MigrateProfileExtraGroup()
|
||||
{
|
||||
#pragma warning disable CS0618
|
||||
var list = await SQLiteHelper.Instance.TableAsync<ProfileGroupItem>().ToListAsync();
|
||||
var groupItems = new ConcurrentDictionary<string, ProfileGroupItem>(list.Where(t => !string.IsNullOrEmpty(t.IndexId)).ToDictionary(t => t.IndexId!));
|
||||
|
||||
|
|
@ -477,8 +475,8 @@ public sealed class AppManager
|
|||
return true;
|
||||
|
||||
//await ProfileGroupItemManager.Instance.ClearAll();
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
#pragma warning restore CS0618
|
||||
|
||||
#endregion SqliteHelper
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,15 @@ public class CoreManager
|
|||
|
||||
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
|
||||
var context = await CoreConfigHandler.BuildCoreConfigContext(_config, node);
|
||||
context = context with { IsTunEnabled = _config.TunModeItem.EnableTun };
|
||||
var preContext = ConfigHandler.GetPreSocksCoreConfigContext(context);
|
||||
if (preContext is not null)
|
||||
{
|
||||
context = context with
|
||||
{
|
||||
TunProtectSsPort = preContext.TunProtectSsPort,
|
||||
ProxyRelaySsPort = preContext.ProxyRelaySsPort,
|
||||
};
|
||||
}
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(context, fileName);
|
||||
if (result.Success != true)
|
||||
{
|
||||
|
|
@ -88,7 +96,7 @@ public class CoreManager
|
|||
}
|
||||
|
||||
await CoreStart(context);
|
||||
await CoreStartPreService(context);
|
||||
await CoreStartPreService(preContext);
|
||||
if (_processService != null)
|
||||
{
|
||||
await UpdateFunc(true, $"{node.GetSummary()}");
|
||||
|
|
@ -183,30 +191,22 @@ public class CoreManager
|
|||
_processService = proc;
|
||||
}
|
||||
|
||||
private async Task CoreStartPreService(CoreConfigContext context)
|
||||
private async Task CoreStartPreService(CoreConfigContext? preContext)
|
||||
{
|
||||
var node = context.Node;
|
||||
if (_processService != null && !_processService.HasExited)
|
||||
if (_processService is { HasExited: false } && preContext != null)
|
||||
{
|
||||
var coreType = AppManager.Instance.GetCoreType(node, node.ConfigType);
|
||||
var itemSocks = ConfigHandler.GetPreSocksItem(_config, node, coreType);
|
||||
if (itemSocks != null)
|
||||
var preCoreType = preContext?.Node?.CoreType ?? ECoreType.sing_box;
|
||||
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(preContext, fileName);
|
||||
if (result.Success)
|
||||
{
|
||||
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
||||
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
|
||||
var itemSocksContext = await CoreConfigHandler.BuildCoreConfigContext(_config, itemSocks);
|
||||
itemSocksContext.ProtectDomainList.AddRangeSafe(context.ProtectDomainList);
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(itemSocksContext, fileName);
|
||||
if (result.Success)
|
||||
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
|
||||
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
||||
if (proc is null)
|
||||
{
|
||||
var coreInfo = CoreInfoManager.Instance.GetCoreInfo(preCoreType);
|
||||
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
||||
if (proc is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_processPreService = proc;
|
||||
return;
|
||||
}
|
||||
_processPreService = proc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ public class TunModeItem
|
|||
public bool StrictRoute { get; set; } = true;
|
||||
public string Stack { get; set; }
|
||||
public int Mtu { get; set; }
|
||||
public bool EnableExInbound { get; set; }
|
||||
public bool EnableIPv6Address { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,5 +16,9 @@ public record CoreConfigContext
|
|||
// TUN Compatibility
|
||||
public bool IsTunEnabled { get; init; } = false;
|
||||
public HashSet<string> ProtectDomainList { get; init; } = new();
|
||||
public int ProtectSocksPort { get; init; } = 0;
|
||||
// -> tun inbound --(if routing proxy)--> relay outbound
|
||||
// -> proxy core (relay inbound --> proxy outbound --(dialerProxy)--> protect outbound)
|
||||
// -> protect inbound -> direct proxy outbound data -> internet
|
||||
public int TunProtectSsPort { get; init; } = 0;
|
||||
public int ProxyRelaySsPort { get; init; } = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ namespace ServiceLib.Models;
|
|||
|
||||
public record ProtocolExtraItem
|
||||
{
|
||||
public bool? Uot { get; init; }
|
||||
public string? CongestionControl { get; init; }
|
||||
|
||||
// vmess
|
||||
public string? AlterId { get; init; }
|
||||
public string? VmessSecurity { get; init; }
|
||||
|
|
@ -29,6 +32,9 @@ public record ProtocolExtraItem
|
|||
public string? Ports { get; init; }
|
||||
public string? HopInterval { get; init; }
|
||||
|
||||
// naiveproxy
|
||||
public int? InsecureConcurrency { get; init; }
|
||||
|
||||
// group profile
|
||||
public string? GroupType { get; init; }
|
||||
public string? ChildItems { get; init; }
|
||||
|
|
|
|||
|
|
@ -133,10 +133,14 @@ public class Outbound4Sbox : BaseServer4Sbox
|
|||
public int? recv_window_conn { get; set; }
|
||||
public int? recv_window { get; set; }
|
||||
public bool? disable_mtu_discovery { get; set; }
|
||||
public int? insecure_concurrency { get; set; }
|
||||
public bool? udp_over_tcp { get; set; }
|
||||
public string? method { get; set; }
|
||||
public string? username { get; set; }
|
||||
public string? password { get; set; }
|
||||
public string? congestion_control { get; set; }
|
||||
public bool? quic { get; set; }
|
||||
public string? quic_congestion_control { get; set; }
|
||||
public string? version { get; set; }
|
||||
public string? network { get; set; }
|
||||
public string? packet_encoding { get; set; }
|
||||
|
|
@ -257,6 +261,7 @@ public class Server4Sbox : BaseServer4Sbox
|
|||
|
||||
// Deprecated in sing-box 1.12.0 , kept for backward compatibility
|
||||
public string? address { get; set; }
|
||||
|
||||
public string? address_resolver { get; set; }
|
||||
public string? address_strategy { get; set; }
|
||||
public string? strategy { get; set; }
|
||||
|
|
|
|||
|
|
@ -179,6 +179,8 @@ public class ServersItem4Ray
|
|||
|
||||
public string flow { get; set; }
|
||||
|
||||
public bool? uot { get; set; }
|
||||
|
||||
public List<SocksUsersItem4Ray> users { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -472,7 +474,7 @@ public class HysteriaSettings4Ray
|
|||
|
||||
public class HysteriaUdpHop4Ray
|
||||
{
|
||||
public string? ports { get; set; }
|
||||
public string? port { get; set; }
|
||||
public string? interval { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
74
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
74
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -745,7 +745,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add Child 的本地化字符串。
|
||||
/// 查找类似 Add Child 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddChildServer {
|
||||
get {
|
||||
|
|
@ -772,7 +772,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [Hysteria2] 的本地化字符串。
|
||||
/// 查找类似 Add [Hysteria2] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddHysteria2Server {
|
||||
get {
|
||||
|
|
@ -781,7 +781,16 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add Policy Group 的本地化字符串。
|
||||
/// 查找类似 Add [NaïveProxy] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddNaiveServer {
|
||||
get {
|
||||
return ResourceManager.GetString("menuAddNaiveServer", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add Policy Group 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddPolicyGroupServer {
|
||||
get {
|
||||
|
|
@ -826,7 +835,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [Shadowsocks] 的本地化字符串。
|
||||
/// 查找类似 Add [Shadowsocks] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddShadowsocksServer {
|
||||
get {
|
||||
|
|
@ -835,7 +844,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [SOCKS] 的本地化字符串。
|
||||
/// 查找类似 Add [SOCKS] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddSocksServer {
|
||||
get {
|
||||
|
|
@ -844,7 +853,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [Trojan] 的本地化字符串。
|
||||
/// 查找类似 Add [Trojan] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddTrojanServer {
|
||||
get {
|
||||
|
|
@ -853,7 +862,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [TUIC] 的本地化字符串。
|
||||
/// 查找类似 Add [TUIC] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddTuicServer {
|
||||
get {
|
||||
|
|
@ -862,7 +871,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [VLESS] 的本地化字符串。
|
||||
/// 查找类似 Add [VLESS] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddVlessServer {
|
||||
get {
|
||||
|
|
@ -871,7 +880,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [VMess] 的本地化字符串。
|
||||
/// 查找类似 Add [VMess] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddVmessServer {
|
||||
get {
|
||||
|
|
@ -880,7 +889,7 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Add [WireGuard] 的本地化字符串。
|
||||
/// 查找类似 Add [WireGuard] 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string menuAddWireguardServer {
|
||||
get {
|
||||
|
|
@ -3060,6 +3069,15 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Insecure Concurrency 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbInsecureConcurrency {
|
||||
get {
|
||||
return ResourceManager.GetString("TbInsecureConcurrency", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Most Stable 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
@ -3780,15 +3798,6 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable additional Inbound 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsEnableExInbound {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsEnableExInbound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable fragment 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
@ -3798,15 +3807,6 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 which conflicts with the group previous proxy 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsEnableFragmentTips {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsEnableFragmentTips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable hardware acceleration (requires restart) 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
@ -4473,6 +4473,24 @@ namespace ServiceLib.Resx {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 UDP over TCP 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbUot {
|
||||
get {
|
||||
return ResourceManager.GetString("TbUot", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Username 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbUsername {
|
||||
get {
|
||||
return ResourceManager.GetString("TbUsername", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Validate Regional Domain IPs 的本地化字符串。
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1071,9 +1071,6 @@
|
|||
<data name="TbSettingsTunMtu" xml:space="preserve">
|
||||
<value>MTU</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>فعال سازی additional Inbound</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>فعال سازی آدرس IPv6</value>
|
||||
</data>
|
||||
|
|
@ -1113,9 +1110,6 @@
|
|||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>افزودن سرور [HTTP]</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>which conflicts with the group previous proxy</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>فعال کردن فرگمنت</value>
|
||||
</data>
|
||||
|
|
@ -1674,4 +1668,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
<data name="TbUot" xml:space="preserve">
|
||||
<value>UDP over TCP</value>
|
||||
</data>
|
||||
<data name="menuAddNaiveServer" xml:space="preserve">
|
||||
<value>Add NaïveProxy</value>
|
||||
</data>
|
||||
<data name="TbInsecureConcurrency" xml:space="preserve">
|
||||
<value>Insecure Concurrency</value>
|
||||
</data>
|
||||
<data name="TbUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1068,9 +1068,6 @@
|
|||
<data name="TbSettingsTunMtu" xml:space="preserve">
|
||||
<value>MTU</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>Activer un port d’écoute supplémentaire</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>Activer IPv6</value>
|
||||
</data>
|
||||
|
|
@ -1110,9 +1107,6 @@
|
|||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>Ajouter [HTTP]</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>En conflit avec le proxy amont de groupe</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>Activer le fragmentation (Fragment)</value>
|
||||
</data>
|
||||
|
|
@ -1639,36 +1633,48 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<value>EchForceQuery</value>
|
||||
</data>
|
||||
<data name="TbFullCertTips" xml:space="preserve">
|
||||
<value>Full certificate (chain), PEM format</value>
|
||||
<value>Certificat complet (chaîne), format PEM</value>
|
||||
</data>
|
||||
<data name="TbCertSha256Tips" xml:space="preserve">
|
||||
<value>Certificate fingerprint (SHA-256)</value>
|
||||
<value>Empreinte du certificat (SHA-256)</value>
|
||||
</data>
|
||||
<data name="TbServeStale" xml:space="preserve">
|
||||
<value>Serve Stale</value>
|
||||
<value>Cache optimiste</value>
|
||||
</data>
|
||||
<data name="TbParallelQuery" xml:space="preserve">
|
||||
<value>Parallel Query</value>
|
||||
<value>Requête parallèle</value>
|
||||
</data>
|
||||
<data name="TbDomesticDNSTips" xml:space="preserve">
|
||||
<value>By default, invoked only during routing for resolution</value>
|
||||
<value>Par défaut, utilisé uniquement lors du routage pour la résolution.</value>
|
||||
</data>
|
||||
<data name="TbRemoteDNSTips" xml:space="preserve">
|
||||
<value>By default, invoked only during routing for resolution; ensure the remote server can reach this DNS</value>
|
||||
<value>Par défaut, invoqué uniquement au routage pour la résolution. Vérifiez que le serveur distant peut joindre ce DNS.</value>
|
||||
</data>
|
||||
<data name="TbDirectResolveStrategyTips" xml:space="preserve">
|
||||
<value>If unset or "AsIs", DNS resolution uses the system DNS; otherwise, the internal DNS module is used.</value>
|
||||
<value>Si non défini ou « AsIs », le DNS système est utilisé ; sinon, le module DNS interne est utilisé.</value>
|
||||
</data>
|
||||
<data name="TbRemoteResolveStrategyTips" xml:space="preserve">
|
||||
<value>If unset or "AsIs", DNS resolution is performed by the remote server's DNS; otherwise, the internal DNS module is used.</value>
|
||||
<value>Si non défini ou « AsIs », la résolution DNS est assurée par le serveur distant ; sinon, le module DNS interne est utilisé.</value>
|
||||
</data>
|
||||
<data name="TbHopInt7" xml:space="preserve">
|
||||
<value>Port hopping interval</value>
|
||||
<value>Intervalle de saut de port</value>
|
||||
</data>
|
||||
<data name="menuServerListPreview" xml:space="preserve">
|
||||
<value>Configuration item preview</value>
|
||||
<value>Aperçu des sous-config</value>
|
||||
</data>
|
||||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="TbUot" xml:space="preserve">
|
||||
<value>UDP over TCP</value>
|
||||
</data>
|
||||
<data name="menuAddNaiveServer" xml:space="preserve">
|
||||
<value>Ajouter [NaïveProxy]</value>
|
||||
</data>
|
||||
<data name="TbInsecureConcurrency" xml:space="preserve">
|
||||
<value>Insecure Concurrency</value>
|
||||
</data>
|
||||
<data name="TbUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
|||
|
|
@ -1071,9 +1071,6 @@
|
|||
<data name="TbSettingsTunMtu" xml:space="preserve">
|
||||
<value>MTU</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>További bejövő engedélyezése</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>IPv6 cím engedélyezése</value>
|
||||
</data>
|
||||
|
|
@ -1113,9 +1110,6 @@
|
|||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>HTTP konfiguráció hozzáadása</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>which conflicts with the group previous proxy</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>Fragment engedélyezése</value>
|
||||
</data>
|
||||
|
|
@ -1674,4 +1668,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
<data name="TbUot" xml:space="preserve">
|
||||
<value>UDP over TCP</value>
|
||||
</data>
|
||||
<data name="menuAddNaiveServer" xml:space="preserve">
|
||||
<value>[NaïveProxy] konfiguráció hozzáadása</value>
|
||||
</data>
|
||||
<data name="TbInsecureConcurrency" xml:space="preserve">
|
||||
<value>Insecure Concurrency</value>
|
||||
</data>
|
||||
<data name="TbUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -514,19 +514,19 @@
|
|||
<value>Add a custom configuration</value>
|
||||
</data>
|
||||
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
||||
<value>Add [Shadowsocks] </value>
|
||||
<value>Add [Shadowsocks]</value>
|
||||
</data>
|
||||
<data name="menuAddSocksServer" xml:space="preserve">
|
||||
<value>Add [SOCKS] </value>
|
||||
<value>Add [SOCKS]</value>
|
||||
</data>
|
||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||
<value>Add [Trojan] </value>
|
||||
<value>Add [Trojan]</value>
|
||||
</data>
|
||||
<data name="menuAddVlessServer" xml:space="preserve">
|
||||
<value>Add [VLESS] </value>
|
||||
<value>Add [VLESS]</value>
|
||||
</data>
|
||||
<data name="menuAddVmessServer" xml:space="preserve">
|
||||
<value>Add [VMess] </value>
|
||||
<value>Add [VMess]</value>
|
||||
</data>
|
||||
<data name="menuSelectAll" xml:space="preserve">
|
||||
<value>Select all</value>
|
||||
|
|
@ -1036,7 +1036,7 @@
|
|||
<value>Domain</value>
|
||||
</data>
|
||||
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||
<value>Add [Hysteria2] </value>
|
||||
<value>Add [Hysteria2]</value>
|
||||
</data>
|
||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||
<value>Hysteria Max bandwidth (Up/Down)</value>
|
||||
|
|
@ -1045,7 +1045,7 @@
|
|||
<value>Use System Hosts</value>
|
||||
</data>
|
||||
<data name="menuAddTuicServer" xml:space="preserve">
|
||||
<value>Add [TUIC] </value>
|
||||
<value>Add [TUIC]</value>
|
||||
</data>
|
||||
<data name="TbHeaderType8" xml:space="preserve">
|
||||
<value>Congestion control</value>
|
||||
|
|
@ -1071,14 +1071,11 @@
|
|||
<data name="TbSettingsTunMtu" xml:space="preserve">
|
||||
<value>MTU</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>Enable additional Inbound</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>Enable IPv6 Address</value>
|
||||
</data>
|
||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||
<value>Add [WireGuard] </value>
|
||||
<value>Add [WireGuard]</value>
|
||||
</data>
|
||||
<data name="TbPrivateKey" xml:space="preserve">
|
||||
<value>Private Key</value>
|
||||
|
|
@ -1113,9 +1110,6 @@
|
|||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>Add [HTTP]</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>which conflicts with the group previous proxy</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>Enable fragment</value>
|
||||
</data>
|
||||
|
|
@ -1522,13 +1516,13 @@
|
|||
<value>Policy Group Type</value>
|
||||
</data>
|
||||
<data name="menuAddPolicyGroupServer" xml:space="preserve">
|
||||
<value>Add Policy Group </value>
|
||||
<value>Add Policy Group</value>
|
||||
</data>
|
||||
<data name="menuAddProxyChainServer" xml:space="preserve">
|
||||
<value>Add Proxy Chain</value>
|
||||
</data>
|
||||
<data name="menuAddChildServer" xml:space="preserve">
|
||||
<value>Add Child </value>
|
||||
<value>Add Child</value>
|
||||
</data>
|
||||
<data name="menuRemoveChildServer" xml:space="preserve">
|
||||
<value>Remove Child </value>
|
||||
|
|
@ -1674,4 +1668,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
<data name="TbUot" xml:space="preserve">
|
||||
<value>UDP over TCP</value>
|
||||
</data>
|
||||
<data name="menuAddNaiveServer" xml:space="preserve">
|
||||
<value>Add [NaïveProxy]</value>
|
||||
</data>
|
||||
<data name="TbInsecureConcurrency" xml:space="preserve">
|
||||
<value>Insecure Concurrency</value>
|
||||
</data>
|
||||
<data name="TbUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1071,9 +1071,6 @@
|
|||
<data name="TbSettingsTunMtu" xml:space="preserve">
|
||||
<value>MTU</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>Включить дополнительный входящий канал</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>Включить IPv6 адреса</value>
|
||||
</data>
|
||||
|
|
@ -1113,9 +1110,6 @@
|
|||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>Добавить сервер [HTTP]</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>что конфликтует с предыдущим прокси группы</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>Включить фрагментацию (Fragment)</value>
|
||||
</data>
|
||||
|
|
@ -1674,4 +1668,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
<data name="TbUot" xml:space="preserve">
|
||||
<value>UDP over TCP</value>
|
||||
</data>
|
||||
<data name="menuAddNaiveServer" xml:space="preserve">
|
||||
<value>Добавить сервер [NaïveProxy]</value>
|
||||
</data>
|
||||
<data name="TbInsecureConcurrency" xml:space="preserve">
|
||||
<value>Insecure Concurrency</value>
|
||||
</data>
|
||||
<data name="TbUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -517,16 +517,16 @@
|
|||
<value>添加 [Shadowsocks]</value>
|
||||
</data>
|
||||
<data name="menuAddSocksServer" xml:space="preserve">
|
||||
<value>添加 [SOCKS] </value>
|
||||
<value>添加 [SOCKS]</value>
|
||||
</data>
|
||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||
<value>添加 [Trojan] </value>
|
||||
<value>添加 [Trojan]</value>
|
||||
</data>
|
||||
<data name="menuAddVlessServer" xml:space="preserve">
|
||||
<value>添加 [VLESS] </value>
|
||||
<value>添加 [VLESS]</value>
|
||||
</data>
|
||||
<data name="menuAddVmessServer" xml:space="preserve">
|
||||
<value>添加 [VMess] </value>
|
||||
<value>添加 [VMess]</value>
|
||||
</data>
|
||||
<data name="menuSelectAll" xml:space="preserve">
|
||||
<value>全选</value>
|
||||
|
|
@ -1033,7 +1033,7 @@
|
|||
<value>Domain</value>
|
||||
</data>
|
||||
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||
<value>添加 [Hysteria2] </value>
|
||||
<value>添加 [Hysteria2]</value>
|
||||
</data>
|
||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||
<value>Hysteria 最大带宽 (Up/Dw)</value>
|
||||
|
|
@ -1042,7 +1042,7 @@
|
|||
<value>使用系统 hosts</value>
|
||||
</data>
|
||||
<data name="menuAddTuicServer" xml:space="preserve">
|
||||
<value>添加 [TUIC] </value>
|
||||
<value>添加 [TUIC]</value>
|
||||
</data>
|
||||
<data name="TbHeaderType8" xml:space="preserve">
|
||||
<value>拥塞控制算法</value>
|
||||
|
|
@ -1068,14 +1068,11 @@
|
|||
<data name="TbSettingsTunMtu" xml:space="preserve">
|
||||
<value>MTU</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>启用额外监听端口</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>启用 IPv6</value>
|
||||
</data>
|
||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||
<value>添加 [WireGuard] </value>
|
||||
<value>添加 [WireGuard]</value>
|
||||
</data>
|
||||
<data name="TbPrivateKey" xml:space="preserve">
|
||||
<value>PrivateKey</value>
|
||||
|
|
@ -1108,10 +1105,7 @@
|
|||
<value>*grpc Authority</value>
|
||||
</data>
|
||||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>添加 [HTTP] </value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>和分组前置代理冲突</value>
|
||||
<value>添加 [HTTP]</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>启用分片 (Fragment)</value>
|
||||
|
|
@ -1408,7 +1402,7 @@
|
|||
<value>Mldsa65Verify</value>
|
||||
</data>
|
||||
<data name="menuAddAnytlsServer" xml:space="preserve">
|
||||
<value>添加 [Anytls] </value>
|
||||
<value>添加 [Anytls]</value>
|
||||
</data>
|
||||
<data name="TbRemoteDNS" xml:space="preserve">
|
||||
<value>远程 DNS</value>
|
||||
|
|
@ -1671,4 +1665,16 @@
|
|||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
<data name="TbUot" xml:space="preserve">
|
||||
<value>UDP over TCP</value>
|
||||
</data>
|
||||
<data name="menuAddNaiveServer" xml:space="preserve">
|
||||
<value>添加 [NaïveProxy]</value>
|
||||
</data>
|
||||
<data name="TbInsecureConcurrency" xml:space="preserve">
|
||||
<value>不安全并发</value>
|
||||
</data>
|
||||
<data name="TbUsername" xml:space="preserve">
|
||||
<value>用户名</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -1068,9 +1068,6 @@
|
|||
<data name="TbSettingsTunMtu" xml:space="preserve">
|
||||
<value>MTU</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||
<value>啟用額外偵聽連接埠</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
|
||||
<value>啟用 IPv6</value>
|
||||
</data>
|
||||
|
|
@ -1110,9 +1107,6 @@
|
|||
<data name="menuAddHttpServer" xml:space="preserve">
|
||||
<value>新增 [HTTP] 節點</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||
<value>和分組前置代理衝突</value>
|
||||
</data>
|
||||
<data name="TbSettingsEnableFragment" xml:space="preserve">
|
||||
<value>啟用分片(Fragment)</value>
|
||||
</data>
|
||||
|
|
@ -1671,4 +1665,16 @@
|
|||
<data name="TbFinalmask" xml:space="preserve">
|
||||
<value>Finalmask</value>
|
||||
</data>
|
||||
<data name="TbUot" xml:space="preserve">
|
||||
<value>UDP over TCP</value>
|
||||
</data>
|
||||
<data name="menuAddNaiveServer" xml:space="preserve">
|
||||
<value>新增 [NaïveProxy] 節點</value>
|
||||
</data>
|
||||
<data name="TbInsecureConcurrency" xml:space="preserve">
|
||||
<value>Insecure Concurrency</value>
|
||||
</data>
|
||||
<data name="TbUsername" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -61,6 +61,51 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
|
|||
ret.Success = true;
|
||||
|
||||
ret.Data = ApplyFullConfigTemplate();
|
||||
if (context.TunProtectSsPort is > 0 and <= 65535)
|
||||
{
|
||||
var ssInbound = new
|
||||
{
|
||||
type = "shadowsocks",
|
||||
tag = "tun-protect-ss",
|
||||
listen = Global.Loopback,
|
||||
listen_port = context.TunProtectSsPort,
|
||||
method = "none",
|
||||
password = "none",
|
||||
};
|
||||
var directRule = new Rule4Sbox()
|
||||
{
|
||||
inbound = new List<string> { ssInbound.tag },
|
||||
outbound = Global.DirectTag,
|
||||
};
|
||||
var singboxConfigNode = JsonUtils.ParseJson(ret.Data.ToString())!.AsObject();
|
||||
var inboundsNode = singboxConfigNode["inbounds"]!.AsArray();
|
||||
inboundsNode.Add(JsonUtils.SerializeToNode(ssInbound, new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
}));
|
||||
var routeNode = singboxConfigNode["route"]?.AsObject();
|
||||
var rulesNode = routeNode?["rules"]?.AsArray();
|
||||
var protectRuleNode = JsonUtils.SerializeToNode(directRule,
|
||||
new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
|
||||
if (rulesNode != null)
|
||||
{
|
||||
rulesNode.Insert(0, protectRuleNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newRulesNode = new JsonArray() { protectRuleNode };
|
||||
if (routeNode is null)
|
||||
{
|
||||
var newRouteNode = new JsonObject() { ["rules"] = newRulesNode };
|
||||
singboxConfigNode["route"] = newRouteNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
routeNode["rules"] = newRulesNode;
|
||||
}
|
||||
}
|
||||
ret.Data = JsonUtils.Serialize(singboxConfigNode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -92,18 +137,8 @@ public partial class CoreConfigSingboxService(CoreConfigContext context)
|
|||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
List<IPEndPoint> lstIpEndPoints = new();
|
||||
List<TcpConnectionInformation> lstTcpConns = new();
|
||||
try
|
||||
{
|
||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
var (lstIpEndPoints, lstTcpConns) = Utils.GetActiveNetworkInfo();
|
||||
|
||||
GenLog();
|
||||
GenMinimizedDns();
|
||||
|
|
|
|||
|
|
@ -26,11 +26,15 @@ public partial class CoreConfigSingboxService
|
|||
{
|
||||
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet) ?? [];
|
||||
|
||||
useDirectDns = rules?.LastOrDefault() is { } lastRule &&
|
||||
lastRule.OutboundTag == Global.DirectTag &&
|
||||
(lastRule.Port == "0-65535" ||
|
||||
lastRule.Network == "tcp,udp" ||
|
||||
lastRule.Ip?.Contains("0.0.0.0/0") == true);
|
||||
if (rules?.LastOrDefault() is { } lastRule && lastRule.OutboundTag == Global.DirectTag)
|
||||
{
|
||||
var noDomain = lastRule.Domain == null || lastRule.Domain.Count == 0;
|
||||
var noProcess = lastRule.Process == null || lastRule.Process.Count == 0;
|
||||
var isAnyIp = lastRule.Ip == null || lastRule.Ip.Count == 0 || lastRule.Ip.Contains("0.0.0.0/0");
|
||||
var isAnyPort = string.IsNullOrEmpty(lastRule.Port) || lastRule.Port == "0-65535";
|
||||
var isAnyNetwork = string.IsNullOrEmpty(lastRule.Network) || lastRule.Network == "tcp,udp";
|
||||
useDirectDns = noDomain && noProcess && isAnyIp && isAnyPort && isAnyNetwork;
|
||||
}
|
||||
}
|
||||
_coreConfig.dns.final = useDirectDns ? Global.SingboxDirectDNSTag : Global.SingboxRemoteDNSTag;
|
||||
var simpleDnsItem = context.SimpleDnsItem;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ public partial class CoreConfigSingboxService
|
|||
try
|
||||
{
|
||||
var listen = "0.0.0.0";
|
||||
var listenPort = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
_coreConfig.inbounds = [];
|
||||
|
||||
if (!_config.TunModeItem.EnableTun
|
||||
|| (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && AppManager.Instance.RunningCoreType == ECoreType.sing_box))
|
||||
if (!context.IsTunEnabled
|
||||
|| (context.IsTunEnabled && _node.Port != listenPort))
|
||||
{
|
||||
var inbound = new Inbound4Sbox()
|
||||
{
|
||||
|
|
@ -20,7 +21,7 @@ public partial class CoreConfigSingboxService
|
|||
};
|
||||
_coreConfig.inbounds.Add(inbound);
|
||||
|
||||
inbound.listen_port = AppManager.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||
inbound.listen_port = listenPort;
|
||||
|
||||
if (_config.Inbound.First().SecondLocalPortEnabled)
|
||||
{
|
||||
|
|
@ -49,7 +50,7 @@ public partial class CoreConfigSingboxService
|
|||
}
|
||||
}
|
||||
|
||||
if (_config.TunModeItem.EnableTun)
|
||||
if (context.IsTunEnabled)
|
||||
{
|
||||
if (_config.TunModeItem.Mtu <= 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@ public partial class CoreConfigSingboxService
|
|||
{
|
||||
proxyOutboundList.AddRange(BuildGroupProxyOutbounds(baseTagName));
|
||||
}
|
||||
var proxyTags = proxyOutboundList.Where(n => n.tag.StartsWith(Global.ProxyTag)).Select(n => n.tag).ToList();
|
||||
if (proxyTags.Count > 1)
|
||||
if (withSelector)
|
||||
{
|
||||
proxyOutboundList.InsertRange(0, BuildSelectorOutbounds(proxyTags, baseTagName));
|
||||
var proxyTags = proxyOutboundList.Where(n => n.tag.StartsWith(Global.ProxyTag)).Select(n => n.tag).ToList();
|
||||
if (proxyTags.Count > 1)
|
||||
{
|
||||
proxyOutboundList.InsertRange(0, BuildSelectorOutbounds(proxyTags, baseTagName));
|
||||
}
|
||||
}
|
||||
return proxyOutboundList;
|
||||
}
|
||||
|
|
@ -43,6 +46,7 @@ public partial class CoreConfigSingboxService
|
|||
case EConfigType.PolicyGroup:
|
||||
proxyOutboundList = BuildOutboundsList(baseTagName);
|
||||
break;
|
||||
|
||||
case EConfigType.ProxyChain:
|
||||
proxyOutboundList = BuildChainOutboundsList(baseTagName);
|
||||
break;
|
||||
|
|
@ -108,6 +112,7 @@ public partial class CoreConfigSingboxService
|
|||
outbound.method = AppManager.Instance.GetShadowsocksSecurities(_node).Contains(protocolExtra.SsMethod)
|
||||
? protocolExtra.SsMethod : Global.None;
|
||||
outbound.password = _node.Password;
|
||||
outbound.udp_over_tcp = protocolExtra.Uot == true ? true : null;
|
||||
|
||||
if (_node.Network == nameof(ETransport.tcp) && _node.HeaderType == Global.TcpHeaderHttp)
|
||||
{
|
||||
|
|
@ -265,7 +270,7 @@ public partial class CoreConfigSingboxService
|
|||
{
|
||||
outbound.uuid = _node.Username;
|
||||
outbound.password = _node.Password;
|
||||
outbound.congestion_control = _node.HeaderType;
|
||||
outbound.congestion_control = protocolExtra.CongestionControl;
|
||||
break;
|
||||
}
|
||||
case EConfigType.Anytls:
|
||||
|
|
@ -273,6 +278,22 @@ public partial class CoreConfigSingboxService
|
|||
outbound.password = _node.Password;
|
||||
break;
|
||||
}
|
||||
case EConfigType.Naive:
|
||||
{
|
||||
outbound.username = _node.Username;
|
||||
outbound.password = _node.Password;
|
||||
if (outbound.network == "quic")
|
||||
{
|
||||
outbound.quic = true;
|
||||
outbound.quic_congestion_control = protocolExtra.CongestionControl.NullIfEmpty();
|
||||
}
|
||||
if (protocolExtra.InsecureConcurrency > 0)
|
||||
{
|
||||
outbound.insecure_concurrency = protocolExtra.InsecureConcurrency;
|
||||
}
|
||||
outbound.udp_over_tcp = protocolExtra.Uot == true ? true : null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FillOutboundTls(outbound);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
var ret = new RetResult();
|
||||
try
|
||||
{
|
||||
if (context.IsTunEnabled && context.TunProtectSsPort > 0 && context.ProxyRelaySsPort > 0)
|
||||
{
|
||||
return GenerateClientProxyRelayConfig();
|
||||
}
|
||||
if (_node == null
|
||||
|| !_node.IsValid())
|
||||
{
|
||||
|
|
@ -56,6 +60,12 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
|
||||
GenStatistic();
|
||||
|
||||
var finalRule = BuildFinalRule();
|
||||
if (!string.IsNullOrEmpty(finalRule?.balancerTag))
|
||||
{
|
||||
_coreConfig.routing.rules.Add(finalRule);
|
||||
}
|
||||
|
||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||
ret.Success = true;
|
||||
ret.Data = ApplyFullConfigTemplate();
|
||||
|
|
@ -90,18 +100,8 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
List<IPEndPoint> lstIpEndPoints = new();
|
||||
List<TcpConnectionInformation> lstTcpConns = new();
|
||||
try
|
||||
{
|
||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
|
||||
var (lstIpEndPoints, lstTcpConns) = Utils.GetActiveNetworkInfo();
|
||||
|
||||
GenLog();
|
||||
_coreConfig.inbounds.Clear();
|
||||
|
|
@ -240,6 +240,7 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
GenLog();
|
||||
GenOutbounds();
|
||||
|
||||
_coreConfig.routing.domainStrategy = Global.AsIs;
|
||||
_coreConfig.routing.rules.Clear();
|
||||
_coreConfig.inbounds.Clear();
|
||||
_coreConfig.inbounds.Add(new()
|
||||
|
|
@ -250,6 +251,8 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
protocol = EInboundProtocol.mixed.ToString(),
|
||||
});
|
||||
|
||||
_coreConfig.routing.rules.Add(BuildFinalRule());
|
||||
|
||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||
ret.Success = true;
|
||||
ret.Data = JsonUtils.Serialize(_coreConfig);
|
||||
|
|
@ -263,5 +266,106 @@ public partial class CoreConfigV2rayService(CoreConfigContext context)
|
|||
}
|
||||
}
|
||||
|
||||
public RetResult GenerateClientProxyRelayConfig()
|
||||
{
|
||||
var ret = new RetResult();
|
||||
try
|
||||
{
|
||||
if (_node == null
|
||||
|| !_node.IsValid())
|
||||
{
|
||||
ret.Msg = ResUI.CheckServerSettings;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (_node.GetNetwork() is nameof(ETransport.quic))
|
||||
{
|
||||
ret.Msg = ResUI.Incorrectconfiguration + $" - {_node.GetNetwork()}";
|
||||
return ret;
|
||||
}
|
||||
|
||||
var result = EmbedUtils.GetEmbedText(Global.V2raySampleClient);
|
||||
if (result.IsNullOrEmpty())
|
||||
{
|
||||
ret.Msg = ResUI.FailedGetDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
|
||||
_coreConfig = JsonUtils.Deserialize<V2rayConfig>(result);
|
||||
if (_coreConfig == null)
|
||||
{
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GenLog();
|
||||
_coreConfig.outbounds.Clear();
|
||||
GenOutbounds();
|
||||
|
||||
var protectNode = new ProfileItem()
|
||||
{
|
||||
CoreType = ECoreType.Xray,
|
||||
ConfigType = EConfigType.Shadowsocks,
|
||||
Address = Global.Loopback,
|
||||
Port = context.TunProtectSsPort,
|
||||
Password = Global.None,
|
||||
};
|
||||
protectNode.SetProtocolExtra(protectNode.GetProtocolExtra() with
|
||||
{
|
||||
SsMethod = Global.None,
|
||||
});
|
||||
|
||||
foreach (var outbound in _coreConfig.outbounds.Where(outbound => outbound.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
|
||||
{
|
||||
outbound.streamSettings ??= new StreamSettings4Ray();
|
||||
outbound.streamSettings.sockopt ??= new Sockopt4Ray();
|
||||
outbound.streamSettings.sockopt.dialerProxy = "tun-project-ss";
|
||||
}
|
||||
_coreConfig.outbounds.Add(new CoreConfigV2rayService(context with
|
||||
{
|
||||
Node = protectNode,
|
||||
}).BuildProxyOutbound("tun-project-ss"));
|
||||
|
||||
var hasBalancer = _coreConfig.routing.balancers is { Count: > 0 };
|
||||
_coreConfig.routing.rules =
|
||||
[
|
||||
new()
|
||||
{
|
||||
inboundTag = new List<string> { "proxy-relay-ss" },
|
||||
outboundTag = hasBalancer ? null : Global.ProxyTag,
|
||||
balancerTag = hasBalancer ? Global.ProxyTag + Global.BalancerTagSuffix: null,
|
||||
type = "field"
|
||||
}
|
||||
];
|
||||
_coreConfig.inbounds.Clear();
|
||||
|
||||
var configNode = JsonUtils.ParseJson(JsonUtils.Serialize(_coreConfig))!;
|
||||
configNode["inbounds"]!.AsArray().Add(new
|
||||
{
|
||||
listen = Global.Loopback,
|
||||
port = context.ProxyRelaySsPort,
|
||||
protocol = "shadowsocks",
|
||||
settings = new
|
||||
{
|
||||
network = "tcp,udp",
|
||||
method = Global.None,
|
||||
password = Global.None,
|
||||
},
|
||||
tag = "proxy-relay-ss",
|
||||
});
|
||||
|
||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||
ret.Success = true;
|
||||
ret.Data = JsonUtils.Serialize(configNode);
|
||||
return ret;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion public gen function
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,17 +70,16 @@ public partial class CoreConfigV2rayService
|
|||
dnsItem.serveStale = simpleDnsItem?.ServeStale is true ? true : null;
|
||||
dnsItem.enableParallelQuery = simpleDnsItem?.ParallelQuery is true ? true : null;
|
||||
|
||||
if (_coreConfig.routing.domainStrategy == Global.IPIfNonMatch)
|
||||
// DNS routing
|
||||
var finalRule = BuildFinalRule();
|
||||
dnsItem.tag = Global.DnsTag;
|
||||
_coreConfig.routing.rules.Add(new()
|
||||
{
|
||||
// DNS routing
|
||||
dnsItem.tag = Global.DnsTag;
|
||||
_coreConfig.routing.rules.Add(new RulesItem4Ray
|
||||
{
|
||||
type = "field",
|
||||
inboundTag = new List<string> { Global.DnsTag },
|
||||
outboundTag = Global.ProxyTag,
|
||||
});
|
||||
}
|
||||
type = "field",
|
||||
inboundTag = [Global.DnsTag],
|
||||
outboundTag = finalRule.outboundTag,
|
||||
balancerTag = finalRule.balancerTag
|
||||
});
|
||||
|
||||
_coreConfig.dns = dnsItem;
|
||||
}
|
||||
|
|
@ -93,45 +92,6 @@ public partial class CoreConfigV2rayService
|
|||
private void FillDnsServers(Dns4Ray dnsItem)
|
||||
{
|
||||
var simpleDNSItem = context.SimpleDnsItem;
|
||||
static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress)
|
||||
{
|
||||
var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';')
|
||||
.Select(addr => addr.Trim())
|
||||
.Where(addr => !string.IsNullOrEmpty(addr))
|
||||
.Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr)
|
||||
.Distinct()
|
||||
.ToList() ?? new List<string> { defaultAddress };
|
||||
return addresses.Count > 0 ? addresses : new List<string> { defaultAddress };
|
||||
}
|
||||
|
||||
static object? CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
||||
{
|
||||
var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress);
|
||||
var domainFinal = dnsAddress;
|
||||
int? portFinal = null;
|
||||
if (scheme.IsNullOrEmpty() || scheme.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
domainFinal = domain;
|
||||
portFinal = port > 0 ? port : null;
|
||||
}
|
||||
else if (scheme.StartsWith("tcp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
domainFinal = scheme + "://" + domain;
|
||||
portFinal = port > 0 ? port : null;
|
||||
}
|
||||
var dnsServer = new DnsServer4Ray
|
||||
{
|
||||
address = domainFinal,
|
||||
port = portFinal,
|
||||
skipFallback = true,
|
||||
domains = domains.Count > 0 ? domains : null,
|
||||
expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null
|
||||
};
|
||||
return JsonUtils.SerializeToNode(dnsServer, new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
});
|
||||
}
|
||||
|
||||
var directDNSAddress = ParseDnsAddresses(simpleDNSItem?.DirectDNS, Global.DomainDirectDNSAddress.First());
|
||||
var remoteDNSAddress = ParseDnsAddresses(simpleDNSItem?.RemoteDNS, Global.DomainRemoteDNSAddress.First());
|
||||
|
|
@ -252,17 +212,6 @@ public partial class CoreConfigV2rayService
|
|||
|
||||
dnsItem.servers ??= [];
|
||||
|
||||
void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null)
|
||||
{
|
||||
if (domains.Count > 0)
|
||||
{
|
||||
foreach (var dnsAddress in dnsAddresses)
|
||||
{
|
||||
dnsItem.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
||||
AddDnsServers(directDNSAddress, directDomainList);
|
||||
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
||||
|
|
@ -273,14 +222,73 @@ public partial class CoreConfigV2rayService
|
|||
AddDnsServers(bootstrapDNSAddress, dnsServerDomains);
|
||||
}
|
||||
|
||||
var useDirectDns = rules?.LastOrDefault() is { } lastRule
|
||||
&& lastRule.OutboundTag == Global.DirectTag
|
||||
&& (lastRule.Port == "0-65535"
|
||||
|| lastRule.Network == "tcp,udp"
|
||||
|| lastRule.Ip?.Contains("0.0.0.0/0") == true);
|
||||
var useDirectDns = false;
|
||||
|
||||
if (rules?.LastOrDefault() is { } lastRule && lastRule.OutboundTag == Global.DirectTag)
|
||||
{
|
||||
var noDomain = lastRule.Domain == null || lastRule.Domain.Count == 0;
|
||||
var noProcess = lastRule.Process == null || lastRule.Process.Count == 0;
|
||||
var isAnyIp = lastRule.Ip == null || lastRule.Ip.Count == 0 || lastRule.Ip.Contains("0.0.0.0/0");
|
||||
var isAnyPort = string.IsNullOrEmpty(lastRule.Port) || lastRule.Port == "0-65535";
|
||||
var isAnyNetwork = string.IsNullOrEmpty(lastRule.Network) || lastRule.Network == "tcp,udp";
|
||||
useDirectDns = noDomain && noProcess && isAnyIp && isAnyPort && isAnyNetwork;
|
||||
}
|
||||
|
||||
var defaultDnsServers = useDirectDns ? directDNSAddress : remoteDNSAddress;
|
||||
dnsItem.servers.AddRange(defaultDnsServers);
|
||||
return;
|
||||
|
||||
static List<string> ParseDnsAddresses(string? dnsInput, string defaultAddress)
|
||||
{
|
||||
var addresses = dnsInput?.Split(dnsInput.Contains(',') ? ',' : ';')
|
||||
.Select(addr => addr.Trim())
|
||||
.Where(addr => !string.IsNullOrEmpty(addr))
|
||||
.Select(addr => addr.StartsWith("dhcp", StringComparison.OrdinalIgnoreCase) ? "localhost" : addr)
|
||||
.Distinct()
|
||||
.ToList() ?? [defaultAddress];
|
||||
return addresses.Count > 0 ? addresses : new List<string> { defaultAddress };
|
||||
}
|
||||
|
||||
static object? CreateDnsServer(string dnsAddress, List<string> domains, List<string>? expectedIPs = null)
|
||||
{
|
||||
var (domain, scheme, port, path) = Utils.ParseUrl(dnsAddress);
|
||||
var domainFinal = dnsAddress;
|
||||
int? portFinal = null;
|
||||
if (scheme.IsNullOrEmpty() || scheme.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
domainFinal = domain;
|
||||
portFinal = port > 0 ? port : null;
|
||||
}
|
||||
else if (scheme.StartsWith("tcp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
domainFinal = scheme + "://" + domain;
|
||||
portFinal = port > 0 ? port : null;
|
||||
}
|
||||
var dnsServer = new DnsServer4Ray
|
||||
{
|
||||
address = domainFinal,
|
||||
port = portFinal,
|
||||
skipFallback = true,
|
||||
domains = domains.Count > 0 ? domains : null,
|
||||
expectedIPs = expectedIPs?.Count > 0 ? expectedIPs : null
|
||||
};
|
||||
return JsonUtils.SerializeToNode(dnsServer, new JsonSerializerOptions
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
});
|
||||
}
|
||||
|
||||
void AddDnsServers(List<string> dnsAddresses, List<string> domains, List<string>? expectedIPs = null)
|
||||
{
|
||||
if (domains.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (var dnsAddress in dnsAddresses)
|
||||
{
|
||||
dnsItem.servers.Add(CreateDnsServer(dnsAddress, domains, expectedIPs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FillDnsHosts(Dns4Ray dnsItem)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public partial class CoreConfigV2rayService
|
|||
var fragmentOutbound = new Outbounds4Ray
|
||||
{
|
||||
protocol = "freedom",
|
||||
tag = $"frag-{Global.ProxyTag}",
|
||||
tag = $"frag-{baseTagName}",
|
||||
settings = new()
|
||||
{
|
||||
fragment = new()
|
||||
|
|
@ -44,16 +44,17 @@ public partial class CoreConfigV2rayService
|
|||
};
|
||||
var actOutboundWithTlsList =
|
||||
proxyOutboundList.Where(n => n.streamSettings?.security.IsNullOrEmpty() == false
|
||||
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true));
|
||||
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true)).ToList();
|
||||
if (actOutboundWithTlsList.Count > 0)
|
||||
{
|
||||
proxyOutboundList.Add(fragmentOutbound);
|
||||
}
|
||||
foreach (var outbound in actOutboundWithTlsList)
|
||||
{
|
||||
var fragmentOutboundClone = JsonUtils.DeepCopy(fragmentOutbound);
|
||||
fragmentOutboundClone.tag = $"frag-{outbound.tag}";
|
||||
outbound.streamSettings.sockopt = new()
|
||||
{
|
||||
dialerProxy = fragmentOutboundClone.tag
|
||||
dialerProxy = fragmentOutbound.tag
|
||||
};
|
||||
proxyOutboundList.Add(fragmentOutboundClone);
|
||||
}
|
||||
}
|
||||
return proxyOutboundList;
|
||||
|
|
@ -67,6 +68,7 @@ public partial class CoreConfigV2rayService
|
|||
case EConfigType.PolicyGroup:
|
||||
proxyOutboundList.AddRange(BuildOutboundsList(baseTagName));
|
||||
break;
|
||||
|
||||
case EConfigType.ProxyChain:
|
||||
proxyOutboundList.AddRange(BuildChainOutboundsList(baseTagName));
|
||||
break;
|
||||
|
|
@ -151,6 +153,7 @@ public partial class CoreConfigV2rayService
|
|||
serversItem.password = _node.Password;
|
||||
serversItem.method = AppManager.Instance.GetShadowsocksSecurities(_node).Contains(protocolExtra.SsMethod)
|
||||
? protocolExtra.SsMethod : "none";
|
||||
serversItem.uot = protocolExtra.Uot == true ? true : null;
|
||||
|
||||
serversItem.ota = false;
|
||||
serversItem.level = 1;
|
||||
|
|
@ -601,7 +604,7 @@ public partial class CoreConfigV2rayService
|
|||
{
|
||||
udpHop = new HysteriaUdpHop4Ray
|
||||
{
|
||||
ports = ports.Replace(':', '-'),
|
||||
port = ports.Replace(':', '-'),
|
||||
interval = hopInterval,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,4 +181,28 @@ public partial class CoreConfigV2rayService
|
|||
|
||||
return tag;
|
||||
}
|
||||
|
||||
private RulesItem4Ray BuildFinalRule()
|
||||
{
|
||||
var finalRule = new RulesItem4Ray()
|
||||
{
|
||||
type = "field",
|
||||
network = "tcp,udp",
|
||||
outboundTag = Global.ProxyTag,
|
||||
};
|
||||
var balancer =
|
||||
_coreConfig?.routing?.balancers?.FirstOrDefault(b => b.tag == Global.ProxyTag + Global.BalancerTagSuffix, null);
|
||||
var domainStrategy = _coreConfig.routing?.domainStrategy ?? Global.AsIs;
|
||||
if (balancer is not null)
|
||||
{
|
||||
finalRule.outboundTag = null;
|
||||
finalRule.balancerTag = balancer.tag;
|
||||
}
|
||||
if (domainStrategy == Global.IPIfNonMatch)
|
||||
{
|
||||
finalRule.network = null;
|
||||
finalRule.ip = ["0.0.0.0/0", "::/0"];
|
||||
}
|
||||
return finalRule;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,15 @@ public class AddServerViewModel : MyReactiveObject
|
|||
[Reactive]
|
||||
public int WgMtu { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool Uot { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string CongestionControl { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public int InsecureConcurrency { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> FetchCertCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> FetchCertChainCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||
|
|
@ -123,6 +132,9 @@ public class AddServerViewModel : MyReactiveObject
|
|||
WgInterfaceAddress = protocolExtra?.WgInterfaceAddress ?? string.Empty;
|
||||
WgReserved = protocolExtra?.WgReserved ?? string.Empty;
|
||||
WgMtu = protocolExtra?.WgMtu ?? 1280;
|
||||
Uot = protocolExtra?.Uot ?? false;
|
||||
CongestionControl = protocolExtra?.CongestionControl ?? string.Empty;
|
||||
InsecureConcurrency = protocolExtra?.InsecureConcurrency ?? 0;
|
||||
}
|
||||
|
||||
private async Task SaveServerAsync()
|
||||
|
|
@ -185,6 +197,9 @@ public class AddServerViewModel : MyReactiveObject
|
|||
WgInterfaceAddress = WgInterfaceAddress.NullIfEmpty(),
|
||||
WgReserved = WgReserved.NullIfEmpty(),
|
||||
WgMtu = WgMtu >= 576 ? WgMtu : null,
|
||||
Uot = Uot ? true : null,
|
||||
CongestionControl = CongestionControl.NullIfEmpty(),
|
||||
InsecureConcurrency = InsecureConcurrency > 0 ? InsecureConcurrency : null
|
||||
});
|
||||
|
||||
if (await ConfigHandler.AddServer(_config, SelectedSource) == 0)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ public class MainWindowViewModel : MyReactiveObject
|
|||
public ReactiveCommand<Unit, Unit> AddTuicServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddWireguardServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddAnytlsServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddNaiveServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddCustomServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddPolicyGroupServerCmd { get; }
|
||||
public ReactiveCommand<Unit, Unit> AddProxyChainServerCmd { get; }
|
||||
|
|
@ -117,6 +118,10 @@ public class MainWindowViewModel : MyReactiveObject
|
|||
{
|
||||
await AddServerAsync(EConfigType.Anytls);
|
||||
});
|
||||
AddNaiveServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await AddServerAsync(EConfigType.Naive);
|
||||
});
|
||||
AddCustomServerCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await AddServerAsync(EConfigType.Custom);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||
[Reactive] public bool TunStrictRoute { get; set; }
|
||||
[Reactive] public string TunStack { get; set; }
|
||||
[Reactive] public int TunMtu { get; set; }
|
||||
[Reactive] public bool TunEnableExInbound { get; set; }
|
||||
[Reactive] public bool TunEnableIPv6Address { get; set; }
|
||||
|
||||
#endregion Tun mode
|
||||
|
|
@ -220,7 +219,6 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||
TunStrictRoute = _config.TunModeItem.StrictRoute;
|
||||
TunStack = _config.TunModeItem.Stack;
|
||||
TunMtu = _config.TunModeItem.Mtu;
|
||||
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
|
||||
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
|
||||
|
||||
#endregion Tun mode
|
||||
|
|
@ -380,7 +378,6 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||
_config.TunModeItem.StrictRoute = TunStrictRoute;
|
||||
_config.TunModeItem.Stack = TunStack;
|
||||
_config.TunModeItem.Mtu = TunMtu;
|
||||
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
|
||||
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
|
||||
|
||||
//coreType
|
||||
|
|
|
|||
|
|
@ -197,6 +197,19 @@
|
|||
Width="300"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbUot}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togUotEnabled3"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
|
|
@ -580,12 +593,84 @@
|
|||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId10"
|
||||
x:Name="txtId11"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridNaive"
|
||||
Grid.Row="2"
|
||||
ColumnDefinitions="300,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbUsername}" />
|
||||
<TextBox
|
||||
x:Name="txtId12"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity12"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbInsecureConcurrency}" />
|
||||
<TextBox
|
||||
x:Name="txtInsecureConcurrency12"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType8}" />
|
||||
<ComboBox
|
||||
x:Name="cmbHeaderType12"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbUot}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togUotEnabled12"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
|
||||
<Separator
|
||||
x:Name="sepa2"
|
||||
|
|
|
|||
|
|
@ -94,10 +94,24 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||
|
||||
case EConfigType.Anytls:
|
||||
gridAnytls.IsVisible = true;
|
||||
sepa2.IsVisible = false;
|
||||
gridTransport.IsVisible = false;
|
||||
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||
cmbCoreType.IsEnabled = false;
|
||||
gridFinalmask.IsVisible = false;
|
||||
break;
|
||||
|
||||
case EConfigType.Naive:
|
||||
gridNaive.IsVisible = true;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
gridFinalmask.IsVisible = false;
|
||||
cmbFingerprint.IsEnabled = false;
|
||||
cmbFingerprint.SelectedValue = string.Empty;
|
||||
cmbAllowInsecure.IsEnabled = false;
|
||||
cmbAllowInsecure.SelectedValue = string.Empty;
|
||||
|
||||
cmbHeaderType12.ItemsSource = Global.NaiveCongestionControls;
|
||||
break;
|
||||
}
|
||||
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
|
||||
|
||||
|
|
@ -122,6 +136,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||
case EConfigType.Shadowsocks:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId3.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SsMethod, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled3.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
|
|
@ -156,7 +171,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||
case EConfigType.TUIC:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.WireGuard:
|
||||
|
|
@ -168,7 +183,15 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||
break;
|
||||
|
||||
case EConfigType.Anytls:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId10.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId11.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.Naive:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType12.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables);
|
||||
break;
|
||||
}
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
<Separator />
|
||||
<MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" />
|
||||
<MenuItem x:Name="menuAddAnytlsServer" Header="{x:Static resx:ResUI.menuAddAnytlsServer}" />
|
||||
<MenuItem x:Name="menuAddNaiveServer" Header="{x:Static resx:ResUI.menuAddNaiveServer}" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuSubscription}">
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
|||
this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -325,12 +325,6 @@
|
|||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="20"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableFragmentTips}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
|
@ -843,19 +837,6 @@
|
|||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableExInbound"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
|||
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -277,6 +277,20 @@
|
|||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbUot}" />
|
||||
<ToggleButton
|
||||
x:Name="togUotEnabled3"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
|
|
@ -772,13 +786,106 @@
|
|||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId10"
|
||||
x:Name="txtId11"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridNaive"
|
||||
Grid.Row="2"
|
||||
Visibility="Hidden">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbUsername}" />
|
||||
<TextBox
|
||||
x:Name="txtId12"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity12"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbInsecureConcurrency}" />
|
||||
<TextBox
|
||||
x:Name="txtInsecureConcurrency12"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType8}" />
|
||||
<ComboBox
|
||||
x:Name="cmbHeaderType12"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbUot}" />
|
||||
<ToggleButton
|
||||
x:Name="togUotEnabled12"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<Separator
|
||||
x:Name="sepa2"
|
||||
|
|
|
|||
|
|
@ -89,10 +89,24 @@ public partial class AddServerWindow
|
|||
|
||||
case EConfigType.Anytls:
|
||||
gridAnytls.Visibility = Visibility.Visible;
|
||||
sepa2.Visibility = Visibility.Collapsed;
|
||||
gridTransport.Visibility = Visibility.Collapsed;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
lstStreamSecurity.Add(Global.StreamSecurityReality);
|
||||
gridFinalmask.Visibility = Visibility.Collapsed;
|
||||
break;
|
||||
|
||||
case EConfigType.Naive:
|
||||
gridNaive.Visibility = Visibility.Visible;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
gridFinalmask.Visibility = Visibility.Collapsed;
|
||||
cmbFingerprint.IsEnabled = false;
|
||||
cmbFingerprint.Text = string.Empty;
|
||||
cmbAllowInsecure.IsEnabled = false;
|
||||
cmbAllowInsecure.Text = string.Empty;
|
||||
|
||||
cmbHeaderType12.ItemsSource = Global.NaiveCongestionControls;
|
||||
break;
|
||||
}
|
||||
cmbStreamSecurity.ItemsSource = lstStreamSecurity;
|
||||
|
||||
|
|
@ -117,6 +131,7 @@ public partial class AddServerWindow
|
|||
case EConfigType.Shadowsocks:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId3.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SsMethod, v => v.cmbSecurity3.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled3.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.MuxEnabled, v => v.togmuxEnabled3.IsChecked).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
|
|
@ -151,7 +166,7 @@ public partial class AddServerWindow
|
|||
case EConfigType.TUIC:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId8.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity8.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType8.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType8.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.WireGuard:
|
||||
|
|
@ -163,7 +178,15 @@ public partial class AddServerWindow
|
|||
break;
|
||||
|
||||
case EConfigType.Anytls:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId10.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtId11.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.Naive:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Username, v => v.txtId12.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtSecurity12.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.InsecureConcurrency, v => v.txtInsecureConcurrency12.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CongestionControl, v => v.cmbHeaderType12.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Uot, v => v.togUotEnabled12.IsChecked).DisposeWith(disposables);
|
||||
break;
|
||||
}
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.Text).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -124,6 +124,10 @@
|
|||
x:Name="menuAddAnytlsServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuAddAnytlsServer}" />
|
||||
<MenuItem
|
||||
x:Name="menuAddNaiveServer"
|
||||
Height="{StaticResource MenuItemHeight}"
|
||||
Header="{x:Static resx:ResUI.menuAddNaiveServer}" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator />
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ public partial class MainWindow
|
|||
this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddNaiveServerCmd, v => v.menuAddNaiveServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).DisposeWith(disposables);
|
||||
|
|
|
|||
|
|
@ -391,13 +391,6 @@
|
|||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="20"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin8}"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableFragmentTips}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
|
@ -1097,20 +1090,6 @@
|
|||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin8}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
|
||||
<ToggleButton
|
||||
x:Name="togEnableExInbound"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin8}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ public partial class OptionSettingWindow
|
|||
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.Text).DisposeWith(disposables);
|
||||
|
|
|
|||
Loading…
Reference in a new issue