mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-07-27 16:24:08 +08:00
Compare commits
48 Commits
85ba9c44fb
...
bcc92c7ed7
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bcc92c7ed7 | ||
![]() |
5623128c14 | ||
![]() |
c0fc63542a | ||
![]() |
cc35789604 | ||
![]() |
bc3dc96777 | ||
![]() |
34193b2e79 | ||
![]() |
6c0d10c0a1 | ||
![]() |
284e147518 | ||
![]() |
3ea844baed | ||
![]() |
8d32bf986a | ||
![]() |
1701eebeb3 | ||
![]() |
2b7ec7a91d | ||
![]() |
95b2580c9e | ||
![]() |
b295295f5f | ||
![]() |
8cf92076d3 | ||
![]() |
18f291df9a | ||
![]() |
ebcceecb2b | ||
![]() |
96dc1410fb | ||
![]() |
fa2d63b9ac | ||
![]() |
4e0e42dbf7 | ||
![]() |
242afecee4 | ||
![]() |
2ff91f578d | ||
![]() |
daf2f57815 | ||
![]() |
95ad31b6f5 | ||
![]() |
c679656bfc | ||
![]() |
c9a7e5c5b3 | ||
![]() |
8b54d1136d | ||
![]() |
6b01ee1aac | ||
![]() |
7b13fce38e | ||
![]() |
41f653a4cc | ||
![]() |
6250beaacd | ||
![]() |
2a4313a48e | ||
![]() |
988a08b76c | ||
![]() |
a655c2dc1f | ||
![]() |
c2f14757c8 | ||
![]() |
6a7e61fd9e | ||
![]() |
8f1a63f3df | ||
![]() |
d2f614eeba | ||
![]() |
4e4be13506 | ||
![]() |
55491c4ded | ||
![]() |
8c574eee12 | ||
![]() |
30996c6d94 | ||
![]() |
a87583e22f | ||
![]() |
aea4470135 | ||
![]() |
54418bf9e1 | ||
![]() |
da66c0e1ea | ||
![]() |
fcb194ed15 | ||
![]() |
885e02f218 |
19
.fpm
19
.fpm
@ -1,19 +0,0 @@
|
|||||||
-s dir
|
|
||||||
--name sing-box
|
|
||||||
--category net
|
|
||||||
--license GPLv3-or-later
|
|
||||||
--description "The universal proxy platform."
|
|
||||||
--url "https://sing-box.sagernet.org/"
|
|
||||||
--maintainer "nekohasekai <contact-git@sekai.icu>"
|
|
||||||
--deb-field "Bug: https://github.com/SagerNet/sing-box/issues"
|
|
||||||
|
|
||||||
release/config/config.json=/etc/sing-box/config.json
|
|
||||||
|
|
||||||
release/config/sing-box.service=/usr/lib/systemd/system/sing-box.service
|
|
||||||
release/config/sing-box@.service=/usr/lib/systemd/system/sing-box@.service
|
|
||||||
|
|
||||||
release/completions/sing-box.bash=/usr/share/bash-completion/completions/sing-box.bash
|
|
||||||
release/completions/sing-box.fish=/usr/share/fish/vendor_completions.d/sing-box.fish
|
|
||||||
release/completions/sing-box.zsh=/usr/share/zsh/site-functions/_sing-box
|
|
||||||
|
|
||||||
LICENSE=/usr/share/licenses/sing-box/LICENSE
|
|
7
.github/setup_legacy_go.sh
vendored
7
.github/setup_legacy_go.sh
vendored
@ -1,13 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
VERSION="1.23.6"
|
VERSION="1.23.6"
|
||||||
|
|
||||||
mkdir -p $HOME/go
|
|
||||||
cd $HOME/go
|
|
||||||
wget "https://dl.google.com/go/go${VERSION}.linux-amd64.tar.gz"
|
wget "https://dl.google.com/go/go${VERSION}.linux-amd64.tar.gz"
|
||||||
tar -xzf "go${VERSION}.linux-amd64.tar.gz"
|
tar -xzf "go${VERSION}.linux-amd64.tar.gz"
|
||||||
mv go go_legacy
|
mv go $HOME/go/go_legacy
|
||||||
cd go_legacy
|
cd $HOME/go/go_legacy
|
||||||
|
|
||||||
# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557
|
# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557
|
||||||
# this patch file only works on golang1.23.x
|
# this patch file only works on golang1.23.x
|
||||||
|
255
.github/workflows/build.yml
vendored
255
.github/workflows/build.yml
vendored
@ -68,42 +68,73 @@ jobs:
|
|||||||
- calculate_version
|
- calculate_version
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ linux, windows, darwin, android ]
|
|
||||||
arch: [ "386", amd64, arm64 ]
|
|
||||||
legacy_go: [ false ]
|
|
||||||
include:
|
include:
|
||||||
- { os: linux, arch: amd64, debian: amd64, rpm: x86_64, pacman: x86_64 }
|
- name: linux_386
|
||||||
- { os: linux, arch: "386", debian: i386, rpm: i386 }
|
goos: linux
|
||||||
- { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl }
|
goarch: 386
|
||||||
- { os: linux, arch: arm, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl }
|
- name: linux_amd64
|
||||||
- { os: linux, arch: arm64, debian: arm64, rpm: aarch64, pacman: aarch64 }
|
goos: linux
|
||||||
- { os: linux, arch: mips64le, debian: mips64el, rpm: mips64el }
|
goarch: amd64
|
||||||
- { os: linux, arch: mipsle, debian: mipsel, rpm: mipsel }
|
- name: linux_arm64
|
||||||
- { os: linux, arch: s390x, debian: s390x, rpm: s390x }
|
goos: linux
|
||||||
- { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le }
|
goarch: arm64
|
||||||
- { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64 }
|
- name: linux_arm
|
||||||
- { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64 }
|
goos: linux
|
||||||
|
goarch: arm
|
||||||
- { os: windows, arch: "386", legacy_go: true }
|
goarm: 6
|
||||||
- { os: windows, arch: amd64, legacy_go: true }
|
- name: linux_arm_v7
|
||||||
|
goos: linux
|
||||||
- { os: android, arch: "386", ndk: "i686-linux-android21" }
|
goarch: arm
|
||||||
- { os: android, arch: amd64, ndk: "x86_64-linux-android21" }
|
goarm: 7
|
||||||
- { os: android, arch: arm64, ndk: "aarch64-linux-android21" }
|
- name: linux_s390x
|
||||||
- { os: android, arch: arm, ndk: "armv7a-linux-androideabi21" }
|
goos: linux
|
||||||
exclude:
|
goarch: s390x
|
||||||
- { os: darwin, arch: "386" }
|
- 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
|
||||||
|
- 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:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
if: ${{ ! matrix.legacy_go }}
|
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24
|
go-version: ^1.24
|
||||||
- name: Cache Legacy Go
|
- name: Cache legacy Go
|
||||||
if: matrix.require_legacy_go
|
if: matrix.require_legacy_go
|
||||||
id: cache-legacy-go
|
id: cache-legacy-go
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@ -111,139 +142,64 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
~/go/go_legacy
|
~/go/go_legacy
|
||||||
key: go_legacy_1236
|
key: go_legacy_1236
|
||||||
- name: Setup Legacy Go
|
- name: Setup legacy Go
|
||||||
if: matrix.legacy_go && steps.cache-legacy-go.outputs.cache-hit != 'true'
|
if: matrix.require_legacy_go && steps.cache-legacy-go.outputs.cache-hit != 'true'
|
||||||
run: |-
|
run: bash .github/setup_legacy_go.sh
|
||||||
.github/setup_legacy_go.sh
|
|
||||||
- name: Setup Legacy Go 2
|
|
||||||
if: matrix.legacy_go
|
|
||||||
run: |-
|
|
||||||
echo "PATH=$HOME/go/go_legacy/bin:$PATH" >> $GITHUB_ENV
|
|
||||||
echo "GOROOT=$HOME/go/go_legacy" >> $GITHUB_ENV
|
|
||||||
- name: Setup Android NDK
|
- name: Setup Android NDK
|
||||||
if: matrix.os == 'android'
|
if: matrix.goos == 'android'
|
||||||
uses: nttld/setup-ndk@v1
|
uses: nttld/setup-ndk@v1
|
||||||
with:
|
with:
|
||||||
ndk-version: r28
|
ndk-version: r28
|
||||||
local-cache: true
|
local-cache: true
|
||||||
|
- name: Setup Goreleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v6
|
||||||
|
with:
|
||||||
|
distribution: goreleaser-pro
|
||||||
|
version: '~> v2'
|
||||||
|
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
|
- name: Set tag
|
||||||
run: |-
|
run: |-
|
||||||
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
|
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
|
||||||
git tag v${{ needs.calculate_version.outputs.version }} -f
|
git tag v${{ needs.calculate_version.outputs.version }} -f
|
||||||
- name: Set build tags
|
|
||||||
run: |
|
|
||||||
set -xeuo pipefail
|
|
||||||
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_reality_server,with_acme,with_clash_api'
|
|
||||||
if [ ! '${{ matrix.legacy_go }}' = 'true' ]; then
|
|
||||||
TAGS="${TAGS},with_ech"
|
|
||||||
fi
|
|
||||||
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
|
|
||||||
- name: Build
|
- name: Build
|
||||||
if: matrix.os != 'android'
|
if: matrix.goos != 'android'
|
||||||
run: |
|
run: |-
|
||||||
set -xeuo pipefail
|
goreleaser release --clean --split
|
||||||
mkdir -p dist
|
|
||||||
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
|
|
||||||
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }}' \
|
|
||||||
./cmd/sing-box
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: "0"
|
GOOS: ${{ matrix.goos }}
|
||||||
GOOS: ${{ matrix.os }}
|
GOARCH: ${{ matrix.goarch }}
|
||||||
GOARCH: ${{ matrix.arch }}
|
GOPATH: ${{ env.HOME }}/go
|
||||||
GOARM: ${{ matrix.goarm }}
|
GOARM: ${{ matrix.goarm }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Build Android
|
||||||
if: matrix.os == 'android'
|
if: matrix.goos == 'android'
|
||||||
run: |
|
run: |-
|
||||||
set -xeuo pipefail
|
|
||||||
go install -v ./cmd/internal/build
|
go install -v ./cmd/internal/build
|
||||||
export CC='${{ matrix.ndk }}-clang'
|
GOOS=$BUILD_GOOS GOARCH=$BUILD_GOARCH build goreleaser release --clean --split
|
||||||
export CXX="${CC}++"
|
|
||||||
mkdir -p dist
|
|
||||||
GOOS=$BUILD_GOOS GOARCH=$BUILD_GOARCH build go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
|
|
||||||
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }}' \
|
|
||||||
./cmd/sing-box
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: "1"
|
BUILD_GOOS: ${{ matrix.goos }}
|
||||||
BUILD_GOOS: ${{ matrix.os }}
|
BUILD_GOARCH: ${{ matrix.goarch }}
|
||||||
BUILD_GOARCH: ${{ matrix.arch }}
|
GOARM: ${{ matrix.goarm }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Set name
|
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||||
run: |-
|
NFPM_KEY_PATH: ${{ env.HOME }}/.gnupg/sagernet.key
|
||||||
ARM_VERSION=$([ -n '${{ matrix.goarm}}' ] && echo 'v${{ matrix.goarm}}' || true)
|
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
LEGACY=$([ '${{ matrix.legacy_go }}' = 'true' ] && echo "-legacy" || true)
|
|
||||||
DIR_NAME="sing-box-${{ needs.calculate_version.outputs.version }}-${{ matrix.os }}-${{ matrix.arch }}${ARM_VERSION}${LEGACY}"
|
|
||||||
PKG_NAME="sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.arch }}${ARM_VERSION}"
|
|
||||||
echo "DIR_NAME=${DIR_NAME}" >> "${GITHUB_ENV}"
|
|
||||||
echo "PKG_NAME=${PKG_NAME}" >> "${GITHUB_ENV}"
|
|
||||||
- name: Package DEB
|
|
||||||
if: matrix.debian != ''
|
|
||||||
run: |
|
|
||||||
set -xeuo pipefail
|
|
||||||
sudo gem install fpm
|
|
||||||
sudo apt-get install -y debsigs
|
|
||||||
fpm -t deb \
|
|
||||||
-v "${{ needs.calculate_version.outputs.version }}" \
|
|
||||||
-p "dist/${PKG_NAME}.deb" \
|
|
||||||
--architecture ${{ matrix.debian }} \
|
|
||||||
dist/sing-box=/usr/bin/sing-box
|
|
||||||
curl -Lo '/tmp/debsigs.diff' 'https://gitlab.com/debsigs/debsigs/-/commit/160138f5de1ec110376d3c807b60a37388bc7c90.diff'
|
|
||||||
sudo patch /usr/bin/debsigs < '/tmp/debsigs.diff'
|
|
||||||
rm -rf $HOME/.gnupg
|
|
||||||
gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
|
|
||||||
${{ secrets.GPG_KEY }}
|
|
||||||
EOF
|
|
||||||
debsigs --sign=origin -k ${{ secrets.GPG_KEY_ID }} --gpgopts '--pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}"' dist/*.deb
|
|
||||||
- name: Package RPM
|
|
||||||
if: matrix.rpm != ''
|
|
||||||
run: |-
|
|
||||||
set -xeuo pipefail
|
|
||||||
sudo gem install fpm
|
|
||||||
fpm -t rpm \
|
|
||||||
-v "${{ needs.calculate_version.outputs.version }}" \
|
|
||||||
-p "dist/${PKG_NAME}.rpm" \
|
|
||||||
--architecture ${{ matrix.rpm }} \
|
|
||||||
dist/sing-box=/usr/bin/sing-box
|
|
||||||
cat > $HOME/.rpmmacros <<EOF
|
|
||||||
%_gpg_name ${{ secrets.GPG_KEY_ID }}
|
|
||||||
%_gpg_sign_cmd_extra_args --pinentry-mode loopback --passphrase ${{ secrets.GPG_PASSPHRASE }}
|
|
||||||
EOF
|
|
||||||
gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
|
|
||||||
${{ secrets.GPG_KEY }}
|
|
||||||
EOF
|
|
||||||
rpmsign --addsign dist/*.rpm
|
|
||||||
- name: Package Pacman
|
|
||||||
if: matrix.pacman != ''
|
|
||||||
run: |-
|
|
||||||
set -xeuo pipefail
|
|
||||||
sudo gem install fpm
|
|
||||||
sudo apt-get install -y libarchive-tools
|
|
||||||
fpm -t pacman \
|
|
||||||
-v "${{ needs.calculate_version.outputs.version }}" \
|
|
||||||
-p "dist/${PKG_NAME}.pkg.tar.zst" \
|
|
||||||
--architecture ${{ matrix.pacman }} \
|
|
||||||
dist/sing-box=/usr/bin/sing-box
|
|
||||||
- name: Archive
|
|
||||||
run: |
|
|
||||||
set -xeuo pipefail
|
|
||||||
cd dist
|
|
||||||
mkdir -p "${DIR_NAME}"
|
|
||||||
cp ../LICENSE "${DIR_NAME}"
|
|
||||||
if [ '${{ matrix.os }}' = 'windoes' ]; then
|
|
||||||
cp sing-box.exe "${DIR_NAME}"
|
|
||||||
zip -r "${DIR_NAME}.zip" "${DIR_NAME}"
|
|
||||||
else
|
|
||||||
cp sing-box "${DIR_NAME}"
|
|
||||||
tar -czvf "${DIR_NAME}.tar.gz" "${DIR_NAME}"
|
|
||||||
fi
|
|
||||||
rm -r "${DIR_NAME}"
|
|
||||||
- name: Cleanup
|
|
||||||
run: rm dist/sing-box
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: binary-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.legacy_go && '-legacy' || '' }}
|
name: binary-${{ matrix.name }}
|
||||||
path: "dist"
|
path: 'dist'
|
||||||
build_android:
|
build_android:
|
||||||
name: Build Android
|
name: Build Android
|
||||||
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Android'
|
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Android'
|
||||||
@ -315,11 +271,13 @@ jobs:
|
|||||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||||
LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
|
LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }}
|
||||||
- name: Prepare upload
|
- name: Prepare upload
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
run: |-
|
run: |-
|
||||||
mkdir -p dist/release
|
mkdir -p dist/release
|
||||||
cp clients/android/app/build/outputs/apk/play/release/*.apk 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
|
cp clients/android/app/build/outputs/apk/other/release/*-universal.apk dist/release
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: binary-android-apks
|
name: binary-android-apks
|
||||||
@ -589,6 +547,12 @@ jobs:
|
|||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- name: Setup Goreleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v6
|
||||||
|
with:
|
||||||
|
distribution: goreleaser-pro
|
||||||
|
version: '~> v2'
|
||||||
|
install-only: true
|
||||||
- name: Cache ghr
|
- name: Cache ghr
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
id: cache-ghr
|
id: cache-ghr
|
||||||
@ -613,17 +577,26 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: dist
|
path: dist
|
||||||
merge-multiple: true
|
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
|
- name: Upload builds
|
||||||
if: ${{ env.PUBLISHED == 'false' }}
|
if: ${{ env.PUBLISHED == 'false' }}
|
||||||
run: |-
|
run: |-
|
||||||
export PATH="$PATH:$HOME/go/bin"
|
export PATH="$PATH:$HOME/go/bin"
|
||||||
ghr --replace --draft --prerelease -p 5 "v${VERSION}" dist
|
ghr --replace --draft --prerelease -p 5 "v${VERSION}" dist/release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Replace builds
|
- name: Replace builds
|
||||||
if: ${{ env.PUBLISHED != 'false' }}
|
if: ${{ env.PUBLISHED != 'false' }}
|
||||||
run: |-
|
run: |-
|
||||||
export PATH="$PATH:$HOME/go/bin"
|
export PATH="$PATH:$HOME/go/bin"
|
||||||
ghr --replace -p 5 "v${VERSION}" dist
|
ghr --replace -p 5 "v${VERSION}" dist/release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
1
.github/workflows/lint.yml
vendored
1
.github/workflows/lint.yml
vendored
@ -35,4 +35,3 @@ jobs:
|
|||||||
version: latest
|
version: latest
|
||||||
args: --timeout=30m
|
args: --timeout=30m
|
||||||
install-mode: binary
|
install-mode: binary
|
||||||
verify: false
|
|
||||||
|
176
.github/workflows/linux.yml
vendored
176
.github/workflows/linux.yml
vendored
@ -1,63 +1,13 @@
|
|||||||
name: Build Linux Packages
|
name: Release to Linux repository
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
version:
|
|
||||||
description: "Version name"
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
release:
|
release:
|
||||||
types:
|
types:
|
||||||
- published
|
- published
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
calculate_version:
|
|
||||||
name: Calculate version
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
version: ${{ steps.outputs.outputs.version }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: ^1.24
|
|
||||||
- name: Check input version
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: |-
|
|
||||||
echo "version=${{ inputs.version }}"
|
|
||||||
echo "version=${{ inputs.version }}" >> "$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"
|
|
||||||
build:
|
build:
|
||||||
name: Build binary
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- { os: linux, arch: amd64, debian: amd64, rpm: x86_64, pacman: x86_64 }
|
|
||||||
- { os: linux, arch: "386", debian: i386, rpm: i386 }
|
|
||||||
- { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl }
|
|
||||||
- { os: linux, arch: arm, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl }
|
|
||||||
- { os: linux, arch: arm64, debian: arm64, rpm: aarch64, pacman: aarch64 }
|
|
||||||
- { os: linux, arch: mips64le, debian: mips64el, rpm: mips64el }
|
|
||||||
- { os: linux, arch: mipsle, debian: mipsel, rpm: mipsel }
|
|
||||||
- { os: linux, arch: s390x, debian: s390x, rpm: s390x }
|
|
||||||
- { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le }
|
|
||||||
- { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64 }
|
|
||||||
- { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64 }
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||||
@ -67,114 +17,22 @@ jobs:
|
|||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24
|
go-version: ^1.24
|
||||||
- name: Setup Android NDK
|
- name: Extract signing key
|
||||||
if: matrix.os == 'android'
|
|
||||||
uses: nttld/setup-ndk@v1
|
|
||||||
with:
|
|
||||||
ndk-version: r28
|
|
||||||
local-cache: true
|
|
||||||
- name: Set tag
|
|
||||||
run: |-
|
run: |-
|
||||||
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
|
mkdir -p $HOME/.gnupg
|
||||||
git tag v${{ needs.calculate_version.outputs.version }} -f
|
cat > $HOME/.gnupg/sagernet.key <<EOF
|
||||||
- name: Set build tags
|
${{ secrets.GPG_KEY }}
|
||||||
run: |
|
EOF
|
||||||
set -xeuo pipefail
|
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||||
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_reality_server,with_acme,with_clash_api'
|
- name: Publish release
|
||||||
if [ ! '${{ matrix.legacy_go }}' = 'true' ]; then
|
uses: goreleaser/goreleaser-action@v6
|
||||||
TAGS="${TAGS},with_ech"
|
with:
|
||||||
fi
|
distribution: goreleaser-pro
|
||||||
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
|
version: '~> v2'
|
||||||
- name: Build
|
args: release -f .goreleaser.fury.yaml --clean
|
||||||
run: |
|
|
||||||
set -xeuo pipefail
|
|
||||||
mkdir -p dist
|
|
||||||
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
|
|
||||||
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }}' \
|
|
||||||
./cmd/sing-box
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: "0"
|
|
||||||
GOOS: ${{ matrix.os }}
|
|
||||||
GOARCH: ${{ matrix.arch }}
|
|
||||||
GOARM: ${{ matrix.goarm }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Set mtime
|
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||||
run: |-
|
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
|
||||||
TZ=UTC touch -t '197001010000' dist/sing-box
|
NFPM_KEY_PATH: ${{ env.HOME }}/.gnupg/sagernet.key
|
||||||
- name: Set name
|
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
if: ${{ ! contains(needs.calculate_version.outputs.version, '-') }}
|
|
||||||
run: |-
|
|
||||||
echo "NAME=sing-box" >> "$GITHUB_ENV"
|
|
||||||
- name: Set beta name
|
|
||||||
if: contains(needs.calculate_version.outputs.version, '-')
|
|
||||||
run: |-
|
|
||||||
echo "NAME=sing-box-beta" >> "$GITHUB_ENV"
|
|
||||||
- name: Package DEB
|
|
||||||
if: matrix.debian != ''
|
|
||||||
run: |
|
|
||||||
set -xeuo pipefail
|
|
||||||
sudo gem install fpm
|
|
||||||
sudo apt-get install -y debsigs
|
|
||||||
fpm -t deb \
|
|
||||||
-v "${{ needs.calculate_version.outputs.version }}" \
|
|
||||||
-p "dist/${NAME}_${{ needs.calculate_version.outputs.version }}_linux_${{ matrix.debian }}.deb" \
|
|
||||||
--architecture ${{ matrix.debian }} \
|
|
||||||
dist/sing-box=/usr/bin/${NAME}
|
|
||||||
curl -Lo '/tmp/debsigs.diff' 'https://gitlab.com/debsigs/debsigs/-/commit/160138f5de1ec110376d3c807b60a37388bc7c90.diff'
|
|
||||||
sudo patch /usr/bin/debsigs < '/tmp/debsigs.diff'
|
|
||||||
rm -rf $HOME/.gnupg
|
|
||||||
gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
|
|
||||||
${{ secrets.GPG_KEY }}
|
|
||||||
EOF
|
|
||||||
debsigs --sign=origin -k ${{ secrets.GPG_KEY_ID }} --gpgopts '--pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}"' dist/*.deb
|
|
||||||
- name: Package RPM
|
|
||||||
if: matrix.rpm != ''
|
|
||||||
run: |-
|
|
||||||
set -xeuo pipefail
|
|
||||||
sudo gem install fpm
|
|
||||||
fpm -t rpm \
|
|
||||||
-v "${{ needs.calculate_version.outputs.version }}" \
|
|
||||||
-p "dist/${NAME}_${{ needs.calculate_version.outputs.version }}_linux_${{ matrix.rpm }}.rpm" \
|
|
||||||
--architecture ${{ matrix.rpm }} \
|
|
||||||
dist/sing-box=/usr/bin/${NAME}
|
|
||||||
cat > $HOME/.rpmmacros <<EOF
|
|
||||||
%_gpg_name ${{ secrets.GPG_KEY_ID }}
|
|
||||||
%_gpg_sign_cmd_extra_args --pinentry-mode loopback --passphrase ${{ secrets.GPG_PASSPHRASE }}
|
|
||||||
EOF
|
|
||||||
gpg --pinentry-mode loopback --passphrase "${{ secrets.GPG_PASSPHRASE }}" --import <<EOF
|
|
||||||
${{ secrets.GPG_KEY }}
|
|
||||||
EOF
|
|
||||||
rpmsign --addsign dist/*.rpm
|
|
||||||
- name: Cleanup
|
|
||||||
run: rm dist/sing-box
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: binary-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.legacy_go && '-legacy' || '' }}
|
|
||||||
path: "dist"
|
|
||||||
upload:
|
|
||||||
name: Upload builds
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- calculate_version
|
|
||||||
- build
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set tag
|
|
||||||
run: |-
|
|
||||||
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
|
|
||||||
git tag v${{ needs.calculate_version.outputs.version }} -f
|
|
||||||
echo "VERSION=${{ needs.calculate_version.outputs.version }}" >> "$GITHUB_ENV"
|
|
||||||
- name: Download builds
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: dist
|
|
||||||
merge-multiple: true
|
|
||||||
- name: Publish packages
|
|
||||||
run: |-
|
|
||||||
wget -O fury-cli.deb https://github.com/gemfury/cli/releases/download/v0.23.0/fury-cli_0.23.0_linux_amd64.deb
|
|
||||||
sudo dpkg -i fury-cli.deb
|
|
||||||
fury migrate dist --as=sagernet --api-token ${{ secrets.FURY_TOKEN }}
|
|
||||||
|
@ -126,8 +126,8 @@ nfpms:
|
|||||||
- deb
|
- deb
|
||||||
- rpm
|
- rpm
|
||||||
- archlinux
|
- archlinux
|
||||||
# - apk
|
# - apk
|
||||||
# - ipk
|
# - ipk
|
||||||
priority: extra
|
priority: extra
|
||||||
contents:
|
contents:
|
||||||
- src: release/config/config.json
|
- src: release/config/config.json
|
||||||
|
13
Makefile
13
Makefile
@ -1,6 +1,8 @@
|
|||||||
NAME = sing-box
|
NAME = sing-box
|
||||||
COMMIT = $(shell git rev-parse --short HEAD)
|
COMMIT = $(shell git rev-parse --short HEAD)
|
||||||
TAGS ?= with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api,with_quic,with_utls,with_tailscale
|
TAGS_GO120 = with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api,with_quic,with_utls
|
||||||
|
TAGS_GO123 = with_tailscale
|
||||||
|
TAGS ?= $(TAGS_GO120),$(TAGS_GO123)
|
||||||
TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_utls,with_reality_server
|
TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_utls,with_reality_server
|
||||||
|
|
||||||
GOHOSTOS = $(shell go env GOHOSTOS)
|
GOHOSTOS = $(shell go env GOHOSTOS)
|
||||||
@ -18,6 +20,11 @@ build:
|
|||||||
export GOTOOLCHAIN=local && \
|
export GOTOOLCHAIN=local && \
|
||||||
go build $(MAIN_PARAMS) $(MAIN)
|
go build $(MAIN_PARAMS) $(MAIN)
|
||||||
|
|
||||||
|
ci_build_go120:
|
||||||
|
export GOTOOLCHAIN=local && \
|
||||||
|
go build $(PARAMS) $(MAIN) && \
|
||||||
|
go build $(PARAMS) -tags "$(TAGS_GO120)" $(MAIN)
|
||||||
|
|
||||||
ci_build:
|
ci_build:
|
||||||
export GOTOOLCHAIN=local && \
|
export GOTOOLCHAIN=local && \
|
||||||
go build $(PARAMS) $(MAIN) && \
|
go build $(PARAMS) $(MAIN) && \
|
||||||
@ -226,8 +233,8 @@ lib:
|
|||||||
go run ./cmd/internal/build_libbox -target ios
|
go run ./cmd/internal/build_libbox -target ios
|
||||||
|
|
||||||
lib_install:
|
lib_install:
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.5
|
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.4
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.5
|
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.4
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
venv/bin/mkdocs serve
|
venv/bin/mkdocs serve
|
||||||
|
@ -45,10 +45,10 @@ type RDRCStore interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DNSTransport interface {
|
type DNSTransport interface {
|
||||||
Lifecycle
|
|
||||||
Type() string
|
Type() string
|
||||||
Tag() string
|
Tag() string
|
||||||
Dependencies() []string
|
Dependencies() []string
|
||||||
|
Reset()
|
||||||
Exchange(ctx context.Context, message *dns.Msg) (*dns.Msg, error)
|
Exchange(ctx context.Context, message *dns.Msg) (*dns.Msg, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ var (
|
|||||||
debugFlags []string
|
debugFlags []string
|
||||||
sharedTags []string
|
sharedTags []string
|
||||||
iosTags []string
|
iosTags []string
|
||||||
memcTags []string
|
|
||||||
debugTags []string
|
debugTags []string
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,9 +58,8 @@ func init() {
|
|||||||
sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=")
|
sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=")
|
||||||
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag)
|
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag)
|
||||||
|
|
||||||
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_clash_api")
|
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_clash_api", "with_tailscale")
|
||||||
iosTags = append(iosTags, "with_dhcp", "with_low_memory", "with_conntrack")
|
iosTags = append(iosTags, "with_dhcp", "with_low_memory", "with_conntrack")
|
||||||
memcTags = append(memcTags, "with_tailscale")
|
|
||||||
debugTags = append(debugTags, "debug")
|
debugTags = append(debugTags, "debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,19 +99,18 @@ func buildAndroid() {
|
|||||||
"-javapkg=io.nekohasekai",
|
"-javapkg=io.nekohasekai",
|
||||||
"-libname=box",
|
"-libname=box",
|
||||||
}
|
}
|
||||||
|
|
||||||
if !debugEnabled {
|
if !debugEnabled {
|
||||||
args = append(args, sharedFlags...)
|
args = append(args, sharedFlags...)
|
||||||
} else {
|
} else {
|
||||||
args = append(args, debugFlags...)
|
args = append(args, debugFlags...)
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := append(sharedTags, memcTags...)
|
args = append(args, "-tags")
|
||||||
if debugEnabled {
|
if !debugEnabled {
|
||||||
tags = append(tags, debugTags...)
|
args = append(args, strings.Join(sharedTags, ","))
|
||||||
|
} else {
|
||||||
|
args = append(args, strings.Join(append(sharedTags, debugTags...), ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args, "-tags", strings.Join(tags, ","))
|
|
||||||
args = append(args, "./experimental/libbox")
|
args = append(args, "./experimental/libbox")
|
||||||
|
|
||||||
command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
|
command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
|
||||||
@ -151,9 +148,7 @@ func buildApple() {
|
|||||||
"-v",
|
"-v",
|
||||||
"-target", bindTarget,
|
"-target", bindTarget,
|
||||||
"-libname=box",
|
"-libname=box",
|
||||||
"-tags-macos=" + strings.Join(memcTags, ","),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !debugEnabled {
|
if !debugEnabled {
|
||||||
args = append(args, sharedFlags...)
|
args = append(args, sharedFlags...)
|
||||||
} else {
|
} else {
|
||||||
@ -161,11 +156,12 @@ func buildApple() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tags := append(sharedTags, iosTags...)
|
tags := append(sharedTags, iosTags...)
|
||||||
if debugEnabled {
|
args = append(args, "-tags")
|
||||||
tags = append(tags, debugTags...)
|
if !debugEnabled {
|
||||||
|
args = append(args, strings.Join(tags, ","))
|
||||||
|
} else {
|
||||||
|
args = append(args, strings.Join(append(tags, debugTags...), ","))
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args, "-tags", strings.Join(tags, ","))
|
|
||||||
args = append(args, "./experimental/libbox")
|
args = append(args, "./experimental/libbox")
|
||||||
|
|
||||||
command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
|
command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
"github.com/sagernet/sing-box/common/listener"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
@ -36,7 +35,6 @@ type DefaultDialer struct {
|
|||||||
udpListener net.ListenConfig
|
udpListener net.ListenConfig
|
||||||
udpAddr4 string
|
udpAddr4 string
|
||||||
udpAddr6 string
|
udpAddr6 string
|
||||||
netns string
|
|
||||||
networkManager adapter.NetworkManager
|
networkManager adapter.NetworkManager
|
||||||
networkStrategy *C.NetworkStrategy
|
networkStrategy *C.NetworkStrategy
|
||||||
defaultNetworkStrategy bool
|
defaultNetworkStrategy bool
|
||||||
@ -200,7 +198,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
|||||||
udpListener: listener,
|
udpListener: listener,
|
||||||
udpAddr4: udpAddr4,
|
udpAddr4: udpAddr4,
|
||||||
udpAddr6: udpAddr6,
|
udpAddr6: udpAddr6,
|
||||||
netns: options.NetNs,
|
|
||||||
networkManager: networkManager,
|
networkManager: networkManager,
|
||||||
networkStrategy: networkStrategy,
|
networkStrategy: networkStrategy,
|
||||||
defaultNetworkStrategy: defaultNetworkStrategy,
|
defaultNetworkStrategy: defaultNetworkStrategy,
|
||||||
@ -217,21 +214,19 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
|
|||||||
return nil, E.New("domain not resolved")
|
return nil, E.New("domain not resolved")
|
||||||
}
|
}
|
||||||
if d.networkStrategy == nil {
|
if d.networkStrategy == nil {
|
||||||
return trackConn(listener.ListenNetworkNamespace[net.Conn](d.netns, func() (net.Conn, error) {
|
switch N.NetworkName(network) {
|
||||||
switch N.NetworkName(network) {
|
case N.NetworkUDP:
|
||||||
case N.NetworkUDP:
|
|
||||||
if !address.IsIPv6() {
|
|
||||||
return d.udpDialer4.DialContext(ctx, network, address.String())
|
|
||||||
} else {
|
|
||||||
return d.udpDialer6.DialContext(ctx, network, address.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !address.IsIPv6() {
|
if !address.IsIPv6() {
|
||||||
return DialSlowContext(&d.dialer4, ctx, network, address)
|
return trackConn(d.udpDialer4.DialContext(ctx, network, address.String()))
|
||||||
} else {
|
} else {
|
||||||
return DialSlowContext(&d.dialer6, ctx, network, address)
|
return trackConn(d.udpDialer6.DialContext(ctx, network, address.String()))
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
|
if !address.IsIPv6() {
|
||||||
|
return trackConn(DialSlowContext(&d.dialer4, ctx, network, address))
|
||||||
|
} else {
|
||||||
|
return trackConn(DialSlowContext(&d.dialer6, ctx, network, address))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return d.DialParallelInterface(ctx, network, address, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
return d.DialParallelInterface(ctx, network, address, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
||||||
}
|
}
|
||||||
@ -287,15 +282,13 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
|
|||||||
|
|
||||||
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if d.networkStrategy == nil {
|
if d.networkStrategy == nil {
|
||||||
return trackPacketConn(listener.ListenNetworkNamespace[net.PacketConn](d.netns, func() (net.PacketConn, error) {
|
if destination.IsIPv6() {
|
||||||
if destination.IsIPv6() {
|
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6))
|
||||||
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)
|
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
|
||||||
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
|
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP+"4", d.udpAddr4))
|
||||||
return d.udpListener.ListenPacket(ctx, N.NetworkUDP+"4", d.udpAddr4)
|
} else {
|
||||||
} else {
|
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4))
|
||||||
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)
|
}
|
||||||
}
|
|
||||||
}))
|
|
||||||
} else {
|
} else {
|
||||||
return d.ListenSerialInterfacePacket(ctx, destination, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
return d.ListenSerialInterfacePacket(ctx, destination, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
||||||
}
|
}
|
||||||
|
@ -6,39 +6,26 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DirectDialer interface {
|
|
||||||
IsEmpty() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type DetourDialer struct {
|
type DetourDialer struct {
|
||||||
outboundManager adapter.OutboundManager
|
outboundManager adapter.OutboundManager
|
||||||
detour string
|
detour string
|
||||||
legacyDNSDialer bool
|
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
initOnce sync.Once
|
initOnce sync.Once
|
||||||
initErr error
|
initErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDetour(outboundManager adapter.OutboundManager, detour string, legacyDNSDialer bool) N.Dialer {
|
func NewDetour(outboundManager adapter.OutboundManager, detour string) N.Dialer {
|
||||||
return &DetourDialer{
|
return &DetourDialer{outboundManager: outboundManager, detour: detour}
|
||||||
outboundManager: outboundManager,
|
|
||||||
detour: detour,
|
|
||||||
legacyDNSDialer: legacyDNSDialer,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitializeDetour(dialer N.Dialer) error {
|
func (d *DetourDialer) Start() error {
|
||||||
detourDialer, isDetour := common.Cast[*DetourDialer](dialer)
|
_, err := d.Dialer()
|
||||||
if !isDetour {
|
return err
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return common.Error(detourDialer.Dialer())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DetourDialer) Dialer() (N.Dialer, error) {
|
func (d *DetourDialer) Dialer() (N.Dialer, error) {
|
||||||
@ -47,20 +34,11 @@ func (d *DetourDialer) Dialer() (N.Dialer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DetourDialer) init() {
|
func (d *DetourDialer) init() {
|
||||||
dialer, loaded := d.outboundManager.Outbound(d.detour)
|
var loaded bool
|
||||||
|
d.dialer, loaded = d.outboundManager.Outbound(d.detour)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
d.initErr = E.New("outbound detour not found: ", d.detour)
|
d.initErr = E.New("outbound detour not found: ", d.detour)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if !d.legacyDNSDialer {
|
|
||||||
if directDialer, isDirect := dialer.(DirectDialer); isDirect {
|
|
||||||
if directDialer.IsEmpty() {
|
|
||||||
d.initErr = E.New("detour to an empty direct outbound makes no sense")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.dialer = dialer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DetourDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (d *DetourDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
@ -23,7 +23,6 @@ type Options struct {
|
|||||||
DirectResolver bool
|
DirectResolver bool
|
||||||
ResolverOnDetour bool
|
ResolverOnDetour bool
|
||||||
NewDialer bool
|
NewDialer bool
|
||||||
LegacyDNSDialer bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: merge with NewWithOptions
|
// TODO: merge with NewWithOptions
|
||||||
@ -46,7 +45,7 @@ func NewWithOptions(options Options) (N.Dialer, error) {
|
|||||||
if outboundManager == nil {
|
if outboundManager == nil {
|
||||||
return nil, E.New("missing outbound manager")
|
return nil, E.New("missing outbound manager")
|
||||||
}
|
}
|
||||||
dialer = NewDetour(outboundManager, dialOptions.Detour, options.LegacyDNSDialer)
|
dialer = NewDetour(outboundManager, dialOptions.Detour)
|
||||||
} else {
|
} else {
|
||||||
dialer, err = NewDefault(options.Context, dialOptions)
|
dialer, err = NewDefault(options.Context, dialOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@ -16,8 +14,6 @@ import (
|
|||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"github.com/vishvananda/netns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Listener struct {
|
type Listener struct {
|
||||||
@ -139,30 +135,3 @@ func (l *Listener) UDPConn() *net.UDPConn {
|
|||||||
func (l *Listener) ListenOptions() option.ListenOptions {
|
func (l *Listener) ListenOptions() option.ListenOptions {
|
||||||
return l.listenOptions
|
return l.listenOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListenNetworkNamespace[T any](nameOrPath string, block func() (T, error)) (T, error) {
|
|
||||||
if nameOrPath != "" {
|
|
||||||
runtime.LockOSThread()
|
|
||||||
defer runtime.UnlockOSThread()
|
|
||||||
currentNs, err := netns.Get()
|
|
||||||
if err != nil {
|
|
||||||
return common.DefaultValue[T](), E.Cause(err, "get current netns")
|
|
||||||
}
|
|
||||||
defer netns.Set(currentNs)
|
|
||||||
var targetNs netns.NsHandle
|
|
||||||
if strings.HasPrefix(nameOrPath, "/") {
|
|
||||||
targetNs, err = netns.GetFromPath(nameOrPath)
|
|
||||||
} else {
|
|
||||||
targetNs, err = netns.GetFromName(nameOrPath)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return common.DefaultValue[T](), E.Cause(err, "get netns ", nameOrPath)
|
|
||||||
}
|
|
||||||
defer targetNs.Close()
|
|
||||||
err = netns.Set(targetNs)
|
|
||||||
if err != nil {
|
|
||||||
return common.DefaultValue[T](), E.Cause(err, "set netns to ", nameOrPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return block()
|
|
||||||
}
|
|
||||||
|
@ -16,12 +16,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (l *Listener) ListenTCP() (net.Listener, error) {
|
func (l *Listener) ListenTCP() (net.Listener, error) {
|
||||||
//nolint:staticcheck
|
|
||||||
if l.listenOptions.ProxyProtocol || l.listenOptions.ProxyProtocolAcceptNoHeader {
|
|
||||||
return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0")
|
|
||||||
}
|
|
||||||
var err error
|
var err error
|
||||||
bindAddr := M.SocksaddrFrom(l.listenOptions.Listen.Build(netip.AddrFrom4([4]byte{127, 0, 0, 1})), l.listenOptions.ListenPort)
|
bindAddr := M.SocksaddrFrom(l.listenOptions.Listen.Build(netip.AddrFrom4([4]byte{127, 0, 0, 1})), l.listenOptions.ListenPort)
|
||||||
|
var tcpListener net.Listener
|
||||||
var listenConfig net.ListenConfig
|
var listenConfig net.ListenConfig
|
||||||
if l.listenOptions.TCPKeepAlive >= 0 {
|
if l.listenOptions.TCPKeepAlive >= 0 {
|
||||||
keepIdle := time.Duration(l.listenOptions.TCPKeepAlive)
|
keepIdle := time.Duration(l.listenOptions.TCPKeepAlive)
|
||||||
@ -40,19 +37,20 @@ func (l *Listener) ListenTCP() (net.Listener, error) {
|
|||||||
}
|
}
|
||||||
setMultiPathTCP(&listenConfig)
|
setMultiPathTCP(&listenConfig)
|
||||||
}
|
}
|
||||||
tcpListener, err := ListenNetworkNamespace[net.Listener](l.listenOptions.NetNs, func() (net.Listener, error) {
|
if l.listenOptions.TCPFastOpen {
|
||||||
if l.listenOptions.TCPFastOpen {
|
var tfoConfig tfo.ListenConfig
|
||||||
var tfoConfig tfo.ListenConfig
|
tfoConfig.ListenConfig = listenConfig
|
||||||
tfoConfig.ListenConfig = listenConfig
|
tcpListener, err = tfoConfig.Listen(l.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
|
||||||
return tfoConfig.Listen(l.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
|
} else {
|
||||||
} else {
|
tcpListener, err = listenConfig.Listen(l.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
|
||||||
return listenConfig.Listen(l.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
|
}
|
||||||
}
|
if err == nil {
|
||||||
})
|
l.logger.Info("tcp server started at ", tcpListener.Addr())
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
//nolint:staticcheck
|
||||||
|
if l.listenOptions.ProxyProtocol || l.listenOptions.ProxyProtocolAcceptNoHeader {
|
||||||
|
return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0")
|
||||||
}
|
}
|
||||||
l.logger.Info("tcp server started at ", tcpListener.Addr())
|
|
||||||
l.tcpListener = tcpListener
|
l.tcpListener = tcpListener
|
||||||
return tcpListener, err
|
return tcpListener, err
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package listener
|
package listener
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
@ -25,9 +24,7 @@ func (l *Listener) ListenUDP() (net.PacketConn, error) {
|
|||||||
if !udpFragment {
|
if !udpFragment {
|
||||||
lc.Control = control.Append(lc.Control, control.DisableUDPFragment())
|
lc.Control = control.Append(lc.Control, control.DisableUDPFragment())
|
||||||
}
|
}
|
||||||
udpConn, err := ListenNetworkNamespace[net.PacketConn](l.listenOptions.NetNs, func() (net.PacketConn, error) {
|
udpConn, err := lc.ListenPacket(l.ctx, M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.String())
|
||||||
return lc.ListenPacket(l.ctx, M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.String())
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -37,12 +34,6 @@ func (l *Listener) ListenUDP() (net.PacketConn, error) {
|
|||||||
return udpConn, err
|
return udpConn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) ListenPacket(listenConfig net.ListenConfig, ctx context.Context, network string, address string) (net.PacketConn, error) {
|
|
||||||
return ListenNetworkNamespace[net.PacketConn](l.listenOptions.NetNs, func() (net.PacketConn, error) {
|
|
||||||
return listenConfig.ListenPacket(ctx, network, address)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Listener) UDPAddr() M.Socksaddr {
|
func (l *Listener) UDPAddr() M.Socksaddr {
|
||||||
return l.udpAddr
|
return l.udpAddr
|
||||||
}
|
}
|
||||||
|
@ -263,7 +263,20 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte
|
|||||||
return nil, tun.ErrDrop
|
return nil, tun.ErrDrop
|
||||||
}
|
}
|
||||||
case *R.RuleActionPredefined:
|
case *R.RuleActionPredefined:
|
||||||
return action.Response(message), nil
|
return &mDNS.Msg{
|
||||||
|
MsgHdr: mDNS.MsgHdr{
|
||||||
|
Id: message.Id,
|
||||||
|
Response: true,
|
||||||
|
Authoritative: true,
|
||||||
|
RecursionDesired: true,
|
||||||
|
RecursionAvailable: true,
|
||||||
|
Rcode: action.Rcode,
|
||||||
|
},
|
||||||
|
Question: message.Question,
|
||||||
|
Answer: action.Answer,
|
||||||
|
Ns: action.Ns,
|
||||||
|
Extra: action.Extra,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var responseCheck func(responseAddrs []netip.Addr) bool
|
var responseCheck func(responseAddrs []netip.Addr) bool
|
||||||
@ -449,6 +462,6 @@ func (r *Router) LookupReverseMapping(ip netip.Addr) (string, bool) {
|
|||||||
func (r *Router) ResetNetwork() {
|
func (r *Router) ResetNetwork() {
|
||||||
r.ClearCache()
|
r.ClearCache()
|
||||||
for _, transport := range r.transport.Transports() {
|
for _, transport := range r.transport.Transports() {
|
||||||
transport.Close()
|
transport.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func (t *Transport) Start(stage adapter.StartStage) error {
|
|||||||
|
|
||||||
func (t *Transport) Close() error {
|
func (t *Transport) Close() error {
|
||||||
for _, transport := range t.transports {
|
for _, transport := range t.transports {
|
||||||
transport.Close()
|
transport.Reset()
|
||||||
}
|
}
|
||||||
if t.interfaceCallback != nil {
|
if t.interfaceCallback != nil {
|
||||||
t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback)
|
t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback)
|
||||||
@ -89,6 +89,12 @@ func (t *Transport) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Transport) Reset() {
|
||||||
|
for _, transport := range t.transports {
|
||||||
|
transport.Reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
err := t.fetchServers()
|
err := t.fetchServers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -246,7 +252,7 @@ func (t *Transport) recreateServers(iface *control.Interface, serverAddrs []M.So
|
|||||||
transports = append(transports, transport.NewUDPRaw(t.logger, t.TransportAdapter, serverDialer, serverAddr))
|
transports = append(transports, transport.NewUDPRaw(t.logger, t.TransportAdapter, serverDialer, serverAddr))
|
||||||
}
|
}
|
||||||
for _, transport := range t.transports {
|
for _, transport := range t.transports {
|
||||||
transport.Close()
|
transport.Reset()
|
||||||
}
|
}
|
||||||
t.transports = transports
|
t.transports = transports
|
||||||
return nil
|
return nil
|
||||||
|
@ -51,12 +51,7 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
func (t *Transport) Reset() {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/dns"
|
"github.com/sagernet/sing-box/dns"
|
||||||
@ -150,17 +149,9 @@ func NewHTTPSRaw(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HTTPSTransport) Start(stage adapter.StartStage) error {
|
func (t *HTTPSTransport) Reset() {
|
||||||
if stage != adapter.StartStateStart {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return dialer.InitializeDetour(t.dialer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *HTTPSTransport) Close() error {
|
|
||||||
t.transport.CloseIdleConnections()
|
t.transport.CloseIdleConnections()
|
||||||
t.transport = t.transport.Clone()
|
t.transport = t.transport.Clone()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HTTPSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *HTTPSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -40,12 +40,7 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
func (t *Transport) Reset() {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -111,12 +111,8 @@ func NewHTTP3(ctx context.Context, logger log.ContextLogger, tag string, options
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HTTP3Transport) Start(stage adapter.StartStage) error {
|
func (t *HTTP3Transport) Reset() {
|
||||||
return nil
|
t.transport.Close()
|
||||||
}
|
|
||||||
|
|
||||||
func (t *HTTP3Transport) Close() error {
|
|
||||||
return t.transport.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *HTTP3Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *HTTP3Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -68,18 +68,13 @@ func NewQUIC(ctx context.Context, logger log.ContextLogger, tag string, options
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
func (t *Transport) Reset() {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) Close() error {
|
|
||||||
t.access.Lock()
|
t.access.Lock()
|
||||||
defer t.access.Unlock()
|
defer t.access.Unlock()
|
||||||
connection := t.connection
|
connection := t.connection
|
||||||
if connection != nil {
|
if connection != nil {
|
||||||
connection.CloseWithError(0, "")
|
connection.CloseWithError(0, "")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/dns"
|
"github.com/sagernet/sing-box/dns"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
@ -47,15 +46,7 @@ func NewTCP(ctx context.Context, logger log.ContextLogger, tag string, options o
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TCPTransport) Start(stage adapter.StartStage) error {
|
func (t *TCPTransport) Reset() {
|
||||||
if stage != adapter.StartStateStart {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return dialer.InitializeDetour(t.dialer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TCPTransport) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TCPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *TCPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/dns"
|
"github.com/sagernet/sing-box/dns"
|
||||||
@ -66,21 +65,13 @@ func NewTLS(ctx context.Context, logger log.ContextLogger, tag string, options o
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TLSTransport) Start(stage adapter.StartStage) error {
|
func (t *TLSTransport) Reset() {
|
||||||
if stage != adapter.StartStateStart {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return dialer.InitializeDetour(t.dialer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TLSTransport) Close() error {
|
|
||||||
t.access.Lock()
|
t.access.Lock()
|
||||||
defer t.access.Unlock()
|
defer t.access.Unlock()
|
||||||
for connection := t.connections.Front(); connection != nil; connection = connection.Next() {
|
for connection := t.connections.Front(); connection != nil; connection = connection.Next() {
|
||||||
connection.Value.Close()
|
connection.Value.Close()
|
||||||
}
|
}
|
||||||
t.connections.Init()
|
t.connections.Init()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/dns"
|
"github.com/sagernet/sing-box/dns"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
@ -65,19 +64,11 @@ func NewUDPRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *UDPTransport) Start(stage adapter.StartStage) error {
|
func (t *UDPTransport) Reset() {
|
||||||
if stage != adapter.StartStateStart {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return dialer.InitializeDetour(t.dialer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *UDPTransport) Close() error {
|
|
||||||
t.access.Lock()
|
t.access.Lock()
|
||||||
defer t.access.Unlock()
|
defer t.access.Unlock()
|
||||||
close(t.done)
|
close(t.done)
|
||||||
t.done = make(chan struct{})
|
t.done = make(chan struct{})
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *UDPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (t *UDPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
@ -20,10 +20,9 @@ func NewLocalDialer(ctx context.Context, options option.LocalDNSServerOptions) (
|
|||||||
return dialer.NewDefaultOutbound(ctx), nil
|
return dialer.NewDefaultOutbound(ctx), nil
|
||||||
} else {
|
} else {
|
||||||
return dialer.NewWithOptions(dialer.Options{
|
return dialer.NewWithOptions(dialer.Options{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Options: options.DialerOptions,
|
Options: options.DialerOptions,
|
||||||
DirectResolver: true,
|
DirectResolver: true,
|
||||||
LegacyDNSDialer: options.Legacy,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,11 +43,10 @@ func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions)
|
|||||||
return transportDialer, nil
|
return transportDialer, nil
|
||||||
} else {
|
} else {
|
||||||
return dialer.NewWithOptions(dialer.Options{
|
return dialer.NewWithOptions(dialer.Options{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Options: options.DialerOptions,
|
Options: options.DialerOptions,
|
||||||
RemoteIsDomain: options.ServerIsDomain(),
|
RemoteIsDomain: options.ServerIsDomain(),
|
||||||
DirectResolver: true,
|
DirectResolver: true,
|
||||||
LegacyDNSDialer: options.Legacy,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,6 @@ func (m *TransportManager) Start(stage adapter.StartStage) error {
|
|||||||
transports := m.transports
|
transports := m.transports
|
||||||
m.access.Unlock()
|
m.access.Unlock()
|
||||||
if stage == adapter.StartStateStart {
|
if stage == adapter.StartStateStart {
|
||||||
if m.defaultTag != "" && m.defaultTransport == nil {
|
|
||||||
return E.New("default DNS server not found: ", m.defaultTag)
|
|
||||||
}
|
|
||||||
return m.startTransports(m.transports)
|
return m.startTransports(m.transports)
|
||||||
} else {
|
} else {
|
||||||
for _, outbound := range transports {
|
for _, outbound := range transports {
|
||||||
@ -228,7 +225,7 @@ func (m *TransportManager) Remove(tag string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if started {
|
if started {
|
||||||
transport.Close()
|
transport.Reset()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,6 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 1.12.0-alpha.19
|
|
||||||
|
|
||||||
* Update gVisor to 20250319.0
|
|
||||||
* Fixes and improvements
|
|
||||||
|
|
||||||
#### 1.12.0-alpha.18
|
#### 1.12.0-alpha.18
|
||||||
|
|
||||||
* Add wildcard SNI support for ShadowTLS inbound **1**
|
* Add wildcard SNI support for ShadowTLS inbound **1**
|
||||||
|
@ -6,7 +6,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
:material-plus: [domain_resolver](#domain_resolver)
|
:material-plus: [domain_resolver](#domain_resolver)
|
||||||
:material-delete-clock: [domain_strategy](#domain_strategy)
|
:material-delete-clock: [domain_strategy](#domain_strategy)
|
||||||
:material-plus: [netns](#netns)
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.11.0"
|
!!! quote "Changes in sing-box 1.11.0"
|
||||||
|
|
||||||
@ -19,25 +18,24 @@ icon: material/new-box
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"detour": "",
|
"detour": "upstream-out",
|
||||||
"bind_interface": "",
|
"bind_interface": "en0",
|
||||||
"inet4_bind_address": "",
|
"inet4_bind_address": "0.0.0.0",
|
||||||
"inet6_bind_address": "",
|
"inet6_bind_address": "::",
|
||||||
"routing_mark": 0,
|
"routing_mark": 1234,
|
||||||
"reuse_addr": false,
|
"reuse_addr": false,
|
||||||
"connect_timeout": "",
|
"connect_timeout": "5s",
|
||||||
"tcp_fast_open": false,
|
"tcp_fast_open": false,
|
||||||
"tcp_multi_path": false,
|
"tcp_multi_path": false,
|
||||||
"udp_fragment": false,
|
"udp_fragment": false,
|
||||||
"netns": "",
|
|
||||||
"domain_resolver": "", // or {}
|
"domain_resolver": "", // or {}
|
||||||
"network_strategy": "",
|
"network_strategy": "default",
|
||||||
"network_type": [],
|
"network_type": [],
|
||||||
"fallback_network_type": [],
|
"fallback_network_type": [],
|
||||||
"fallback_delay": "",
|
"fallback_delay": "300ms",
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
"domain_strategy": ""
|
"domain_strategy": "prefer_ipv6"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -77,15 +75,6 @@ Set netfilter routing mark.
|
|||||||
|
|
||||||
Reuse listener address.
|
Reuse listener address.
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
#### tcp_fast_open
|
||||||
|
|
||||||
Enable TCP Fast Open.
|
Enable TCP Fast Open.
|
||||||
@ -102,15 +91,14 @@ Enable TCP Multi Path.
|
|||||||
|
|
||||||
Enable UDP fragmentation.
|
Enable UDP fragmentation.
|
||||||
|
|
||||||
#### netns
|
#### connect_timeout
|
||||||
|
|
||||||
!!! question "Since sing-box 1.12.0"
|
Connect timeout, in golang's Duration format.
|
||||||
|
|
||||||
!!! quote ""
|
A duration string is a possibly signed sequence of
|
||||||
|
decimal numbers, each with optional fraction and a unit suffix,
|
||||||
Only supported on Linux.
|
such as "300ms", "-1.5h" or "2h45m".
|
||||||
|
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||||
Set network namespace, name or path.
|
|
||||||
|
|
||||||
#### domain_resolver
|
#### domain_resolver
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
:material-plus: [domain_resolver](#domain_resolver)
|
:material-plus: [domain_resolver](#domain_resolver)
|
||||||
:material-delete-clock: [domain_strategy](#domain_strategy)
|
:material-delete-clock: [domain_strategy](#domain_strategy)
|
||||||
:material-plus: [netns](#netns)
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.11.0 中的更改"
|
!!! quote "sing-box 1.11.0 中的更改"
|
||||||
|
|
||||||
@ -19,26 +18,25 @@ icon: material/new-box
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"detour": "",
|
"detour": "upstream-out",
|
||||||
"bind_interface": "",
|
"bind_interface": "en0",
|
||||||
"inet4_bind_address": "",
|
"inet4_bind_address": "0.0.0.0",
|
||||||
"inet6_bind_address": "",
|
"inet6_bind_address": "::",
|
||||||
"routing_mark": 0,
|
"routing_mark": 1234,
|
||||||
"reuse_addr": false,
|
"reuse_addr": false,
|
||||||
"connect_timeout": "",
|
"connect_timeout": "5s",
|
||||||
"tcp_fast_open": false,
|
"tcp_fast_open": false,
|
||||||
"tcp_multi_path": false,
|
"tcp_multi_path": false,
|
||||||
"udp_fragment": false,
|
"udp_fragment": false,
|
||||||
"netns": "",
|
|
||||||
"domain_resolver": "", // 或 {}
|
"domain_resolver": "", // 或 {}
|
||||||
"network_strategy": "",
|
"network_strategy": "",
|
||||||
"network_type": [],
|
"network_type": [],
|
||||||
"fallback_network_type": [],
|
"fallback_network_type": [],
|
||||||
"fallback_delay": "",
|
"fallback_delay": "300ms",
|
||||||
|
|
||||||
// 废弃的
|
// 废弃的
|
||||||
|
|
||||||
"domain_strategy": ""
|
"domain_strategy": "prefer_ipv6"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -78,13 +76,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
重用监听地址。
|
重用监听地址。
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
#### tcp_fast_open
|
||||||
|
|
||||||
启用 TCP Fast Open。
|
启用 TCP Fast Open。
|
||||||
@ -101,15 +92,12 @@ icon: material/new-box
|
|||||||
|
|
||||||
启用 UDP 分段。
|
启用 UDP 分段。
|
||||||
|
|
||||||
#### netns
|
#### connect_timeout
|
||||||
|
|
||||||
!!! question "自 sing-box 1.12.0 起"
|
连接超时,采用 golang 的 Duration 格式。
|
||||||
|
|
||||||
!!! quote ""
|
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
||||||
|
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置网络命名空间,名称或路径。
|
|
||||||
|
|
||||||
#### domain_resolver
|
#### domain_resolver
|
||||||
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
---
|
---
|
||||||
icon: material/new-box
|
icon: material/delete-clock
|
||||||
---
|
---
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.12.0"
|
|
||||||
|
|
||||||
:material-plus: [netns](#netns)
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.11.0"
|
!!! quote "Changes in sing-box 1.11.0"
|
||||||
|
|
||||||
:material-delete-clock: [sniff](#sniff)
|
:material-delete-clock: [sniff](#sniff)
|
||||||
@ -18,18 +14,17 @@ icon: material/new-box
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"listen": "",
|
"listen": "::",
|
||||||
"listen_port": 0,
|
"listen_port": 5353,
|
||||||
"tcp_fast_open": false,
|
"tcp_fast_open": false,
|
||||||
"tcp_multi_path": false,
|
"tcp_multi_path": false,
|
||||||
"udp_fragment": false,
|
"udp_fragment": false,
|
||||||
"udp_timeout": "",
|
"udp_timeout": "5m",
|
||||||
"netns": "",
|
"detour": "another-in",
|
||||||
"detour": "",
|
|
||||||
"sniff": false,
|
"sniff": false,
|
||||||
"sniff_override_destination": false,
|
"sniff_override_destination": false,
|
||||||
"sniff_timeout": "",
|
"sniff_timeout": "300ms",
|
||||||
"domain_strategy": "",
|
"domain_strategy": "prefer_ipv6",
|
||||||
"udp_disable_domain_unmapping": false
|
"udp_disable_domain_unmapping": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -77,16 +72,6 @@ UDP NAT expiration time.
|
|||||||
|
|
||||||
`5m` will be used by default.
|
`5m` will be used by default.
|
||||||
|
|
||||||
#### netns
|
|
||||||
|
|
||||||
!!! question "Since sing-box 1.12.0"
|
|
||||||
|
|
||||||
!!! quote ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set network namespace, name or path.
|
|
||||||
|
|
||||||
#### detour
|
#### detour
|
||||||
|
|
||||||
If set, connections will be forwarded to the specified inbound.
|
If set, connections will be forwarded to the specified inbound.
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
---
|
---
|
||||||
icon: material/new-box
|
icon: material/delete-clock
|
||||||
---
|
---
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.12.0"
|
|
||||||
|
|
||||||
:material-plus: [netns](#netns)
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.11.0 中的更改"
|
!!! quote "sing-box 1.11.0 中的更改"
|
||||||
|
|
||||||
:material-delete-clock: [sniff](#sniff)
|
:material-delete-clock: [sniff](#sniff)
|
||||||
@ -18,18 +14,17 @@ icon: material/new-box
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"listen": "",
|
"listen": "::",
|
||||||
"listen_port": 0,
|
"listen_port": 5353,
|
||||||
"tcp_fast_open": false,
|
"tcp_fast_open": false,
|
||||||
"tcp_multi_path": false,
|
"tcp_multi_path": false,
|
||||||
"udp_fragment": false,
|
"udp_fragment": false,
|
||||||
"udp_timeout": "",
|
"udp_timeout": "5m",
|
||||||
"netns": "",
|
"detour": "another-in",
|
||||||
"detour": "",
|
|
||||||
"sniff": false,
|
"sniff": false,
|
||||||
"sniff_override_destination": false,
|
"sniff_override_destination": false,
|
||||||
"sniff_timeout": "",
|
"sniff_timeout": "300ms",
|
||||||
"domain_strategy": "",
|
"domain_strategy": "prefer_ipv6",
|
||||||
"udp_disable_domain_unmapping": false
|
"udp_disable_domain_unmapping": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -78,16 +73,6 @@ UDP NAT 过期时间。
|
|||||||
|
|
||||||
默认使用 `5m`。
|
默认使用 `5m`。
|
||||||
|
|
||||||
#### netns
|
|
||||||
|
|
||||||
!!! question "自 sing-box 1.12.0 起"
|
|
||||||
|
|
||||||
!!! quote ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置网络命名空间,名称或路径。
|
|
||||||
|
|
||||||
#### detour
|
#### detour
|
||||||
|
|
||||||
如果设置,连接将被转发到指定的入站。
|
如果设置,连接将被转发到指定的入站。
|
||||||
|
@ -38,12 +38,7 @@ func newPlatformTransport(iif LocalDNSTransport, tag string, options option.Loca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *platformTransport) Start(stage adapter.StartStage) error {
|
func (p *platformTransport) Reset() {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *platformTransport) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *platformTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
func (p *platformTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
8
go.mod
8
go.mod
@ -23,16 +23,16 @@ require (
|
|||||||
github.com/sagernet/cors v1.2.1
|
github.com/sagernet/cors v1.2.1
|
||||||
github.com/sagernet/fswatch v0.1.1
|
github.com/sagernet/fswatch v0.1.1
|
||||||
github.com/sagernet/gomobile v0.1.4
|
github.com/sagernet/gomobile v0.1.4
|
||||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
|
||||||
github.com/sagernet/quic-go v0.49.0-beta.1
|
github.com/sagernet/quic-go v0.49.0-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.5-0.20250324102321-1ddf4ccbfab8
|
github.com/sagernet/sing v0.6.4-0.20250316065121-38f666955109
|
||||||
github.com/sagernet/sing-mux v0.3.1
|
github.com/sagernet/sing-mux v0.3.1
|
||||||
github.com/sagernet/sing-quic v0.4.1-beta.1
|
github.com/sagernet/sing-quic v0.4.1-beta.1
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056
|
||||||
github.com/sagernet/sing-tun v0.6.2-0.20250319123703-35b5747b44ec
|
github.com/sagernet/sing-tun v0.6.1
|
||||||
github.com/sagernet/sing-vmess v0.2.0
|
github.com/sagernet/sing-vmess v0.2.0
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||||
github.com/sagernet/tailscale v1.80.3-mod.0
|
github.com/sagernet/tailscale v1.80.3-mod.0
|
||||||
@ -41,7 +41,6 @@ require (
|
|||||||
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.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/vishvananda/netns v0.0.4
|
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.33.0
|
golang.org/x/crypto v0.33.0
|
||||||
@ -123,6 +122,7 @@ require (
|
|||||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
||||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect
|
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
||||||
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
12
go.sum
12
go.sum
@ -167,8 +167,8 @@ github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQ
|
|||||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||||
github.com/sagernet/gomobile v0.1.4 h1:WzX9ka+iHdupMgy2Vdich+OAt7TM8C2cZbIbzNjBrJY=
|
github.com/sagernet/gomobile v0.1.4 h1:WzX9ka+iHdupMgy2Vdich+OAt7TM8C2cZbIbzNjBrJY=
|
||||||
github.com/sagernet/gomobile v0.1.4/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
github.com/sagernet/gomobile v0.1.4/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb h1:pprQtDqNgqXkRsXn+0E8ikKOemzmum8bODjSfDene38=
|
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff h1:mlohw3360Wg1BNGook/UHnISXhUx4Gd/3tVLs5T0nSs=
|
||||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb/go.mod h1:QkkPEJLw59/tfxgapHta14UL5qMUah5NXhO0Kw2Kan4=
|
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff/go.mod h1:ehZwnT2UpmOWAHFL48XdBhnd4Qu4hN2O3Ji0us3ZHMw=
|
||||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||||
@ -178,8 +178,8 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W
|
|||||||
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.5-0.20250324102321-1ddf4ccbfab8 h1:Kg/OPLceU3Ty46ceEwLfL9NLbKBCLj5dNQb1Ia+Q0VI=
|
github.com/sagernet/sing v0.6.4-0.20250316065121-38f666955109 h1:clwEzQu0oiapGllEDtbGQjcmQaIAt8DH3EeOHAWyiKs=
|
||||||
github.com/sagernet/sing v0.6.5-0.20250324102321-1ddf4ccbfab8/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.4-0.20250316065121-38f666955109/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
|
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
|
||||||
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
|
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
|
||||||
github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s=
|
github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s=
|
||||||
@ -190,8 +190,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
|
|||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056 h1:GFNJQAHhSXqAfxAw1wDG/QWbdpGH5Na3k8qUynqWnEA=
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056 h1:GFNJQAHhSXqAfxAw1wDG/QWbdpGH5Na3k8qUynqWnEA=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056/go.mod h1:HyacBPIFiKihJQR8LQp56FM4hBtd/7MZXnRxxQIOPsc=
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056/go.mod h1:HyacBPIFiKihJQR8LQp56FM4hBtd/7MZXnRxxQIOPsc=
|
||||||
github.com/sagernet/sing-tun v0.6.2-0.20250319123703-35b5747b44ec h1:9/OYGb9qDmUFIhqd3S+3eni62EKRQR1rSmRH18baA/M=
|
github.com/sagernet/sing-tun v0.6.1 h1:4l0+gnEKcGjlWfUVTD+W0BRApqIny/lU2ZliurE+VMo=
|
||||||
github.com/sagernet/sing-tun v0.6.2-0.20250319123703-35b5747b44ec/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
github.com/sagernet/sing-tun v0.6.1/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||||
github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI=
|
github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI=
|
||||||
github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
|
github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||||
|
@ -191,24 +191,34 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
|||||||
serverType = C.DNSTypeUDP
|
serverType = C.DNSTypeUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remoteOptions := RemoteDNSServerOptions{
|
var remoteOptions RemoteDNSServerOptions
|
||||||
LocalDNSServerOptions: LocalDNSServerOptions{
|
if options.Detour == "" {
|
||||||
DialerOptions: DialerOptions{
|
remoteOptions = RemoteDNSServerOptions{
|
||||||
Detour: options.Detour,
|
LocalDNSServerOptions: LocalDNSServerOptions{
|
||||||
DomainResolver: &DomainResolveOptions{
|
LegacyStrategy: options.Strategy,
|
||||||
Server: options.AddressResolver,
|
LegacyDefaultDialer: options.Detour == "",
|
||||||
Strategy: options.AddressStrategy,
|
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
||||||
},
|
|
||||||
FallbackDelay: options.AddressFallbackDelay,
|
|
||||||
},
|
},
|
||||||
Legacy: true,
|
LegacyAddressResolver: options.AddressResolver,
|
||||||
LegacyStrategy: options.Strategy,
|
LegacyAddressStrategy: options.AddressStrategy,
|
||||||
LegacyDefaultDialer: options.Detour == "",
|
LegacyAddressFallbackDelay: options.AddressFallbackDelay,
|
||||||
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
}
|
||||||
},
|
} else {
|
||||||
LegacyAddressResolver: options.AddressResolver,
|
remoteOptions = RemoteDNSServerOptions{
|
||||||
LegacyAddressStrategy: options.AddressStrategy,
|
LocalDNSServerOptions: LocalDNSServerOptions{
|
||||||
LegacyAddressFallbackDelay: options.AddressFallbackDelay,
|
DialerOptions: DialerOptions{
|
||||||
|
Detour: options.Detour,
|
||||||
|
DomainResolver: &DomainResolveOptions{
|
||||||
|
Server: options.AddressResolver,
|
||||||
|
Strategy: options.AddressStrategy,
|
||||||
|
},
|
||||||
|
FallbackDelay: options.AddressFallbackDelay,
|
||||||
|
},
|
||||||
|
LegacyStrategy: options.Strategy,
|
||||||
|
LegacyDefaultDialer: options.Detour == "",
|
||||||
|
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch serverType {
|
switch serverType {
|
||||||
case C.DNSTypeLocal:
|
case C.DNSTypeLocal:
|
||||||
@ -352,7 +362,6 @@ type HostsDNSServerOptions struct {
|
|||||||
|
|
||||||
type LocalDNSServerOptions struct {
|
type LocalDNSServerOptions struct {
|
||||||
DialerOptions
|
DialerOptions
|
||||||
Legacy bool `json:"-"`
|
|
||||||
LegacyStrategy DomainStrategy `json:"-"`
|
LegacyStrategy DomainStrategy `json:"-"`
|
||||||
LegacyDefaultDialer bool `json:"-"`
|
LegacyDefaultDialer bool `json:"-"`
|
||||||
LegacyClientSubnet netip.Prefix `json:"-"`
|
LegacyClientSubnet netip.Prefix `json:"-"`
|
||||||
|
@ -68,7 +68,6 @@ type ListenOptions struct {
|
|||||||
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
||||||
UDPFragmentDefault bool `json:"-"`
|
UDPFragmentDefault bool `json:"-"`
|
||||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
||||||
NetNs string `json:"netns,omitempty"`
|
|
||||||
|
|
||||||
// Deprecated: removed
|
// Deprecated: removed
|
||||||
ProxyProtocol bool `json:"proxy_protocol,omitempty"`
|
ProxyProtocol bool `json:"proxy_protocol,omitempty"`
|
||||||
|
@ -77,7 +77,6 @@ type DialerOptions struct {
|
|||||||
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
||||||
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
||||||
UDPFragmentDefault bool `json:"-"`
|
UDPFragmentDefault bool `json:"-"`
|
||||||
NetNs string `json:"netns,omitempty"`
|
|
||||||
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
|
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
|
||||||
NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
|
NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
|
||||||
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
||||||
|
@ -125,9 +125,10 @@ func (r *DefaultRule) UnmarshalJSON(data []byte) error {
|
|||||||
return badjson.UnmarshallExcluded(data, &r.RawDefaultRule, &r.RuleAction)
|
return badjson.UnmarshallExcluded(data, &r.RawDefaultRule, &r.RuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r DefaultRule) IsValid() bool {
|
func (r *DefaultRule) IsValid() bool {
|
||||||
var defaultValue DefaultRule
|
var defaultValue DefaultRule
|
||||||
defaultValue.Invert = r.Invert
|
defaultValue.Invert = r.Invert
|
||||||
|
defaultValue.Action = r.Action
|
||||||
return !reflect.DeepEqual(r, defaultValue)
|
return !reflect.DeepEqual(r, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@ func (r *DefaultDNSRule) UnmarshalJSONContext(ctx context.Context, data []byte)
|
|||||||
func (r DefaultDNSRule) IsValid() bool {
|
func (r DefaultDNSRule) IsValid() bool {
|
||||||
var defaultValue DefaultDNSRule
|
var defaultValue DefaultDNSRule
|
||||||
defaultValue.Invert = r.Invert
|
defaultValue.Invert = r.Invert
|
||||||
|
defaultValue.DNSRuleAction = r.DNSRuleAction
|
||||||
return !reflect.DeepEqual(r, defaultValue)
|
return !reflect.DeepEqual(r, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,18 +4,17 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json/badjson"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ShadowTLSInboundOptions struct {
|
type ShadowTLSInboundOptions struct {
|
||||||
ListenOptions
|
ListenOptions
|
||||||
Version int `json:"version,omitempty"`
|
Version int `json:"version,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Users []ShadowTLSUser `json:"users,omitempty"`
|
Users []ShadowTLSUser `json:"users,omitempty"`
|
||||||
Handshake ShadowTLSHandshakeOptions `json:"handshake,omitempty"`
|
Handshake ShadowTLSHandshakeOptions `json:"handshake,omitempty"`
|
||||||
HandshakeForServerName *badjson.TypedMap[string, ShadowTLSHandshakeOptions] `json:"handshake_for_server_name,omitempty"`
|
HandshakeForServerName map[string]ShadowTLSHandshakeOptions `json:"handshake_for_server_name,omitempty"`
|
||||||
StrictMode bool `json:"strict_mode,omitempty"`
|
StrictMode bool `json:"strict_mode,omitempty"`
|
||||||
WildcardSNI WildcardSNI `json:"wildcard_sni,omitempty"`
|
WildcardSNI WildcardSNI `json:"wildcard_sni,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WildcardSNI int
|
type WildcardSNI int
|
||||||
|
@ -7,15 +7,13 @@ import (
|
|||||||
|
|
||||||
type SocksInboundOptions struct {
|
type SocksInboundOptions struct {
|
||||||
ListenOptions
|
ListenOptions
|
||||||
Users []auth.User `json:"users,omitempty"`
|
Users []auth.User `json:"users,omitempty"`
|
||||||
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPMixedInboundOptions struct {
|
type HTTPMixedInboundOptions struct {
|
||||||
ListenOptions
|
ListenOptions
|
||||||
Users []auth.User `json:"users,omitempty"`
|
Users []auth.User `json:"users,omitempty"`
|
||||||
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
|
SetSystemProxy bool `json:"set_system_proxy,omitempty"`
|
||||||
SetSystemProxy bool `json:"set_system_proxy,omitempty"`
|
|
||||||
InboundTLSOptionsContainer
|
InboundTLSOptionsContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"reflect"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@ -28,7 +27,6 @@ func RegisterOutbound(registry *outbound.Registry) {
|
|||||||
var (
|
var (
|
||||||
_ N.ParallelDialer = (*Outbound)(nil)
|
_ N.ParallelDialer = (*Outbound)(nil)
|
||||||
_ dialer.ParallelNetworkDialer = (*Outbound)(nil)
|
_ dialer.ParallelNetworkDialer = (*Outbound)(nil)
|
||||||
_ dialer.DirectDialer = (*Outbound)(nil)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Outbound struct {
|
type Outbound struct {
|
||||||
@ -39,7 +37,6 @@ type Outbound struct {
|
|||||||
fallbackDelay time.Duration
|
fallbackDelay time.Duration
|
||||||
overrideOption int
|
overrideOption int
|
||||||
overrideDestination M.Socksaddr
|
overrideDestination M.Socksaddr
|
||||||
isEmpty bool
|
|
||||||
// loopBack *loopBackDetector
|
// loopBack *loopBackDetector
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +56,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
domainStrategy: C.DomainStrategy(options.DomainStrategy),
|
domainStrategy: C.DomainStrategy(options.DomainStrategy),
|
||||||
fallbackDelay: time.Duration(options.FallbackDelay),
|
fallbackDelay: time.Duration(options.FallbackDelay),
|
||||||
dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
|
dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
|
||||||
//nolint:staticcheck
|
|
||||||
isEmpty: reflect.DeepEqual(options.DialerOptions, option.DialerOptions{UDPFragmentDefault: true}) && options.OverrideAddress == "" && options.OverridePort == 0,
|
|
||||||
// loopBack: newLoopBackDetector(router),
|
// loopBack: newLoopBackDetector(router),
|
||||||
}
|
}
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
@ -247,10 +242,6 @@ func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.
|
|||||||
return conn, newDestination, nil
|
return conn, newDestination, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Outbound) IsEmpty() bool {
|
|
||||||
return h.isEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func (h *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
/*func (h *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
if h.loopBack.CheckConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
if h.loopBack.CheckConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
||||||
return E.New("reject loopback connection to ", metadata.Destination)
|
return E.New("reject loopback connection to ", metadata.Destination)
|
||||||
|
@ -85,7 +85,7 @@ 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), h.listener, metadata.Source, onClose)
|
return socks.HandleConnectionEx(ctx, conn, reader, h.authenticator, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, 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, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, onClose)
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,6 @@ func (t *TProxy) NewPacketEx(buffer *buf.Buffer, oob []byte, source M.Socksaddr)
|
|||||||
|
|
||||||
type tproxyPacketWriter struct {
|
type tproxyPacketWriter struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
listener *listener.Listener
|
|
||||||
source netip.AddrPort
|
source netip.AddrPort
|
||||||
destination M.Socksaddr
|
destination M.Socksaddr
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn
|
||||||
@ -131,12 +130,7 @@ type tproxyPacketWriter struct {
|
|||||||
|
|
||||||
func (t *TProxy) preparePacketConnection(source M.Socksaddr, destination M.Socksaddr, userData any) (bool, context.Context, N.PacketWriter, N.CloseHandlerFunc) {
|
func (t *TProxy) preparePacketConnection(source M.Socksaddr, destination M.Socksaddr, userData any) (bool, context.Context, N.PacketWriter, N.CloseHandlerFunc) {
|
||||||
ctx := log.ContextWithNewID(t.ctx)
|
ctx := log.ContextWithNewID(t.ctx)
|
||||||
writer := &tproxyPacketWriter{
|
writer := &tproxyPacketWriter{ctx: ctx, source: source.AddrPort(), destination: destination}
|
||||||
ctx: ctx,
|
|
||||||
listener: t.listener,
|
|
||||||
source: source.AddrPort(),
|
|
||||||
destination: destination,
|
|
||||||
}
|
|
||||||
return true, ctx, writer, func(it error) {
|
return true, ctx, writer, func(it error) {
|
||||||
common.Close(common.PtrOrNil(writer.conn))
|
common.Close(common.PtrOrNil(writer.conn))
|
||||||
}
|
}
|
||||||
@ -152,10 +146,10 @@ func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socks
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var listenConfig net.ListenConfig
|
var listener net.ListenConfig
|
||||||
listenConfig.Control = control.Append(listenConfig.Control, control.ReuseAddr())
|
listener.Control = control.Append(listener.Control, control.ReuseAddr())
|
||||||
listenConfig.Control = control.Append(listenConfig.Control, redir.TProxyWriteBack())
|
listener.Control = control.Append(listener.Control, redir.TProxyWriteBack())
|
||||||
packetConn, err := w.listener.ListenPacket(listenConfig, w.ctx, "udp", destination.String())
|
packetConn, err := listener.ListenPacket(w.ctx, "udp", destination.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -46,16 +46,14 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||||||
var handshakeForServerName map[string]shadowtls.HandshakeConfig
|
var handshakeForServerName map[string]shadowtls.HandshakeConfig
|
||||||
if options.Version > 1 {
|
if options.Version > 1 {
|
||||||
handshakeForServerName = make(map[string]shadowtls.HandshakeConfig)
|
handshakeForServerName = make(map[string]shadowtls.HandshakeConfig)
|
||||||
if options.HandshakeForServerName != nil {
|
for serverName, serverOptions := range options.HandshakeForServerName {
|
||||||
for _, entry := range options.HandshakeForServerName.Entries() {
|
handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions, serverOptions.ServerIsDomain())
|
||||||
handshakeDialer, err := dialer.New(ctx, entry.Value.DialerOptions, entry.Value.ServerIsDomain())
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
handshakeForServerName[serverName] = shadowtls.HandshakeConfig{
|
||||||
handshakeForServerName[entry.Key] = shadowtls.HandshakeConfig{
|
Server: serverOptions.ServerOptions.Build(),
|
||||||
Server: entry.Value.ServerOptions.Build(),
|
Dialer: handshakeDialer,
|
||||||
Dialer: handshakeDialer,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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), h.listener, metadata.Source, onClose)
|
err := socks.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), h.authenticator, adapter.NewUpstreamHandlerEx(metadata, h.newUserConnection, h.streamUserPacketConnection), metadata.Source, 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, nil, M.SocksaddrFromNet(conn.RemoteAddr()), nil)
|
return socks.HandleConnectionEx(ctx, conn, std_bufio.NewReader(conn), l.authenticator, l, M.SocksaddrFromNet(conn.RemoteAddr()), 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) {
|
||||||
|
@ -2,7 +2,6 @@ package route
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@ -307,7 +306,7 @@ func (m *ConnectionManager) connectionCopyEarly(source net.Conn, destination io.
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = payload.ReadOnceFrom(source)
|
_, err = payload.ReadOnceFrom(source)
|
||||||
if err != nil && !(E.IsTimeout(err) || errors.Is(err, io.EOF)) {
|
if err != nil && !E.IsTimeout(err) {
|
||||||
return E.Cause(err, "read payload")
|
return E.Cause(err, "read payload")
|
||||||
}
|
}
|
||||||
_ = source.SetReadDeadline(time.Time{})
|
_ = source.SetReadDeadline(time.Time{})
|
||||||
|
@ -444,32 +444,3 @@ func (r *RuleActionPredefined) String() string {
|
|||||||
options = append(options, common.Map(r.Extra, dns.RR.String)...)
|
options = append(options, common.Map(r.Extra, dns.RR.String)...)
|
||||||
return F.ToString("predefined(", strings.Join(options, ","), ")")
|
return F.ToString("predefined(", strings.Join(options, ","), ")")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuleActionPredefined) Response(request *dns.Msg) *dns.Msg {
|
|
||||||
return &dns.Msg{
|
|
||||||
MsgHdr: dns.MsgHdr{
|
|
||||||
Id: request.Id,
|
|
||||||
Response: true,
|
|
||||||
Authoritative: true,
|
|
||||||
RecursionDesired: true,
|
|
||||||
RecursionAvailable: true,
|
|
||||||
Rcode: r.Rcode,
|
|
||||||
},
|
|
||||||
Question: request.Question,
|
|
||||||
Answer: rewriteRecords(r.Answer, request.Question[0]),
|
|
||||||
Ns: rewriteRecords(r.Ns, request.Question[0]),
|
|
||||||
Extra: rewriteRecords(r.Extra, request.Question[0]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func rewriteRecords(records []dns.RR, question dns.Question) []dns.RR {
|
|
||||||
return common.Map(records, func(it dns.RR) dns.RR {
|
|
||||||
if strings.HasPrefix(it.Header().Name, "*") {
|
|
||||||
if strings.HasSuffix(question.Name, it.Header().Name[1:]) {
|
|
||||||
it = dns.Copy(it)
|
|
||||||
it.Header().Name = question.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return it
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -13,7 +13,7 @@ require (
|
|||||||
github.com/docker/go-connections v0.5.0
|
github.com/docker/go-connections v0.5.0
|
||||||
github.com/gofrs/uuid/v5 v5.3.1
|
github.com/gofrs/uuid/v5 v5.3.1
|
||||||
github.com/sagernet/quic-go v0.49.0-beta.1
|
github.com/sagernet/quic-go v0.49.0-beta.1
|
||||||
github.com/sagernet/sing v0.6.4-0.20250319121229-11d8838dc56d
|
github.com/sagernet/sing v0.6.4-0.20250316065121-38f666955109
|
||||||
github.com/sagernet/sing-quic v0.4.1-beta.1
|
github.com/sagernet/sing-quic v0.4.1-beta.1
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||||
@ -109,7 +109,7 @@ require (
|
|||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||||
github.com/sagernet/sing-mux v0.3.1 // indirect
|
github.com/sagernet/sing-mux v0.3.1 // indirect
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056 // indirect
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056 // indirect
|
||||||
github.com/sagernet/sing-tun v0.6.2-0.20250319123703-35b5747b44ec // indirect
|
github.com/sagernet/sing-tun v0.6.1 // indirect
|
||||||
github.com/sagernet/sing-vmess v0.2.0 // indirect
|
github.com/sagernet/sing-vmess v0.2.0 // indirect
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
|
||||||
github.com/sagernet/tailscale v1.80.3-mod.0 // indirect
|
github.com/sagernet/tailscale v1.80.3-mod.0 // indirect
|
||||||
|
@ -201,8 +201,8 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W
|
|||||||
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.4-0.20250319121229-11d8838dc56d h1:8GJnvXlOBdgCa0spumUzPbMamkEbud4sfNTd8+1YaEg=
|
github.com/sagernet/sing v0.6.4-0.20250316065121-38f666955109 h1:clwEzQu0oiapGllEDtbGQjcmQaIAt8DH3EeOHAWyiKs=
|
||||||
github.com/sagernet/sing v0.6.4-0.20250319121229-11d8838dc56d/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.4-0.20250316065121-38f666955109/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
|
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
|
||||||
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
|
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
|
||||||
github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s=
|
github.com/sagernet/sing-quic v0.4.1-beta.1 h1:V2VfMckT3EQR3ZdfSzJgZZDsvfZZH42QAZpnOnHKa0s=
|
||||||
@ -213,8 +213,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
|
|||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056 h1:GFNJQAHhSXqAfxAw1wDG/QWbdpGH5Na3k8qUynqWnEA=
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056 h1:GFNJQAHhSXqAfxAw1wDG/QWbdpGH5Na3k8qUynqWnEA=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056/go.mod h1:HyacBPIFiKihJQR8LQp56FM4hBtd/7MZXnRxxQIOPsc=
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056/go.mod h1:HyacBPIFiKihJQR8LQp56FM4hBtd/7MZXnRxxQIOPsc=
|
||||||
github.com/sagernet/sing-tun v0.6.2-0.20250319123703-35b5747b44ec h1:9/OYGb9qDmUFIhqd3S+3eni62EKRQR1rSmRH18baA/M=
|
github.com/sagernet/sing-tun v0.6.1 h1:4l0+gnEKcGjlWfUVTD+W0BRApqIny/lU2ZliurE+VMo=
|
||||||
github.com/sagernet/sing-tun v0.6.2-0.20250319123703-35b5747b44ec/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
github.com/sagernet/sing-tun v0.6.1/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||||
github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI=
|
github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI=
|
||||||
github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
|
github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||||
|
@ -20,43 +20,25 @@ import (
|
|||||||
|
|
||||||
func TestShadowTLS(t *testing.T) {
|
func TestShadowTLS(t *testing.T) {
|
||||||
t.Run("v1", func(t *testing.T) {
|
t.Run("v1", func(t *testing.T) {
|
||||||
testShadowTLS(t, 1, "", false, option.ShadowTLSWildcardSNIOff)
|
testShadowTLS(t, 1, "", false)
|
||||||
})
|
})
|
||||||
t.Run("v2", func(t *testing.T) {
|
t.Run("v2", func(t *testing.T) {
|
||||||
testShadowTLS(t, 2, "hello", false, option.ShadowTLSWildcardSNIOff)
|
testShadowTLS(t, 2, "hello", false)
|
||||||
})
|
})
|
||||||
t.Run("v3", func(t *testing.T) {
|
t.Run("v3", func(t *testing.T) {
|
||||||
testShadowTLS(t, 3, "hello", false, option.ShadowTLSWildcardSNIOff)
|
testShadowTLS(t, 3, "hello", false)
|
||||||
})
|
})
|
||||||
t.Run("v2-utls", func(t *testing.T) {
|
t.Run("v2-utls", func(t *testing.T) {
|
||||||
testShadowTLS(t, 2, "hello", true, option.ShadowTLSWildcardSNIOff)
|
testShadowTLS(t, 2, "hello", true)
|
||||||
})
|
})
|
||||||
t.Run("v3-utls", func(t *testing.T) {
|
t.Run("v3-utls", func(t *testing.T) {
|
||||||
testShadowTLS(t, 3, "hello", true, option.ShadowTLSWildcardSNIOff)
|
testShadowTLS(t, 3, "hello", true)
|
||||||
})
|
|
||||||
t.Run("v3-wildcard-sni-authed", func(t *testing.T) {
|
|
||||||
testShadowTLS(t, 3, "hello", false, option.ShadowTLSWildcardSNIAuthed)
|
|
||||||
})
|
|
||||||
t.Run("v3-wildcard-sni-all", func(t *testing.T) {
|
|
||||||
testShadowTLS(t, 3, "hello", false, option.ShadowTLSWildcardSNIAll)
|
|
||||||
})
|
|
||||||
t.Run("v3-wildcard-sni-authed-utls", func(t *testing.T) {
|
|
||||||
testShadowTLS(t, 3, "hello", true, option.ShadowTLSWildcardSNIAll)
|
|
||||||
})
|
|
||||||
t.Run("v3-wildcard-sni-all-utls", func(t *testing.T) {
|
|
||||||
testShadowTLS(t, 3, "hello", true, option.ShadowTLSWildcardSNIAll)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool, wildcardSNI option.WildcardSNI) {
|
func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool) {
|
||||||
method := shadowaead_2022.List[0]
|
method := shadowaead_2022.List[0]
|
||||||
ssPassword := mkBase64(t, 16)
|
ssPassword := mkBase64(t, 16)
|
||||||
var clientServerName string
|
|
||||||
if wildcardSNI != option.ShadowTLSWildcardSNIOff {
|
|
||||||
clientServerName = "cloudflare.com"
|
|
||||||
} else {
|
|
||||||
clientServerName = "google.com"
|
|
||||||
}
|
|
||||||
startInstance(t, option.Options{
|
startInstance(t, option.Options{
|
||||||
Inbounds: []option.Inbound{
|
Inbounds: []option.Inbound{
|
||||||
{
|
{
|
||||||
@ -86,10 +68,9 @@ func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool,
|
|||||||
ServerPort: 443,
|
ServerPort: 443,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Version: version,
|
Version: version,
|
||||||
Password: password,
|
Password: password,
|
||||||
Users: []option.ShadowTLSUser{{Password: password}},
|
Users: []option.ShadowTLSUser{{Password: password}},
|
||||||
WildcardSNI: wildcardSNI,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -127,7 +108,7 @@ func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool,
|
|||||||
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
||||||
TLS: &option.OutboundTLSOptions{
|
TLS: &option.OutboundTLSOptions{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
ServerName: clientServerName,
|
ServerName: "google.com",
|
||||||
UTLS: &option.OutboundUTLSOptions{
|
UTLS: &option.OutboundUTLSOptions{
|
||||||
Enabled: utlsEanbled,
|
Enabled: utlsEanbled,
|
||||||
},
|
},
|
||||||
|
@ -74,10 +74,6 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if header.OpCode.IsControl() {
|
if header.OpCode.IsControl() {
|
||||||
if header.Length > 128 {
|
|
||||||
err = wsutil.ErrFrameTooLarge
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = c.controlHandler(header, c.reader)
|
err = c.controlHandler(header, c.reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user