Compare commits
35 Commits
dev-go124-
...
v1.11.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
044482bedc | ||
|
|
9c90dc1e8b | ||
|
|
e0cf586111 | ||
|
|
a594edda13 | ||
|
|
dc1a4a5ed4 | ||
|
|
767d30e8a7 | ||
|
|
6926779655 | ||
|
|
399c900596 | ||
|
|
04c8e09663 | ||
|
|
321744d6fa | ||
|
|
fd6dbc6c14 | ||
|
|
98dadfb316 | ||
|
|
f13956b9d4 | ||
|
|
26c7f86121 | ||
|
|
d70a2674d6 | ||
|
|
dbf7007a51 | ||
|
|
c03c57a650 | ||
|
|
a7acb0f26d | ||
|
|
aa28d5394d | ||
|
|
5377021746 | ||
|
|
25310deefd | ||
|
|
08f3bc409e | ||
|
|
061331de2d | ||
|
|
c58f3999e3 | ||
|
|
1d641e0e8f | ||
|
|
767fa36967 | ||
|
|
48d801e9fc | ||
|
|
840fdddfb3 | ||
|
|
431a446e9a | ||
|
|
98083e08c5 | ||
|
|
1f545d0578 | ||
|
|
19d5bc4921 | ||
|
|
642b71c237 | ||
|
|
901f94b409 | ||
|
|
b0d4355978 |
615
.github/workflows/build.yml
vendored
615
.github/workflows/build.yml
vendored
@@ -1,615 +0,0 @@
|
|||||||
name: Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: "Version name"
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
prerelease:
|
|
||||||
description: "Is prerelease"
|
|
||||||
required: true
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
build:
|
|
||||||
description: "Build type"
|
|
||||||
required: true
|
|
||||||
type: choice
|
|
||||||
default: "All"
|
|
||||||
options:
|
|
||||||
- All
|
|
||||||
- Binary
|
|
||||||
- Android
|
|
||||||
- Apple
|
|
||||||
- app-store
|
|
||||||
- iOS
|
|
||||||
- macOS
|
|
||||||
- tvOS
|
|
||||||
- macOS-standalone
|
|
||||||
- publish-android
|
|
||||||
macos_project_version:
|
|
||||||
description: "macOS project version"
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main-next
|
|
||||||
- dev-next
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}-${{ inputs.build }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
calculate_version:
|
|
||||||
name: Calculate version
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
version: ${{ steps.outputs.outputs.version }}
|
|
||||||
prerelease: ${{ steps.outputs.outputs.prerelease }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ^1.23
|
|
||||||
- name: Check input version
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: |-
|
|
||||||
echo "version=${{ inputs.version }}"
|
|
||||||
echo "prerelease=${{ inputs.prerelease }}"
|
|
||||||
echo "version=${{ inputs.version }}" >> "$GITHUB_ENV"
|
|
||||||
echo "prerelease=${{ inputs.prerelease }}" >> "$GITHUB_ENV"
|
|
||||||
- name: Calculate version
|
|
||||||
if: github.event_name != 'workflow_dispatch'
|
|
||||||
run: |-
|
|
||||||
go run -v ./cmd/internal/read_tag --nightly
|
|
||||||
- name: Set outputs
|
|
||||||
id: outputs
|
|
||||||
run: |-
|
|
||||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "prerelease=$prerelease" >> "$GITHUB_OUTPUT"
|
|
||||||
build:
|
|
||||||
name: Build binary
|
|
||||||
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- name: linux_386
|
|
||||||
goos: linux
|
|
||||||
goarch: 386
|
|
||||||
- name: linux_amd64
|
|
||||||
goos: linux
|
|
||||||
goarch: amd64
|
|
||||||
- name: linux_arm64
|
|
||||||
goos: linux
|
|
||||||
goarch: arm64
|
|
||||||
- name: linux_arm
|
|
||||||
goos: linux
|
|
||||||
goarch: arm
|
|
||||||
goarm: 6
|
|
||||||
- name: linux_arm_v7
|
|
||||||
goos: linux
|
|
||||||
goarch: arm
|
|
||||||
goarm: 7
|
|
||||||
- name: linux_s390x
|
|
||||||
goos: linux
|
|
||||||
goarch: s390x
|
|
||||||
- name: linux_riscv64
|
|
||||||
goos: linux
|
|
||||||
goarch: riscv64
|
|
||||||
- name: linux_mips64le
|
|
||||||
goos: linux
|
|
||||||
goarch: mips64le
|
|
||||||
- name: windows_amd64
|
|
||||||
goos: windows
|
|
||||||
goarch: amd64
|
|
||||||
require_legacy_go: true
|
|
||||||
- name: windows_386
|
|
||||||
goos: windows
|
|
||||||
goarch: 386
|
|
||||||
require_legacy_go: true
|
|
||||||
- name: windows_arm64
|
|
||||||
goos: windows
|
|
||||||
goarch: arm64
|
|
||||||
- name: darwin_arm64
|
|
||||||
goos: darwin
|
|
||||||
goarch: arm64
|
|
||||||
- name: darwin_amd64
|
|
||||||
goos: darwin
|
|
||||||
goarch: amd64
|
|
||||||
require_legacy_go: true
|
|
||||||
- name: android_arm64
|
|
||||||
goos: android
|
|
||||||
goarch: arm64
|
|
||||||
- name: android_arm
|
|
||||||
goos: android
|
|
||||||
goarch: arm
|
|
||||||
goarm: 7
|
|
||||||
- name: android_amd64
|
|
||||||
goos: android
|
|
||||||
goarch: amd64
|
|
||||||
- name: android_386
|
|
||||||
goos: android
|
|
||||||
goarch: 386
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ^1.23
|
|
||||||
- name: Cache legacy Go
|
|
||||||
if: matrix.require_legacy_go
|
|
||||||
id: cache-legacy-go
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/go/go1.20.14
|
|
||||||
key: go120
|
|
||||||
- name: Setup legacy Go
|
|
||||||
if: matrix.require_legacy_go == 'true' && steps.cache-legacy-go.outputs.cache-hit != 'true'
|
|
||||||
run: |-
|
|
||||||
wget https://dl.google.com/go/go1.20.14.linux-amd64.tar.gz
|
|
||||||
tar -xzf go1.20.14.linux-amd64.tar.gz
|
|
||||||
mv go $HOME/go/go1.20.14
|
|
||||||
- name: Setup Android NDK
|
|
||||||
if: matrix.goos == 'android'
|
|
||||||
uses: nttld/setup-ndk@v1
|
|
||||||
with:
|
|
||||||
ndk-version: r28-beta2
|
|
||||||
local-cache: true
|
|
||||||
- name: Setup Goreleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v6
|
|
||||||
with:
|
|
||||||
distribution: goreleaser-pro
|
|
||||||
version: latest
|
|
||||||
install-only: true
|
|
||||||
- name: Extract signing key
|
|
||||||
run: |-
|
|
||||||
mkdir -p $HOME/.gnupg
|
|
||||||
cat > $HOME/.gnupg/sagernet.key <<EOF
|
|
||||||
${{ secrets.GPG_KEY }}
|
|
||||||
EOF
|
|
||||||
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
|
||||||
- name: Set tag
|
|
||||||
run: |-
|
|
||||||
git tag v${{ needs.calculate_version.outputs.version }}
|
|
||||||
- name: Build
|
|
||||||
if: matrix.goos != 'android'
|
|
||||||
run: |-
|
|
||||||
goreleaser release --clean --split
|
|
||||||
env:
|
|
||||||
GOOS: ${{ matrix.goos }}
|
|
||||||
GOARCH: ${{ matrix.goarch }}
|
|
||||||
GOPATH: ${{ env.HOME }}/go
|
|
||||||
GOARM: ${{ matrix.goarm }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
|
||||||
NFPM_KEY_PATH: ${{ env.HOME }}/.gnupg/sagernet.key
|
|
||||||
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
|
||||||
- name: Build Android
|
|
||||||
if: matrix.goos == 'android'
|
|
||||||
run: |-
|
|
||||||
go install -v ./cmd/internal/build
|
|
||||||
GOOS=$BUILD_GOOS GOARCH=$BUILD_GOARCH build goreleaser release --clean --split
|
|
||||||
env:
|
|
||||||
BUILD_GOOS: ${{ matrix.goos }}
|
|
||||||
BUILD_GOARCH: ${{ matrix.goarch }}
|
|
||||||
GOARM: ${{ matrix.goarm }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
|
||||||
NFPM_KEY_PATH: ${{ env.HOME }}/.gnupg/sagernet.key
|
|
||||||
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
|
||||||
- name: Upload artifact
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: binary-${{ matrix.name }}
|
|
||||||
path: 'dist'
|
|
||||||
build_android:
|
|
||||||
name: Build Android
|
|
||||||
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Android'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
submodules: 'recursive'
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ^1.23
|
|
||||||
- name: Setup Android NDK
|
|
||||||
id: setup-ndk
|
|
||||||
uses: nttld/setup-ndk@v1
|
|
||||||
with:
|
|
||||||
ndk-version: r28-beta2
|
|
||||||
- name: Setup OpenJDK
|
|
||||||
run: |-
|
|
||||||
sudo apt update && sudo apt install -y openjdk-17-jdk-headless
|
|
||||||
/usr/lib/jvm/java-17-openjdk-amd64/bin/java --version
|
|
||||||
- name: Set tag
|
|
||||||
run: |-
|
|
||||||
git tag v${{ needs.calculate_version.outputs.version }}
|
|
||||||
- name: Build library
|
|
||||||
run: |-
|
|
||||||
make lib_install
|
|
||||||
export PATH="$PATH:$(go env GOPATH)/bin"
|
|
||||||
make lib_android
|
|
||||||
env:
|
|
||||||
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
|
|
||||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
||||||
- name: Checkout main branch
|
|
||||||
if: needs.calculate_version.outputs.prerelease == 'false'
|
|
||||||
run: |-
|
|
||||||
cd clients/android
|
|
||||||
git checkout main
|
|
||||||
- name: Checkout dev branch
|
|
||||||
if: needs.calculate_version.outputs.prerelease == 'true'
|
|
||||||
run: |-
|
|
||||||
cd clients/android
|
|
||||||
git checkout dev
|
|
||||||
- name: Gradle cache
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.gradle
|
|
||||||
key: gradle-${{ hashFiles('**/*.gradle') }}
|
|
||||||
- name: Build
|
|
||||||
run: |-
|
|
||||||
go run -v ./cmd/internal/update_android_version --ci
|
|
||||||
mkdir clients/android/app/libs
|
|
||||||
cp libbox.aar clients/android/app/libs
|
|
||||||
cd clients/android
|
|
||||||
./gradlew :app:assemblePlayRelease :app:assembleOtherRelease
|
|
||||||
env:
|
|
||||||
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
|
|
||||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
||||||
LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
|
|
||||||
- name: Prepare upload
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: |-
|
|
||||||
mkdir -p dist/release
|
|
||||||
cp clients/android/app/build/outputs/apk/play/release/*.apk dist/release
|
|
||||||
cp clients/android/app/build/outputs/apk/other/release/*-universal.apk dist/release
|
|
||||||
- name: Upload artifact
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: binary-android-apks
|
|
||||||
path: 'dist'
|
|
||||||
publish_android:
|
|
||||||
name: Publish Android
|
|
||||||
if: github.event_name == 'workflow_dispatch' && inputs.build == 'publish-android'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
submodules: 'recursive'
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ^1.23
|
|
||||||
- name: Setup Android NDK
|
|
||||||
id: setup-ndk
|
|
||||||
uses: nttld/setup-ndk@v1
|
|
||||||
with:
|
|
||||||
ndk-version: r28-beta2
|
|
||||||
- name: Setup OpenJDK
|
|
||||||
run: |-
|
|
||||||
sudo apt update && sudo apt install -y openjdk-17-jdk-headless
|
|
||||||
/usr/lib/jvm/java-17-openjdk-amd64/bin/java --version
|
|
||||||
- name: Set tag
|
|
||||||
run: |-
|
|
||||||
git tag v${{ needs.calculate_version.outputs.version }}
|
|
||||||
- name: Build library
|
|
||||||
run: |-
|
|
||||||
make lib_install
|
|
||||||
export PATH="$PATH:$(go env GOPATH)/bin"
|
|
||||||
make lib_android
|
|
||||||
env:
|
|
||||||
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
|
|
||||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
||||||
- name: Checkout main branch
|
|
||||||
if: needs.calculate_version.outputs.prerelease == 'false'
|
|
||||||
run: |-
|
|
||||||
cd clients/android
|
|
||||||
git checkout main
|
|
||||||
- name: Checkout dev branch
|
|
||||||
if: needs.calculate_version.outputs.prerelease == 'true'
|
|
||||||
run: |-
|
|
||||||
cd clients/android
|
|
||||||
git checkout dev
|
|
||||||
- name: Gradle cache
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.gradle
|
|
||||||
key: gradle-${{ hashFiles('**/*.gradle') }}
|
|
||||||
- name: Build
|
|
||||||
run: |-
|
|
||||||
go run -v ./cmd/internal/update_android_version --ci
|
|
||||||
mkdir clients/android/app/libs
|
|
||||||
cp libbox.aar clients/android/app/libs
|
|
||||||
cd clients/android
|
|
||||||
echo -n "$SERVICE_ACCOUNT_CREDENTIALS" | base64 --decode > service-account-credentials.json
|
|
||||||
./gradlew :app:publishPlayReleaseBundle
|
|
||||||
env:
|
|
||||||
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
|
|
||||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
||||||
LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
|
|
||||||
SERVICE_ACCOUNT_CREDENTIALS: ${{ secrets.SERVICE_ACCOUNT_CREDENTIALS }}
|
|
||||||
build_apple_library:
|
|
||||||
name: Build Apple library
|
|
||||||
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store' || inputs.build == 'iOS' || inputs.build == 'macOS' || inputs.build == 'tvOS' || inputs.build == 'macOS-standalone'
|
|
||||||
runs-on: macos-15
|
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
submodules: 'recursive'
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ^1.23
|
|
||||||
- name: Setup Xcode
|
|
||||||
run: |-
|
|
||||||
sudo xcode-select -s /Applications/Xcode_16.2_beta_3.app
|
|
||||||
- name: Set tag
|
|
||||||
run: |-
|
|
||||||
git tag v${{ needs.calculate_version.outputs.version }}
|
|
||||||
- name: Build library
|
|
||||||
run: |-
|
|
||||||
make lib_install
|
|
||||||
export PATH="$PATH:$(go env GOPATH)/bin"
|
|
||||||
make lib_ios
|
|
||||||
- name: Upload library
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: library-apple
|
|
||||||
path: 'Libbox.xcframework'
|
|
||||||
build_apple:
|
|
||||||
name: Build Apple clients
|
|
||||||
runs-on: macos-15
|
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
- build_apple_library
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- name: iOS
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'iOS' }}
|
|
||||||
scheme: SFI
|
|
||||||
destination: 'generic/platform=iOS'
|
|
||||||
archive: build/SFI.xcarchive
|
|
||||||
upload: SFI/Upload.plist
|
|
||||||
- name: macOS
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'macOS' }}
|
|
||||||
scheme: SFM
|
|
||||||
destination: 'generic/platform=macOS'
|
|
||||||
archive: build/SFM.xcarchive
|
|
||||||
upload: SFI/Upload.plist
|
|
||||||
- name: tvOS
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'app-store'|| inputs.build == 'tvOS' }}
|
|
||||||
scheme: SFT
|
|
||||||
destination: 'generic/platform=tvOS'
|
|
||||||
archive: build/SFT.xcarchive
|
|
||||||
upload: SFI/Upload.plist
|
|
||||||
- name: macOS-standalone
|
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone' }}
|
|
||||||
scheme: SFM.System
|
|
||||||
destination: 'generic/platform=macOS'
|
|
||||||
archive: build/SFM.System.xcarchive
|
|
||||||
export: SFM.System/Export.plist
|
|
||||||
export_path: build/SFM.System
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
if: matrix.if
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
submodules: 'recursive'
|
|
||||||
- name: Setup Go
|
|
||||||
if: matrix.if
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ^1.23
|
|
||||||
- name: Setup Xcode
|
|
||||||
if: matrix.if
|
|
||||||
run: |-
|
|
||||||
sudo xcode-select -s /Applications/Xcode_16.2_beta_3.app
|
|
||||||
- name: Set tag
|
|
||||||
if: matrix.if
|
|
||||||
run: |-
|
|
||||||
git tag v${{ needs.calculate_version.outputs.version }}
|
|
||||||
echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
|
|
||||||
- name: Checkout main branch
|
|
||||||
if: matrix.if && needs.calculate_version.outputs.prerelease == 'false'
|
|
||||||
run: |-
|
|
||||||
cd clients/apple
|
|
||||||
git checkout main
|
|
||||||
- name: Checkout dev branch
|
|
||||||
if: matrix.if && needs.calculate_version.outputs.prerelease == 'true'
|
|
||||||
run: |-
|
|
||||||
cd clients/apple
|
|
||||||
git checkout dev
|
|
||||||
- name: Setup certificates
|
|
||||||
if: matrix.if
|
|
||||||
run: |-
|
|
||||||
CERTIFICATE_PATH=$RUNNER_TEMP/Certificates.p12
|
|
||||||
KEYCHAIN_PATH=$RUNNER_TEMP/certificates.keychain-db
|
|
||||||
echo -n "$CERTIFICATES_P12" | base64 --decode -o $CERTIFICATE_PATH
|
|
||||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
||||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
||||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
||||||
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
||||||
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
||||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
||||||
|
|
||||||
PROFILES_ZIP_PATH=$RUNNER_TEMP/Profiles.zip
|
|
||||||
echo -n "$PROVISIONING_PROFILES" | base64 --decode -o $PROFILES_ZIP_PATH
|
|
||||||
|
|
||||||
PROFILES_PATH="$HOME/Library/MobileDevice/Provisioning Profiles"
|
|
||||||
mkdir -p "$PROFILES_PATH"
|
|
||||||
unzip $PROFILES_ZIP_PATH -d "$PROFILES_PATH"
|
|
||||||
|
|
||||||
ASC_KEY_PATH=$RUNNER_TEMP/Key.p12
|
|
||||||
echo -n "$ASC_KEY" | base64 --decode -o $ASC_KEY_PATH
|
|
||||||
|
|
||||||
xcrun notarytool store-credentials "notarytool-password" \
|
|
||||||
--key $ASC_KEY_PATH \
|
|
||||||
--key-id $ASC_KEY_ID \
|
|
||||||
--issuer $ASC_KEY_ISSUER_ID
|
|
||||||
env:
|
|
||||||
CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
|
|
||||||
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
|
|
||||||
KEYCHAIN_PASSWORD: ${{ secrets.P12_PASSWORD }}
|
|
||||||
PROVISIONING_PROFILES: ${{ secrets.PROVISIONING_PROFILES }}
|
|
||||||
ASC_KEY: ${{ secrets.ASC_KEY }}
|
|
||||||
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
|
|
||||||
ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }}
|
|
||||||
- name: Download library
|
|
||||||
if: matrix.if
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: library-apple
|
|
||||||
path: clients/apple/Libbox.xcframework
|
|
||||||
- name: Build
|
|
||||||
if: matrix.if
|
|
||||||
run: |-
|
|
||||||
go run -v ./cmd/internal/update_apple_version --ci
|
|
||||||
cd clients/apple
|
|
||||||
xcodebuild archive \
|
|
||||||
-scheme "${{ matrix.scheme }}" \
|
|
||||||
-configuration Release \
|
|
||||||
-destination "${{ matrix.destination }}" \
|
|
||||||
-archivePath "${{ matrix.archive }}" \
|
|
||||||
-allowProvisioningUpdates \
|
|
||||||
-authenticationKeyPath $RUNNER_TEMP/Key.p12 \
|
|
||||||
-authenticationKeyID $ASC_KEY_ID \
|
|
||||||
-authenticationKeyIssuerID $ASC_KEY_ISSUER_ID
|
|
||||||
env:
|
|
||||||
MACOS_PROJECT_VERSION: ${{ inputs.macos_project_version }}
|
|
||||||
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
|
|
||||||
ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }}
|
|
||||||
- name: Upload to App Store Connect
|
|
||||||
if: matrix.if && matrix.name != 'macOS-standalone' && github.event_name == 'workflow_dispatch'
|
|
||||||
run: |-
|
|
||||||
cd clients/apple
|
|
||||||
xcodebuild -exportArchive \
|
|
||||||
-archivePath "${{ matrix.archive }}" \
|
|
||||||
-exportOptionsPlist ${{ matrix.upload }} \
|
|
||||||
-allowProvisioningUpdates \
|
|
||||||
-authenticationKeyPath $RUNNER_TEMP/Key.p12 \
|
|
||||||
-authenticationKeyID $ASC_KEY_ID \
|
|
||||||
-authenticationKeyIssuerID $ASC_KEY_ISSUER_ID
|
|
||||||
env:
|
|
||||||
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
|
|
||||||
ASC_KEY_ISSUER_ID: ${{ secrets.ASC_KEY_ISSUER_ID }}
|
|
||||||
- name: Build image
|
|
||||||
if: matrix.if && matrix.name == 'macOS-standalone' && github.event_name == 'workflow_dispatch'
|
|
||||||
run: |-
|
|
||||||
pushd clients/apple
|
|
||||||
xcodebuild -exportArchive \
|
|
||||||
-archivePath "${{ matrix.archive }}" \
|
|
||||||
-exportOptionsPlist ${{ matrix.export }} \
|
|
||||||
-exportPath "${{ matrix.export_path }}"
|
|
||||||
brew install create-dmg
|
|
||||||
create-dmg \
|
|
||||||
--volname "sing-box" \
|
|
||||||
--volicon "${{ matrix.export_path }}/SFM.app/Contents/Resources/AppIcon.icns" \
|
|
||||||
--icon "SFM.app" 0 0 \
|
|
||||||
--hide-extension "SFM.app" \
|
|
||||||
--app-drop-link 0 0 \
|
|
||||||
--skip-jenkins \
|
|
||||||
SFM.dmg "${{ matrix.export_path }}/SFM.app"
|
|
||||||
xcrun notarytool submit "SFM.dmg" --wait --keychain-profile "notarytool-password"
|
|
||||||
cd "${{ matrix.archive }}"
|
|
||||||
zip -r SFM.dSYMs.zip dSYMs
|
|
||||||
popd
|
|
||||||
|
|
||||||
mkdir -p dist/release
|
|
||||||
cp clients/apple/SFM.dmg "dist/release/SFM-${VERSION}-universal.dmg"
|
|
||||||
cp "clients/apple/${{ matrix.archive }}/SFM.dSYMs.zip" "dist/release/SFM-${VERSION}-universal.dSYMs.zip"
|
|
||||||
- name: Upload image
|
|
||||||
if: matrix.if && matrix.name == 'macOS-standalone' && github.event_name == 'workflow_dispatch'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: binary-macos-dmg
|
|
||||||
path: 'dist'
|
|
||||||
upload:
|
|
||||||
name: Upload builds
|
|
||||||
if: always() && github.event_name == 'workflow_dispatch' && inputs.build != 'publish-android'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
- build
|
|
||||||
- build_android
|
|
||||||
- build_apple
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Goreleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v6
|
|
||||||
with:
|
|
||||||
distribution: goreleaser-pro
|
|
||||||
version: latest
|
|
||||||
install-only: true
|
|
||||||
- name: Cache ghr
|
|
||||||
uses: actions/cache@v4
|
|
||||||
id: cache-ghr
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/go/bin/ghr
|
|
||||||
key: ghr
|
|
||||||
- name: Setup ghr
|
|
||||||
if: steps.cache-ghr.outputs.cache-hit != 'true'
|
|
||||||
run: |-
|
|
||||||
cd $HOME
|
|
||||||
git clone https://github.com/nekohasekai/ghr ghr
|
|
||||||
cd ghr
|
|
||||||
go install -v .
|
|
||||||
- name: Set tag
|
|
||||||
run: |-
|
|
||||||
git tag v${{ needs.calculate_version.outputs.version }}
|
|
||||||
echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
|
|
||||||
- name: Download builds
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: dist
|
|
||||||
merge-multiple: true
|
|
||||||
- name: Merge builds
|
|
||||||
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
|
|
||||||
run: |-
|
|
||||||
goreleaser continue --merge --skip publish
|
|
||||||
mkdir -p dist/release
|
|
||||||
mv dist/*/sing-box*{tar.gz,zip,deb,rpm,_amd64.pkg.tar.zst,_arm64.pkg.tar.zst} dist/release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
|
||||||
- name: Upload builds
|
|
||||||
run: |-
|
|
||||||
export PATH="$PATH:$HOME/go/bin"
|
|
||||||
ghr --replace --draft --prerelease -p 5 "v${VERSION}" dist/release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
219
.github/workflows/debug.yml
vendored
Normal file
219
.github/workflows/debug.yml
vendored
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
name: Debug build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- stable-next
|
||||||
|
- main-next
|
||||||
|
- dev-next
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- '.github/**'
|
||||||
|
- '!.github/workflows/debug.yml'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- stable-next
|
||||||
|
- main-next
|
||||||
|
- dev-next
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Debug build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ^1.23
|
||||||
|
- name: Run Test
|
||||||
|
run: |
|
||||||
|
go test -v ./...
|
||||||
|
build_go120:
|
||||||
|
name: Debug build (Go 1.20)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ~1.20
|
||||||
|
- name: Cache go module
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: go120-${{ hashFiles('**/go.sum') }}
|
||||||
|
- name: Run Test
|
||||||
|
run: make ci_build_go120
|
||||||
|
build_go121:
|
||||||
|
name: Debug build (Go 1.21)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ~1.21
|
||||||
|
- name: Cache go module
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: go121-${{ hashFiles('**/go.sum') }}
|
||||||
|
- name: Run Test
|
||||||
|
run: make ci_build
|
||||||
|
build_go122:
|
||||||
|
name: Debug build (Go 1.22)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ~1.22
|
||||||
|
- name: Cache go module
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: go122-${{ hashFiles('**/go.sum') }}
|
||||||
|
- name: Run Test
|
||||||
|
run: make ci_build
|
||||||
|
cross:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# windows
|
||||||
|
- name: windows-amd64
|
||||||
|
goos: windows
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v1
|
||||||
|
- name: windows-amd64-v3
|
||||||
|
goos: windows
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v3
|
||||||
|
- name: windows-386
|
||||||
|
goos: windows
|
||||||
|
goarch: 386
|
||||||
|
- name: windows-arm64
|
||||||
|
goos: windows
|
||||||
|
goarch: arm64
|
||||||
|
- name: windows-arm32v7
|
||||||
|
goos: windows
|
||||||
|
goarch: arm
|
||||||
|
goarm: 7
|
||||||
|
|
||||||
|
# linux
|
||||||
|
- name: linux-amd64
|
||||||
|
goos: linux
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v1
|
||||||
|
- name: linux-amd64-v3
|
||||||
|
goos: linux
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v3
|
||||||
|
- name: linux-386
|
||||||
|
goos: linux
|
||||||
|
goarch: 386
|
||||||
|
- name: linux-arm64
|
||||||
|
goos: linux
|
||||||
|
goarch: arm64
|
||||||
|
- name: linux-armv5
|
||||||
|
goos: linux
|
||||||
|
goarch: arm
|
||||||
|
goarm: 5
|
||||||
|
- name: linux-armv6
|
||||||
|
goos: linux
|
||||||
|
goarch: arm
|
||||||
|
goarm: 6
|
||||||
|
- name: linux-armv7
|
||||||
|
goos: linux
|
||||||
|
goarch: arm
|
||||||
|
goarm: 7
|
||||||
|
- name: linux-mips-softfloat
|
||||||
|
goos: linux
|
||||||
|
goarch: mips
|
||||||
|
gomips: softfloat
|
||||||
|
- name: linux-mips-hardfloat
|
||||||
|
goos: linux
|
||||||
|
goarch: mips
|
||||||
|
gomips: hardfloat
|
||||||
|
- name: linux-mipsel-softfloat
|
||||||
|
goos: linux
|
||||||
|
goarch: mipsle
|
||||||
|
gomips: softfloat
|
||||||
|
- name: linux-mipsel-hardfloat
|
||||||
|
goos: linux
|
||||||
|
goarch: mipsle
|
||||||
|
gomips: hardfloat
|
||||||
|
- name: linux-mips64
|
||||||
|
goos: linux
|
||||||
|
goarch: mips64
|
||||||
|
- name: linux-mips64el
|
||||||
|
goos: linux
|
||||||
|
goarch: mips64le
|
||||||
|
- name: linux-s390x
|
||||||
|
goos: linux
|
||||||
|
goarch: s390x
|
||||||
|
# darwin
|
||||||
|
- name: darwin-amd64
|
||||||
|
goos: darwin
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v1
|
||||||
|
- name: darwin-amd64-v3
|
||||||
|
goos: darwin
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v3
|
||||||
|
- name: darwin-arm64
|
||||||
|
goos: darwin
|
||||||
|
goarch: arm64
|
||||||
|
# freebsd
|
||||||
|
- name: freebsd-amd64
|
||||||
|
goos: freebsd
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v1
|
||||||
|
- name: freebsd-amd64-v3
|
||||||
|
goos: freebsd
|
||||||
|
goarch: amd64
|
||||||
|
goamd64: v3
|
||||||
|
- name: freebsd-386
|
||||||
|
goos: freebsd
|
||||||
|
goarch: 386
|
||||||
|
- name: freebsd-arm64
|
||||||
|
goos: freebsd
|
||||||
|
goarch: arm64
|
||||||
|
fail-fast: true
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
GOOS: ${{ matrix.goos }}
|
||||||
|
GOARCH: ${{ matrix.goarch }}
|
||||||
|
GOAMD64: ${{ matrix.goamd64 }}
|
||||||
|
GOARM: ${{ matrix.goarm }}
|
||||||
|
GOMIPS: ${{ matrix.gomips }}
|
||||||
|
CGO_ENABLED: 0
|
||||||
|
TAGS: with_gvisor,with_dhcp,with_wireguard,with_clash_api,with_quic,with_utls,with_ech
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: ^1.21
|
||||||
|
- name: Build
|
||||||
|
id: build
|
||||||
|
run: make
|
||||||
1
.github/workflows/linux.yml
vendored
1
.github/workflows/linux.yml
vendored
@@ -22,6 +22,7 @@ jobs:
|
|||||||
mkdir -p $HOME/.gnupg
|
mkdir -p $HOME/.gnupg
|
||||||
cat > $HOME/.gnupg/sagernet.key <<EOF
|
cat > $HOME/.gnupg/sagernet.key <<EOF
|
||||||
${{ secrets.GPG_KEY }}
|
${{ secrets.GPG_KEY }}
|
||||||
|
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||||
EOF
|
EOF
|
||||||
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
|
|||||||
@@ -200,6 +200,4 @@ release:
|
|||||||
ids:
|
ids:
|
||||||
- archive
|
- archive
|
||||||
- package
|
- package
|
||||||
skip_upload: true
|
skip_upload: true
|
||||||
partial:
|
|
||||||
by: target
|
|
||||||
6
Makefile
6
Makefile
@@ -201,15 +201,9 @@ test_stdio:
|
|||||||
lib_android:
|
lib_android:
|
||||||
go run ./cmd/internal/build_libbox -target android
|
go run ./cmd/internal/build_libbox -target android
|
||||||
|
|
||||||
lib_android_debug:
|
|
||||||
go run ./cmd/internal/build_libbox -target android -debug
|
|
||||||
|
|
||||||
lib_ios:
|
lib_ios:
|
||||||
go run ./cmd/internal/build_libbox -target ios
|
go run ./cmd/internal/build_libbox -target ios
|
||||||
|
|
||||||
lib_ios_debug:
|
|
||||||
go run ./cmd/internal/build_libbox -target ios -debug
|
|
||||||
|
|
||||||
lib:
|
lib:
|
||||||
go run ./cmd/internal/build_libbox -target android
|
go run ./cmd/internal/build_libbox -target android
|
||||||
go run ./cmd/internal/build_libbox -target ios
|
go run ./cmd/internal/build_libbox -target ios
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import (
|
|||||||
_ "github.com/sagernet/gomobile"
|
_ "github.com/sagernet/gomobile"
|
||||||
"github.com/sagernet/sing-box/cmd/internal/build_shared"
|
"github.com/sagernet/sing-box/cmd/internal/build_shared"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
"github.com/sagernet/sing/common/shell"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -64,33 +62,9 @@ func init() {
|
|||||||
func buildAndroid() {
|
func buildAndroid() {
|
||||||
build_shared.FindSDK()
|
build_shared.FindSDK()
|
||||||
|
|
||||||
var javaPath string
|
|
||||||
javaHome := os.Getenv("JAVA_HOME")
|
|
||||||
if javaHome == "" {
|
|
||||||
javaPath = "java"
|
|
||||||
} else {
|
|
||||||
javaPath = filepath.Join(javaHome, "bin", "java")
|
|
||||||
}
|
|
||||||
|
|
||||||
javaVersion, err := shell.Exec(javaPath, "--version").ReadOutput()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(E.Cause(err, "check java version"))
|
|
||||||
}
|
|
||||||
if !strings.Contains(javaVersion, "openjdk 17") {
|
|
||||||
log.Fatal("java version should be openjdk 17")
|
|
||||||
}
|
|
||||||
|
|
||||||
var bindTarget string
|
|
||||||
if debugEnabled {
|
|
||||||
bindTarget = "android/arm64"
|
|
||||||
} else {
|
|
||||||
bindTarget = "android"
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"bind",
|
"bind",
|
||||||
"-v",
|
"-v",
|
||||||
"-target", bindTarget,
|
|
||||||
"-androidapi", "21",
|
"-androidapi", "21",
|
||||||
"-javapkg=io.nekohasekai",
|
"-javapkg=io.nekohasekai",
|
||||||
"-libname=box",
|
"-libname=box",
|
||||||
@@ -112,7 +86,7 @@ func buildAndroid() {
|
|||||||
command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
|
command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
|
||||||
command.Stdout = os.Stdout
|
command.Stdout = os.Stdout
|
||||||
command.Stderr = os.Stderr
|
command.Stderr = os.Stderr
|
||||||
err = command.Run()
|
err := command.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -130,17 +104,10 @@ func buildAndroid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildiOS() {
|
func buildiOS() {
|
||||||
var bindTarget string
|
|
||||||
if debugEnabled {
|
|
||||||
bindTarget = "ios"
|
|
||||||
} else {
|
|
||||||
bindTarget = "ios,iossimulator,tvos,tvossimulator,macos"
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"bind",
|
"bind",
|
||||||
"-v",
|
"-v",
|
||||||
"-target", bindTarget,
|
"-target", "ios,iossimulator,tvos,tvossimulator,macos",
|
||||||
"-libname=box",
|
"-libname=box",
|
||||||
}
|
}
|
||||||
if !debugEnabled {
|
if !debugEnabled {
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
|
"github.com/sagernet/sing/common/shell"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -40,6 +42,14 @@ func FindSDK() {
|
|||||||
log.Fatal("android NDK not found")
|
log.Fatal("android NDK not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
javaVersion, err := shell.Exec("java", "--version").ReadOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(E.Cause(err, "check java version"))
|
||||||
|
}
|
||||||
|
if !strings.Contains(javaVersion, "openjdk 17") {
|
||||||
|
log.Fatal("java version should be openjdk 17")
|
||||||
|
}
|
||||||
|
|
||||||
os.Setenv("ANDROID_HOME", androidSDKPath)
|
os.Setenv("ANDROID_HOME", androidSDKPath)
|
||||||
os.Setenv("ANDROID_SDK_HOME", androidSDKPath)
|
os.Setenv("ANDROID_SDK_HOME", androidSDKPath)
|
||||||
os.Setenv("ANDROID_NDK_HOME", androidNDKPath)
|
os.Setenv("ANDROID_NDK_HOME", androidNDKPath)
|
||||||
@@ -48,16 +58,12 @@ func FindSDK() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func findNDK() bool {
|
func findNDK() bool {
|
||||||
const fixedVersion = "28.0.12674087"
|
const fixedVersion = "26.2.11394342"
|
||||||
const versionFile = "source.properties"
|
const versionFile = "source.properties"
|
||||||
if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.IsFile(filepath.Join(fixedPath, versionFile)) {
|
if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.IsFile(filepath.Join(fixedPath, versionFile)) {
|
||||||
androidNDKPath = fixedPath
|
androidNDKPath = fixedPath
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if ndkHomeEnv := os.Getenv("ANDROID_NDK_HOME"); rw.IsFile(filepath.Join(ndkHomeEnv, versionFile)) {
|
|
||||||
androidNDKPath = ndkHomeEnv
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
ndkVersions, err := os.ReadDir(filepath.Join(androidSDKPath, "ndk"))
|
ndkVersions, err := os.ReadDir(filepath.Join(androidSDKPath, "ndk"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ func ReadTag() (string, error) {
|
|||||||
return version.String() + "-" + shortCommit, nil
|
return version.String() + "-" + shortCommit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadTagVersionRev() (badversion.Version, error) {
|
|
||||||
currentTagRev := common.Must1(shell.Exec("git", "describe", "--tags", "--abbrev=0").ReadOutput())
|
|
||||||
return badversion.Parse(currentTagRev[1:]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReadTagVersion() (badversion.Version, error) {
|
func ReadTagVersion() (badversion.Version, error) {
|
||||||
currentTag := common.Must1(shell.Exec("git", "describe", "--tags").ReadOutput())
|
currentTag := common.Must1(shell.Exec("git", "describe", "--tags").ReadOutput())
|
||||||
currentTagRev := common.Must1(shell.Exec("git", "describe", "--tags", "--abbrev=0").ReadOutput())
|
currentTagRev := common.Must1(shell.Exec("git", "describe", "--tags", "--abbrev=0").ReadOutput())
|
||||||
@@ -36,11 +31,3 @@ func ReadTagVersion() (badversion.Version, error) {
|
|||||||
}
|
}
|
||||||
return version, nil
|
return version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsDevBranch() bool {
|
|
||||||
branch, err := shell.Exec("git", "branch", "--show-current").ReadOutput()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return branch == "dev-next"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,74 +1,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/cmd/internal/build_shared"
|
"github.com/sagernet/sing-box/cmd/internal/build_shared"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
F "github.com/sagernet/sing/common/format"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var nightly bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.BoolVar(&nightly, "nightly", false, "Print nightly tag")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
currentTag, err := build_shared.ReadTag()
|
||||||
if nightly {
|
if err != nil {
|
||||||
version, err := build_shared.ReadTagVersionRev()
|
log.Error(err)
|
||||||
if err != nil {
|
_, err = os.Stdout.WriteString("unknown\n")
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
versionStr string
|
|
||||||
isPrerelease bool
|
|
||||||
)
|
|
||||||
if version.PreReleaseIdentifier != "" {
|
|
||||||
isPrerelease = true
|
|
||||||
versionStr = version.VersionString() + "-nightly"
|
|
||||||
} else {
|
|
||||||
version.Patch++
|
|
||||||
versionStr = version.VersionString() + "-nightly"
|
|
||||||
}
|
|
||||||
if build_shared.IsDevBranch() {
|
|
||||||
isPrerelease = true
|
|
||||||
}
|
|
||||||
err = setGitHubOutput("version", versionStr)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
err = setGitHubOutput("prerelease", F.ToString(isPrerelease))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tag, err := build_shared.ReadTag()
|
_, err = os.Stdout.WriteString(currentTag + "\n")
|
||||||
if err != nil {
|
}
|
||||||
log.Error(err)
|
if err != nil {
|
||||||
os.Stdout.WriteString("unknown\n")
|
log.Error(err)
|
||||||
} else {
|
|
||||||
os.Stdout.WriteString(tag + "\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setGitHubOutput(name string, value string) error {
|
|
||||||
outputFile, err := os.OpenFile(os.Getenv("GITHUB_ENV"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = outputFile.WriteString(name + "=" + value + "\n")
|
|
||||||
if err != nil {
|
|
||||||
outputFile.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = outputFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
os.Stderr.WriteString(name + "=" + value + "\n")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -13,22 +12,9 @@ import (
|
|||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var flagRunInCI bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.BoolVar(&flagRunInCI, "ci", false, "Run in CI")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
newVersion := common.Must1(build_shared.ReadTagVersion())
|
||||||
newVersion := common.Must1(build_shared.ReadTag())
|
androidPath, err := filepath.Abs("../sing-box-for-android")
|
||||||
var androidPath string
|
|
||||||
if flagRunInCI {
|
|
||||||
androidPath = "clients/android"
|
|
||||||
} else {
|
|
||||||
androidPath = "../sing-box-for-android"
|
|
||||||
}
|
|
||||||
androidPath, err := filepath.Abs(androidPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -45,10 +31,10 @@ func main() {
|
|||||||
for _, propPair := range propsList {
|
for _, propPair := range propsList {
|
||||||
switch propPair[0] {
|
switch propPair[0] {
|
||||||
case "VERSION_NAME":
|
case "VERSION_NAME":
|
||||||
if propPair[1] != newVersion {
|
if propPair[1] != newVersion.String() {
|
||||||
versionUpdated = true
|
versionUpdated = true
|
||||||
propPair[1] = newVersion
|
propPair[1] = newVersion.String()
|
||||||
log.Info("updated version to ", newVersion)
|
log.Info("updated version to ", newVersion.String())
|
||||||
}
|
}
|
||||||
case "GO_VERSION":
|
case "GO_VERSION":
|
||||||
if propPair[1] != runtime.Version() {
|
if propPair[1] != runtime.Version() {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -14,22 +13,9 @@ import (
|
|||||||
"howett.net/plist"
|
"howett.net/plist"
|
||||||
)
|
)
|
||||||
|
|
||||||
var flagRunInCI bool
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.BoolVar(&flagRunInCI, "ci", false, "Run in CI")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
|
||||||
newVersion := common.Must1(build_shared.ReadTagVersion())
|
newVersion := common.Must1(build_shared.ReadTagVersion())
|
||||||
var applePath string
|
applePath, err := filepath.Abs("../sing-box-for-apple")
|
||||||
if flagRunInCI {
|
|
||||||
applePath = "clients/apple"
|
|
||||||
} else {
|
|
||||||
applePath = "../sing-box-for-apple"
|
|
||||||
}
|
|
||||||
applePath, err := filepath.Abs(applePath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,15 +30,14 @@ func NewClient(ctx context.Context, serverAddress string, options option.Outboun
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if options.ECH != nil && options.ECH.Enabled {
|
if options.ECH != nil && options.ECH.Enabled {
|
||||||
if options.ECH.PQSignatureSchemesEnabled || options.ECH.DynamicRecordSizingDisabled {
|
return NewECHClient(ctx, serverAddress, options)
|
||||||
return NewECHClient(ctx, serverAddress, options)
|
|
||||||
}
|
|
||||||
} else if options.Reality != nil && options.Reality.Enabled {
|
} else if options.Reality != nil && options.Reality.Enabled {
|
||||||
return NewRealityClient(ctx, serverAddress, options)
|
return NewRealityClient(ctx, serverAddress, options)
|
||||||
} else if options.UTLS != nil && options.UTLS.Enabled {
|
} else if options.UTLS != nil && options.UTLS.Enabled {
|
||||||
return NewUTLSClient(ctx, serverAddress, options)
|
return NewUTLSClient(ctx, serverAddress, options)
|
||||||
|
} else {
|
||||||
|
return NewSTDClient(ctx, serverAddress, options)
|
||||||
}
|
}
|
||||||
return NewSTDClient(ctx, serverAddress, options)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
|
func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
|
||||||
|
cftls "github.com/sagernet/cloudflare-tls"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
"github.com/cloudflare/circl/hpke"
|
"github.com/cloudflare/circl/hpke"
|
||||||
@@ -58,6 +59,7 @@ func ECHKeygenDefault(serverName string, pqSignatureSchemesEnabled bool) (config
|
|||||||
|
|
||||||
type echKeyConfigPair struct {
|
type echKeyConfigPair struct {
|
||||||
id uint8
|
id uint8
|
||||||
|
key cftls.EXP_ECHKey
|
||||||
rawKey []byte
|
rawKey []byte
|
||||||
conf myECHKeyConfig
|
conf myECHKeyConfig
|
||||||
rawConf []byte
|
rawConf []byte
|
||||||
@@ -151,13 +153,14 @@ func echKeygen(version uint16, serverName string, conf []myECHKeyConfig, suite [
|
|||||||
sk = be.AppendUint16(sk, uint16(len(b)))
|
sk = be.AppendUint16(sk, uint16(len(b)))
|
||||||
sk = append(sk, b...)
|
sk = append(sk, b...)
|
||||||
|
|
||||||
cfECHKeys, err := UnmarshalECHKeys(sk)
|
cfECHKeys, err := cftls.EXP_UnmarshalECHKeys(sk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "bug: can't parse generated ECH server key")
|
return nil, E.Cause(err, "bug: can't parse generated ECH server key")
|
||||||
}
|
}
|
||||||
if len(cfECHKeys) != 1 {
|
if len(cfECHKeys) != 1 {
|
||||||
return nil, E.New("bug: unexpected server key count")
|
return nil, E.New("bug: unexpected server key count")
|
||||||
}
|
}
|
||||||
|
pair.key = cfECHKeys[0]
|
||||||
pair.rawKey = sk
|
pair.rawKey = sk
|
||||||
|
|
||||||
pairs = append(pairs, pair)
|
pairs = append(pairs, pair)
|
||||||
|
|||||||
@@ -17,13 +17,12 @@ func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLS
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if options.ECH != nil && options.ECH.Enabled {
|
if options.ECH != nil && options.ECH.Enabled {
|
||||||
if options.ECH.PQSignatureSchemesEnabled || options.ECH.DynamicRecordSizingDisabled {
|
return NewECHServer(ctx, logger, options)
|
||||||
return NewECHServer(ctx, logger, options)
|
|
||||||
}
|
|
||||||
} else if options.Reality != nil && options.Reality.Enabled {
|
} else if options.Reality != nil && options.Reality.Enabled {
|
||||||
return NewRealityServer(ctx, logger, options)
|
return NewRealityServer(ctx, logger, options)
|
||||||
|
} else {
|
||||||
|
return NewSTDServer(ctx, logger, options)
|
||||||
}
|
}
|
||||||
return NewSTDServer(ctx, logger, options)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) {
|
func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) {
|
||||||
|
|||||||
@@ -4,25 +4,16 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-dns"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/ntp"
|
"github.com/sagernet/sing/common/ntp"
|
||||||
aTLS "github.com/sagernet/sing/common/tls"
|
|
||||||
"github.com/sagernet/sing/service"
|
|
||||||
|
|
||||||
mDNS "github.com/miekg/dns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ ConfigCompat = (*STDClientConfig)(nil)
|
|
||||||
|
|
||||||
type STDClientConfig struct {
|
type STDClientConfig struct {
|
||||||
config *tls.Config
|
config *tls.Config
|
||||||
}
|
}
|
||||||
@@ -55,63 +46,6 @@ func (s *STDClientConfig) Clone() Config {
|
|||||||
return &STDClientConfig{s.config.Clone()}
|
return &STDClientConfig{s.config.Clone()}
|
||||||
}
|
}
|
||||||
|
|
||||||
type STDECHClientConfig struct {
|
|
||||||
STDClientConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *STDClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (aTLS.Conn, error) {
|
|
||||||
if len(s.config.EncryptedClientHelloConfigList) == 0 {
|
|
||||||
message := &mDNS.Msg{
|
|
||||||
MsgHdr: mDNS.MsgHdr{
|
|
||||||
RecursionDesired: true,
|
|
||||||
},
|
|
||||||
Question: []mDNS.Question{
|
|
||||||
{
|
|
||||||
Name: mDNS.Fqdn(s.config.ServerName),
|
|
||||||
Qtype: mDNS.TypeHTTPS,
|
|
||||||
Qclass: mDNS.ClassINET,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dnsRouter := service.FromContext[adapter.Router](ctx)
|
|
||||||
response, err := dnsRouter.Exchange(ctx, message)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "fetch ECH config list")
|
|
||||||
}
|
|
||||||
if response.Rcode != mDNS.RcodeSuccess {
|
|
||||||
return nil, E.Cause(dns.RCodeError(response.Rcode), "fetch ECH config list")
|
|
||||||
}
|
|
||||||
for _, rr := range response.Answer {
|
|
||||||
switch resource := rr.(type) {
|
|
||||||
case *mDNS.HTTPS:
|
|
||||||
for _, value := range resource.Value {
|
|
||||||
if value.Key().String() == "ech" {
|
|
||||||
echConfigList, err := base64.StdEncoding.DecodeString(value.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "decode ECH config")
|
|
||||||
}
|
|
||||||
s.config.EncryptedClientHelloConfigList = echConfigList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, E.New("no ECH config found in DNS records")
|
|
||||||
}
|
|
||||||
tlsConn, err := s.Client(conn)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = tlsConn.HandshakeContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tlsConn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *STDECHClientConfig) Clone() Config {
|
|
||||||
return &STDECHClientConfig{STDClientConfig{s.config.Clone()}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSTDClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
func NewSTDClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
var serverName string
|
var serverName string
|
||||||
if options.ServerName != "" {
|
if options.ServerName != "" {
|
||||||
@@ -194,21 +128,5 @@ func NewSTDClient(ctx context.Context, serverAddress string, options option.Outb
|
|||||||
}
|
}
|
||||||
tlsConfig.RootCAs = certPool
|
tlsConfig.RootCAs = certPool
|
||||||
}
|
}
|
||||||
if options.ECH != nil && options.ECH.Enabled {
|
|
||||||
var echConfig []byte
|
|
||||||
if len(options.ECH.Config) > 0 {
|
|
||||||
echConfig = []byte(strings.Join(options.ECH.Config, "\n"))
|
|
||||||
} else if options.ECH.ConfigPath != "" {
|
|
||||||
content, err := os.ReadFile(options.ECH.ConfigPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "read ECH config")
|
|
||||||
}
|
|
||||||
echConfig = content
|
|
||||||
}
|
|
||||||
if echConfig != nil {
|
|
||||||
tlsConfig.EncryptedClientHelloConfigList = echConfig
|
|
||||||
}
|
|
||||||
return &STDECHClientConfig{STDClientConfig{&tlsConfig}}, nil
|
|
||||||
}
|
|
||||||
return &STDClientConfig{&tlsConfig}, nil
|
return &STDClientConfig{&tlsConfig}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package tls
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/pem"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -15,8 +14,6 @@ import (
|
|||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/ntp"
|
"github.com/sagernet/sing/common/ntp"
|
||||||
|
|
||||||
"golang.org/x/crypto/cryptobyte"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var errInsecureUnused = E.New("tls: insecure unused")
|
var errInsecureUnused = E.New("tls: insecure unused")
|
||||||
@@ -241,31 +238,6 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
|
|||||||
tlsConfig.Certificates = []tls.Certificate{keyPair}
|
tlsConfig.Certificates = []tls.Certificate{keyPair}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if options.ECH != nil && options.ECH.Enabled {
|
|
||||||
var echKey []byte
|
|
||||||
if len(options.ECH.Key) > 0 {
|
|
||||||
echKey = []byte(strings.Join(options.ECH.Key, "\n"))
|
|
||||||
} else if options.ECH.KeyPath != "" {
|
|
||||||
content, err := os.ReadFile(options.ECH.KeyPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "read ECH key")
|
|
||||||
}
|
|
||||||
echKey = content
|
|
||||||
} else {
|
|
||||||
return nil, E.New("missing ECH key")
|
|
||||||
}
|
|
||||||
|
|
||||||
block, rest := pem.Decode(echKey)
|
|
||||||
if block == nil || block.Type != "ECH KEYS" || len(rest) > 0 {
|
|
||||||
return nil, E.New("invalid ECH keys pem")
|
|
||||||
}
|
|
||||||
|
|
||||||
echKeys, err := UnmarshalECHKeys(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "parse ECH keys")
|
|
||||||
}
|
|
||||||
tlsConfig.EncryptedClientHelloKeys = echKeys
|
|
||||||
}
|
|
||||||
return &STDServerConfig{
|
return &STDServerConfig{
|
||||||
config: tlsConfig,
|
config: tlsConfig,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@@ -276,22 +248,3 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
|
|||||||
keyPath: options.KeyPath,
|
keyPath: options.KeyPath,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnmarshalECHKeys(raw []byte) ([]tls.EncryptedClientHelloKey, error) {
|
|
||||||
var keys []tls.EncryptedClientHelloKey
|
|
||||||
rawString := cryptobyte.String(raw)
|
|
||||||
for !rawString.Empty() {
|
|
||||||
var key tls.EncryptedClientHelloKey
|
|
||||||
if !rawString.ReadUint16LengthPrefixed((*cryptobyte.String)(&key.PrivateKey)) {
|
|
||||||
return nil, E.New("error parsing private key")
|
|
||||||
}
|
|
||||||
if !rawString.ReadUint16LengthPrefixed((*cryptobyte.String)(&key.Config)) {
|
|
||||||
return nil, E.New("error parsing config")
|
|
||||||
}
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
if len(keys) == 0 {
|
|
||||||
return nil, E.New("empty ECH keys")
|
|
||||||
}
|
|
||||||
return keys, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
//go:build android && debug
|
|
||||||
|
|
||||||
package constant
|
|
||||||
|
|
||||||
// TODO: remove after fixed
|
|
||||||
// https://github.com/golang/go/issues/68760
|
|
||||||
|
|
||||||
const FixAndroidStack = true
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
//go:build !(android && debug)
|
|
||||||
|
|
||||||
package constant
|
|
||||||
|
|
||||||
const FixAndroidStack = false
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 1.11.0-beta.9
|
#### 1.11.0-beta.6
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func groupRouter(server *Server) http.Handler {
|
|||||||
|
|
||||||
func getGroups(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
func getGroups(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
groups := common.Map(common.Filter(server.outbound.Outbounds(), func(it adapter.Outbound) bool {
|
groups := common.Map(common.Filter(server.outboundManager.Outbounds(), func(it adapter.Outbound) bool {
|
||||||
_, isGroup := it.(adapter.OutboundGroup)
|
_, isGroup := it.(adapter.OutboundGroup)
|
||||||
return isGroup
|
return isGroup
|
||||||
}), func(it adapter.Outbound) *badjson.JSONObject {
|
}), func(it adapter.Outbound) *badjson.JSONObject {
|
||||||
@@ -86,7 +86,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
|||||||
result, err = urlTestGroup.URLTest(ctx)
|
result, err = urlTestGroup.URLTest(ctx)
|
||||||
} else {
|
} else {
|
||||||
outbounds := common.FilterNotNil(common.Map(outboundGroup.All(), func(it string) adapter.Outbound {
|
outbounds := common.FilterNotNil(common.Map(outboundGroup.All(), func(it string) adapter.Outbound {
|
||||||
itOutbound, _ := server.outbound.Outbound(it)
|
itOutbound, _ := server.outboundManager.Outbound(it)
|
||||||
return itOutbound
|
return itOutbound
|
||||||
}))
|
}))
|
||||||
b, _ := batch.New(ctx, batch.WithConcurrencyNum[any](10))
|
b, _ := batch.New(ctx, batch.WithConcurrencyNum[any](10))
|
||||||
@@ -100,7 +100,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
checked[realTag] = true
|
checked[realTag] = true
|
||||||
p, loaded := server.outbound.Outbound(realTag)
|
p, loaded := server.outboundManager.Outbound(realTag)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func findProxyByName(server *Server) func(next http.Handler) http.Handler {
|
|||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
name := r.Context().Value(CtxKeyProxyName).(string)
|
name := r.Context().Value(CtxKeyProxyName).(string)
|
||||||
proxy, exist := server.outbound.Outbound(name)
|
proxy, exist := server.outboundManager.Outbound(name)
|
||||||
if !exist {
|
if !exist {
|
||||||
render.Status(r, http.StatusNotFound)
|
render.Status(r, http.StatusNotFound)
|
||||||
render.JSON(w, r, ErrNotFound)
|
render.JSON(w, r, ErrNotFound)
|
||||||
@@ -86,14 +86,9 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
|
|||||||
func getProxies(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
func getProxies(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
var proxyMap badjson.JSONObject
|
var proxyMap badjson.JSONObject
|
||||||
outbounds := common.Filter(server.outbound.Outbounds(), func(detour adapter.Outbound) bool {
|
outbounds := common.Filter(server.outboundManager.Outbounds(), func(detour adapter.Outbound) bool {
|
||||||
return detour.Tag() != ""
|
return detour.Tag() != ""
|
||||||
})
|
})
|
||||||
outbounds = append(outbounds, common.Map(common.Filter(server.endpoint.Endpoints(), func(detour adapter.Endpoint) bool {
|
|
||||||
return detour.Tag() != ""
|
|
||||||
}), func(it adapter.Endpoint) adapter.Outbound {
|
|
||||||
return it
|
|
||||||
})...)
|
|
||||||
|
|
||||||
allProxies := make([]string, 0, len(outbounds))
|
allProxies := make([]string, 0, len(outbounds))
|
||||||
|
|
||||||
@@ -105,7 +100,7 @@ func getProxies(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
|||||||
allProxies = append(allProxies, detour.Tag())
|
allProxies = append(allProxies, detour.Tag())
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultTag := server.outbound.Default().Tag()
|
defaultTag := server.outboundManager.Default().Tag()
|
||||||
|
|
||||||
sort.SliceStable(allProxies, func(i, j int) bool {
|
sort.SliceStable(allProxies, func(i, j int) bool {
|
||||||
return allProxies[i] == defaultTag
|
return allProxies[i] == defaultTag
|
||||||
|
|||||||
@@ -40,17 +40,16 @@ func init() {
|
|||||||
var _ adapter.ClashServer = (*Server)(nil)
|
var _ adapter.ClashServer = (*Server)(nil)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
router adapter.Router
|
router adapter.Router
|
||||||
outbound adapter.OutboundManager
|
outboundManager adapter.OutboundManager
|
||||||
endpoint adapter.EndpointManager
|
logger log.Logger
|
||||||
logger log.Logger
|
httpServer *http.Server
|
||||||
httpServer *http.Server
|
trafficManager *trafficontrol.Manager
|
||||||
trafficManager *trafficontrol.Manager
|
urlTestHistory *urltest.HistoryStorage
|
||||||
urlTestHistory *urltest.HistoryStorage
|
mode string
|
||||||
mode string
|
modeList []string
|
||||||
modeList []string
|
modeUpdateHook chan<- struct{}
|
||||||
modeUpdateHook chan<- struct{}
|
|
||||||
|
|
||||||
externalController bool
|
externalController bool
|
||||||
externalUI string
|
externalUI string
|
||||||
@@ -62,11 +61,10 @@ func NewServer(ctx context.Context, logFactory log.ObservableFactory, options op
|
|||||||
trafficManager := trafficontrol.NewManager()
|
trafficManager := trafficontrol.NewManager()
|
||||||
chiRouter := chi.NewRouter()
|
chiRouter := chi.NewRouter()
|
||||||
s := &Server{
|
s := &Server{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
router: service.FromContext[adapter.Router](ctx),
|
router: service.FromContext[adapter.Router](ctx),
|
||||||
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
outboundManager: service.FromContext[adapter.OutboundManager](ctx),
|
||||||
endpoint: service.FromContext[adapter.EndpointManager](ctx),
|
logger: logFactory.NewLogger("clash-api"),
|
||||||
logger: logFactory.NewLogger("clash-api"),
|
|
||||||
httpServer: &http.Server{
|
httpServer: &http.Server{
|
||||||
Addr: options.ExternalController,
|
Addr: options.ExternalController,
|
||||||
Handler: chiRouter,
|
Handler: chiRouter,
|
||||||
@@ -244,11 +242,11 @@ func (s *Server) TrafficManager() *trafficontrol.Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RoutedConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, matchedRule adapter.Rule, matchOutbound adapter.Outbound) net.Conn {
|
func (s *Server) RoutedConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, matchedRule adapter.Rule, matchOutbound adapter.Outbound) net.Conn {
|
||||||
return trafficontrol.NewTCPTracker(conn, s.trafficManager, metadata, s.outbound, matchedRule, matchOutbound)
|
return trafficontrol.NewTCPTracker(conn, s.trafficManager, metadata, s.outboundManager, matchedRule, matchOutbound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, matchedRule adapter.Rule, matchOutbound adapter.Outbound) N.PacketConn {
|
func (s *Server) RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, matchedRule adapter.Rule, matchOutbound adapter.Outbound) N.PacketConn {
|
||||||
return trafficontrol.NewUDPTracker(conn, s.trafficManager, metadata, s.outbound, matchedRule, matchOutbound)
|
return trafficontrol.NewUDPTracker(conn, s.trafficManager, metadata, s.outboundManager, matchedRule, matchOutbound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func authentication(serverSecret string) func(next http.Handler) http.Handler {
|
func authentication(serverSecret string) func(next http.Handler) http.Handler {
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ func (s *Server) downloadExternalUI() error {
|
|||||||
s.logger.Info("downloading external ui")
|
s.logger.Info("downloading external ui")
|
||||||
var detour adapter.Outbound
|
var detour adapter.Outbound
|
||||||
if s.externalUIDownloadDetour != "" {
|
if s.externalUIDownloadDetour != "" {
|
||||||
outbound, loaded := s.outbound.Outbound(s.externalUIDownloadDetour)
|
outbound, loaded := s.outboundManager.Outbound(s.externalUIDownloadDetour)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
return E.New("detour outbound not found: ", s.externalUIDownloadDetour)
|
return E.New("detour outbound not found: ", s.externalUIDownloadDetour)
|
||||||
}
|
}
|
||||||
detour = outbound
|
detour = outbound
|
||||||
} else {
|
} else {
|
||||||
outbound := s.outbound.Default()
|
outbound := s.outboundManager.Default()
|
||||||
detour = outbound
|
detour = outbound
|
||||||
}
|
}
|
||||||
httpClient := &http.Client{
|
httpClient := &http.Client{
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
@@ -114,24 +113,11 @@ func (c *CommandClient) Connect() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if C.FixAndroidStack {
|
c.handler.Connected()
|
||||||
go func() {
|
c.handler.InitializeClashMode(newIterator(modeList), currentMode)
|
||||||
c.handler.Connected()
|
|
||||||
c.handler.InitializeClashMode(newIterator(modeList), currentMode)
|
|
||||||
if len(modeList) == 0 {
|
|
||||||
conn.Close()
|
|
||||||
c.handler.Disconnected(os.ErrInvalid.Error())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
c.handler.Connected()
|
|
||||||
c.handler.InitializeClashMode(newIterator(modeList), currentMode)
|
|
||||||
if len(modeList) == 0 {
|
|
||||||
conn.Close()
|
|
||||||
c.handler.Disconnected(os.ErrInvalid.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(modeList) == 0 {
|
if len(modeList) == 0 {
|
||||||
|
conn.Close()
|
||||||
|
c.handler.Disconnected(os.ErrInvalid.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
go c.handleModeConn(conn)
|
go c.handleModeConn(conn)
|
||||||
|
|||||||
@@ -130,17 +130,17 @@ func (s *platformInterfaceStub) SendNotification(notification *platform.Notifica
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FormatConfig(configContent string) (*StringBox, error) {
|
func FormatConfig(configContent string) (string, error) {
|
||||||
options, err := parseConfig(box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry()), configContent)
|
options, err := parseConfig(box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry(), include.EndpointRegistry()), configContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
encoder := json.NewEncoder(&buffer)
|
encoder := json.NewEncoder(&buffer)
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
err = encoder.Encode(options)
|
err = encoder.Encode(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
return wrapString(buffer.String()), nil
|
return buffer.String(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ type HTTPRequest interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HTTPResponse interface {
|
type HTTPResponse interface {
|
||||||
GetContent() (*StringBox, error)
|
GetContent() ([]byte, error)
|
||||||
|
GetContentString() (string, error)
|
||||||
WriteTo(path string) error
|
WriteTo(path string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,22 +210,27 @@ type httpResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpResponse) errorString() string {
|
func (h *httpResponse) errorString() string {
|
||||||
content, err := h.GetContent()
|
content, err := h.GetContentString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Sprint("HTTP ", h.Status)
|
return fmt.Sprint("HTTP ", h.Status)
|
||||||
}
|
}
|
||||||
return fmt.Sprint("HTTP ", h.Status, ": ", content)
|
return fmt.Sprint("HTTP ", h.Status, ": ", content)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpResponse) GetContent() (*StringBox, error) {
|
func (h *httpResponse) GetContent() ([]byte, error) {
|
||||||
h.getContentOnce.Do(func() {
|
h.getContentOnce.Do(func() {
|
||||||
defer h.Body.Close()
|
defer h.Body.Close()
|
||||||
h.content, h.contentError = io.ReadAll(h.Body)
|
h.content, h.contentError = io.ReadAll(h.Body)
|
||||||
})
|
})
|
||||||
if h.contentError != nil {
|
return h.content, h.contentError
|
||||||
return nil, h.contentError
|
}
|
||||||
|
|
||||||
|
func (h *httpResponse) GetContentString() (string, error) {
|
||||||
|
content, err := h.GetContent()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
return wrapString(string(h.content)), nil
|
return string(content), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpResponse) WriteTo(path string) error {
|
func (h *httpResponse) WriteTo(path string) error {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
@@ -56,14 +55,6 @@ func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Eleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
|
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
|
||||||
if C.FixAndroidStack {
|
|
||||||
go m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
|
|
||||||
} else {
|
|
||||||
m.updateDefaultInterface(interfaceName, interfaceIndex32, isExpensive, isConstrained)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *platformDefaultInterfaceMonitor) updateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
|
|
||||||
m.isExpensive = isExpensive
|
m.isExpensive = isExpensive
|
||||||
m.isConstrained = isConstrained
|
m.isConstrained = isConstrained
|
||||||
err := m.networkManager.UpdateInterfaces()
|
err := m.networkManager.UpdateInterfaces()
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package libbox
|
|
||||||
|
|
||||||
// https://github.com/golang/go/issues/46893
|
|
||||||
// TODO: remove after `bulkBarrierPreWrite: unaligned arguments` fixed
|
|
||||||
|
|
||||||
type StringBox struct {
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapString(value string) *StringBox {
|
|
||||||
return &StringBox{Value: value}
|
|
||||||
}
|
|
||||||
@@ -81,36 +81,23 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Start() error {
|
func (s *BoxService) Start() error {
|
||||||
if C.FixAndroidStack {
|
return s.instance.Start()
|
||||||
var err error
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
err = s.instance.Start()
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
<-done
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
return s.instance.Start()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Close() error {
|
func (s *BoxService) Close() error {
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
case <-time.After(C.FatalStopTimeout):
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}()
|
||||||
s.cancel()
|
s.cancel()
|
||||||
s.urlTestHistoryStorage.Close()
|
s.urlTestHistoryStorage.Close()
|
||||||
var err error
|
return s.instance.Close()
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
err = s.instance.Close()
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-done:
|
|
||||||
return err
|
|
||||||
case <-time.After(C.FatalStopTimeout):
|
|
||||||
os.Exit(1)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) NeedWIFIState() bool {
|
func (s *BoxService) NeedWIFIState() bool {
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ func ClearServiceError() {
|
|||||||
os.Remove(serviceErrorPath())
|
os.Remove(serviceErrorPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadServiceError() (*StringBox, error) {
|
func ReadServiceError() (string, error) {
|
||||||
data, err := os.ReadFile(serviceErrorPath())
|
data, err := os.ReadFile(serviceErrorPath())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
os.Remove(serviceErrorPath())
|
os.Remove(serviceErrorPath())
|
||||||
}
|
}
|
||||||
return wrapString(string(data)), err
|
return string(data), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteServiceError(message string) error {
|
func WriteServiceError(message string) error {
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -25,7 +25,7 @@ require (
|
|||||||
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
|
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
|
||||||
github.com/sagernet/quic-go v0.48.2-beta.1
|
github.com/sagernet/quic-go v0.48.2-beta.1
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||||
github.com/sagernet/sing v0.6.0-beta.6
|
github.com/sagernet/sing v0.6.0-beta.5
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1
|
github.com/sagernet/sing-dns v0.4.0-beta.1
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1
|
github.com/sagernet/sing-mux v0.3.0-alpha.1
|
||||||
github.com/sagernet/sing-quic v0.4.0-alpha.4
|
github.com/sagernet/sing-quic v0.4.0-alpha.4
|
||||||
@@ -36,7 +36,7 @@ require (
|
|||||||
github.com/sagernet/sing-vmess v0.2.0-beta.1
|
github.com/sagernet/sing-vmess v0.2.0-beta.1
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||||
github.com/sagernet/utls v1.6.7
|
github.com/sagernet/utls v1.6.7
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5
|
github.com/sagernet/wireguard-go v0.0.1-beta.4
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -110,8 +110,8 @@ github.com/sagernet/quic-go v0.48.2-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/
|
|||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||||
github.com/sagernet/sing v0.6.0-beta.6 h1:IFnTCG06Z5rLMZJqw1ZmDncDl2N9gsVw0MGvgakrpg8=
|
github.com/sagernet/sing v0.6.0-beta.5 h1:RD2j8WmJsvAbbBkAlJWaiYmnd+v/JohBiweoew7kMwo=
|
||||||
github.com/sagernet/sing v0.6.0-beta.6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.0-beta.5/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1 h1:W1XkdhigwxDOMgMDVB+9kdomCpb7ExsZfB4acPcTZFY=
|
github.com/sagernet/sing-dns v0.4.0-beta.1 h1:W1XkdhigwxDOMgMDVB+9kdomCpb7ExsZfB4acPcTZFY=
|
||||||
github.com/sagernet/sing-dns v0.4.0-beta.1/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8=
|
github.com/sagernet/sing-dns v0.4.0-beta.1/go.mod h1:8wuFcoFkWM4vJuQyg8e97LyvDwe0/Vl7G839WLcKDs8=
|
||||||
github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
|
github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
|
||||||
@@ -132,8 +132,8 @@ github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxe
|
|||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||||
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5 h1:aBEsxJUMEONwOZqKPIkuAcv4zJV5p6XlzEN04CF0FXc=
|
github.com/sagernet/wireguard-go v0.0.1-beta.4 h1:8uyM5fxfEXdu4RH05uOK+v25i3lTNdCYMPSAUJ14FnI=
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
github.com/sagernet/wireguard-go v0.0.1-beta.4/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata a
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = http.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), h.authenticator, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, onClose)
|
err = http.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), h.authenticator, nil, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, onClose)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
N.CloseOnHandshakeFailure(conn, onClose, err)
|
N.CloseOnHandshakeFailure(conn, onClose, err)
|
||||||
h.logger.ErrorContext(ctx, E.Cause(err, "process connection from ", metadata.Source))
|
h.logger.ErrorContext(ctx, E.Cause(err, "process connection from ", metadata.Source))
|
||||||
|
|||||||
@@ -85,9 +85,9 @@ func (h *Inbound) newConnection(ctx context.Context, conn net.Conn, metadata ada
|
|||||||
}
|
}
|
||||||
switch headerBytes[0] {
|
switch headerBytes[0] {
|
||||||
case socks4.Version, socks5.Version:
|
case socks4.Version, socks5.Version:
|
||||||
return socks.HandleConnectionEx(ctx, conn, reader, h.authenticator, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, onClose)
|
return socks.HandleConnectionEx(ctx, conn, reader, h.authenticator, nil, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, metadata.Destination, onClose)
|
||||||
default:
|
default:
|
||||||
return http.HandleConnectionEx(ctx, conn, reader, h.authenticator, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, onClose)
|
return http.HandleConnectionEx(ctx, conn, reader, h.authenticator, nil, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, onClose)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (h *Inbound) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||||
err := socks.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), h.authenticator, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, onClose)
|
err := socks.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), h.authenticator, nil, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, metadata.Destination, onClose)
|
||||||
N.CloseOnHandshakeFailure(conn, onClose, err)
|
N.CloseOnHandshakeFailure(conn, onClose, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if E.IsClosedOrCanceled(err) {
|
if E.IsClosedOrCanceled(err) {
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ func (l *ProxyListener) acceptLoop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *ProxyListener) accept(ctx context.Context, conn *net.TCPConn) error {
|
func (l *ProxyListener) accept(ctx context.Context, conn *net.TCPConn) error {
|
||||||
return socks.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), l.authenticator, l, M.SocksaddrFromNet(conn.RemoteAddr()), nil)
|
return socks.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), l.authenticator, nil, l, M.SocksaddrFromNet(conn.RemoteAddr()), M.Socksaddr{}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ProxyListener) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
func (l *ProxyListener) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||||
|
|||||||
@@ -61,25 +61,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
peers := common.Map(options.Peers, func(it option.LegacyWireGuardPeer) wireguard.PeerOptions {
|
|
||||||
return wireguard.PeerOptions{
|
|
||||||
Endpoint: it.ServerOptions.Build(),
|
|
||||||
PublicKey: it.PublicKey,
|
|
||||||
PreSharedKey: it.PreSharedKey,
|
|
||||||
AllowedIPs: it.AllowedIPs,
|
|
||||||
// PersistentKeepaliveInterval: time.Duration(it.PersistentKeepaliveInterval),
|
|
||||||
Reserved: it.Reserved,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if len(peers) == 0 {
|
|
||||||
peers = []wireguard.PeerOptions{{
|
|
||||||
Endpoint: options.ServerOptions.Build(),
|
|
||||||
PublicKey: options.PeerPublicKey,
|
|
||||||
PreSharedKey: options.PreSharedKey,
|
|
||||||
AllowedIPs: []netip.Prefix{netip.PrefixFrom(netip.IPv4Unspecified(), 0), netip.PrefixFrom(netip.IPv6Unspecified(), 0)},
|
|
||||||
Reserved: options.Reserved,
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
|
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
@@ -101,7 +82,16 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
}
|
}
|
||||||
return endpointAddresses[0], nil
|
return endpointAddresses[0], nil
|
||||||
},
|
},
|
||||||
Peers: peers,
|
Peers: common.Map(options.Peers, func(it option.LegacyWireGuardPeer) wireguard.PeerOptions {
|
||||||
|
return wireguard.PeerOptions{
|
||||||
|
Endpoint: it.ServerOptions.Build(),
|
||||||
|
PublicKey: it.PublicKey,
|
||||||
|
PreSharedKey: it.PreSharedKey,
|
||||||
|
AllowedIPs: it.AllowedIPs,
|
||||||
|
// PersistentKeepaliveInterval: time.Duration(it.PersistentKeepaliveInterval),
|
||||||
|
Reserved: it.Reserved,
|
||||||
|
}
|
||||||
|
}),
|
||||||
Workers: options.Workers,
|
Workers: options.Workers,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -461,12 +461,8 @@ match:
|
|||||||
break match
|
break match
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !preMatch && inputPacketConn != nil && !metadata.Destination.IsFqdn() && !metadata.Destination.Addr.IsGlobalUnicast() {
|
if !preMatch && metadata.Destination.Addr.IsUnspecified() {
|
||||||
var timeout time.Duration
|
newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{}, inputConn, inputPacketConn)
|
||||||
if metadata.InboundType == C.TypeSOCKS {
|
|
||||||
timeout = C.TCPTimeout
|
|
||||||
}
|
|
||||||
newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{Timeout: timeout}, inputConn, inputPacketConn)
|
|
||||||
if newErr != nil {
|
if newErr != nil {
|
||||||
fatalErr = newErr
|
fatalErr = newErr
|
||||||
return
|
return
|
||||||
@@ -562,7 +558,8 @@ func (r *Router) actionSniff(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !metadata.Destination.Addr.IsGlobalUnicast() {
|
// TODO: maybe always override destination
|
||||||
|
if metadata.Destination.Addr.IsUnspecified() {
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
}
|
}
|
||||||
if len(packetBuffers) > 0 {
|
if len(packetBuffers) > 0 {
|
||||||
|
|||||||
@@ -120,19 +120,9 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
if len(message.Question) != 1 {
|
if len(message.Question) > 0 {
|
||||||
r.dnsLogger.WarnContext(ctx, "bad question size: ", len(message.Question))
|
r.dnsLogger.DebugContext(ctx, "exchange ", formatQuestion(message.Question[0].String()))
|
||||||
responseMessage := mDNS.Msg{
|
|
||||||
MsgHdr: mDNS.MsgHdr{
|
|
||||||
Id: message.Id,
|
|
||||||
Response: true,
|
|
||||||
Rcode: mDNS.RcodeFormatError,
|
|
||||||
},
|
|
||||||
Question: message.Question,
|
|
||||||
}
|
|
||||||
return &responseMessage, nil
|
|
||||||
}
|
}
|
||||||
r.dnsLogger.DebugContext(ctx, "exchange ", formatQuestion(message.Question[0].String()))
|
|
||||||
var (
|
var (
|
||||||
response *mDNS.Msg
|
response *mDNS.Msg
|
||||||
cached bool
|
cached bool
|
||||||
@@ -144,14 +134,16 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er
|
|||||||
var metadata *adapter.InboundContext
|
var metadata *adapter.InboundContext
|
||||||
ctx, metadata = adapter.ExtendContext(ctx)
|
ctx, metadata = adapter.ExtendContext(ctx)
|
||||||
metadata.Destination = M.Socksaddr{}
|
metadata.Destination = M.Socksaddr{}
|
||||||
metadata.QueryType = message.Question[0].Qtype
|
if len(message.Question) > 0 {
|
||||||
switch metadata.QueryType {
|
metadata.QueryType = message.Question[0].Qtype
|
||||||
case mDNS.TypeA:
|
switch metadata.QueryType {
|
||||||
metadata.IPVersion = 4
|
case mDNS.TypeA:
|
||||||
case mDNS.TypeAAAA:
|
metadata.IPVersion = 4
|
||||||
metadata.IPVersion = 6
|
case mDNS.TypeAAAA:
|
||||||
|
metadata.IPVersion = 6
|
||||||
|
}
|
||||||
|
metadata.Domain = fqdnToDomain(message.Question[0].Name)
|
||||||
}
|
}
|
||||||
metadata.Domain = fqdnToDomain(message.Question[0].Name)
|
|
||||||
var (
|
var (
|
||||||
options dns.QueryOptions
|
options dns.QueryOptions
|
||||||
rule adapter.DNSRule
|
rule adapter.DNSRule
|
||||||
@@ -210,7 +202,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if r.dnsReverseMapping != nil && response != nil && len(response.Answer) > 0 {
|
if r.dnsReverseMapping != nil && len(message.Question) > 0 && response != nil && len(response.Answer) > 0 {
|
||||||
if _, isFakeIP := transport.(adapter.FakeIPTransport); !isFakeIP {
|
if _, isFakeIP := transport.(adapter.FakeIPTransport); !isFakeIP {
|
||||||
for _, answer := range response.Answer {
|
for _, answer := range response.Answer {
|
||||||
switch record := answer.(type) {
|
switch record := answer.(type) {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ require (
|
|||||||
github.com/sagernet/sing-vmess v0.2.0-beta.1 // indirect
|
github.com/sagernet/sing-vmess v0.2.0-beta.1 // indirect
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
||||||
github.com/sagernet/utls v1.6.7 // indirect
|
github.com/sagernet/utls v1.6.7 // indirect
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5 // indirect
|
github.com/sagernet/wireguard-go v0.0.1-beta.4 // indirect
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||||
github.com/vishvananda/netns v0.0.4 // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
|
|||||||
@@ -168,8 +168,8 @@ github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxe
|
|||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||||
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5 h1:aBEsxJUMEONwOZqKPIkuAcv4zJV5p6XlzEN04CF0FXc=
|
github.com/sagernet/wireguard-go v0.0.1-beta.4 h1:8uyM5fxfEXdu4RH05uOK+v25i3lTNdCYMPSAUJ14FnI=
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.5/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
github.com/sagernet/wireguard-go v0.0.1-beta.4/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
|||||||
@@ -150,20 +150,14 @@ func (e *Endpoint) Start(resolve bool) error {
|
|||||||
connectAddr netip.AddrPort
|
connectAddr netip.AddrPort
|
||||||
reserved [3]uint8
|
reserved [3]uint8
|
||||||
)
|
)
|
||||||
if len(e.peers) == 1 {
|
peerLen := len(e.peers)
|
||||||
|
if peerLen == 1 {
|
||||||
isConnect = true
|
isConnect = true
|
||||||
connectAddr = e.peers[0].endpoint
|
connectAddr = e.peers[0].endpoint
|
||||||
reserved = e.peers[0].reserved
|
reserved = e.peers[0].reserved
|
||||||
}
|
}
|
||||||
bind = NewClientBind(e.options.Context, e.options.Logger, e.options.Dialer, isConnect, connectAddr, reserved)
|
bind = NewClientBind(e.options.Context, e.options.Logger, e.options.Dialer, isConnect, connectAddr, reserved)
|
||||||
}
|
}
|
||||||
if isWgListener || len(e.peers) > 1 {
|
|
||||||
for _, peer := range e.peers {
|
|
||||||
if peer.reserved != [3]uint8{} {
|
|
||||||
bind.SetReservedForEndpoint(peer.endpoint, peer.reserved)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := e.tunDevice.Start()
|
err := e.tunDevice.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user