mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Compare commits
68 Commits
230ac25f2c
...
bc01878605
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bc01878605 | ||
![]() |
7489d3fff7 | ||
![]() |
794c5f81d1 | ||
![]() |
26bf8e3a0e | ||
![]() |
dcb7fb9880 | ||
![]() |
3e991b8068 | ||
![]() |
943d977bbb | ||
![]() |
af9ac17d0d | ||
![]() |
4760fd80ef | ||
![]() |
873b6194b7 | ||
![]() |
b801eb5eed | ||
![]() |
0044fca876 | ||
![]() |
40a8bf2a35 | ||
![]() |
fd460fbf52 | ||
![]() |
a69fd02e6a | ||
![]() |
ed57655e7e | ||
![]() |
e49704c819 | ||
![]() |
fc2724bac2 | ||
![]() |
9536f9f8b3 | ||
![]() |
cb7894b509 | ||
![]() |
0762a81cb3 | ||
![]() |
ab0c4f5c82 | ||
![]() |
b998ce8142 | ||
![]() |
855efbc0f6 | ||
![]() |
5a2a876c1b | ||
![]() |
9ec8100a91 | ||
![]() |
3f1b7919a9 | ||
![]() |
1ad4335d53 | ||
![]() |
f1023e4ea9 | ||
![]() |
989a0406d7 | ||
![]() |
ee6feb1d19 | ||
![]() |
1a5b1cd84c | ||
![]() |
ff6a00351f | ||
![]() |
4222b5d5f2 | ||
![]() |
f58172700a | ||
![]() |
91e3abceda | ||
![]() |
8c3eeb7208 | ||
![]() |
8df21000f8 | ||
![]() |
f3759a6065 | ||
![]() |
a5b95befb9 | ||
![]() |
90d5e7012a | ||
![]() |
a32065ee4f | ||
![]() |
7192e4b095 | ||
![]() |
69fbe7fa5d | ||
![]() |
d0e592a438 | ||
![]() |
2f315e233a | ||
![]() |
6de2817f54 | ||
![]() |
19dc4b8c54 | ||
![]() |
abf15ce617 | ||
![]() |
c77a1c4378 | ||
![]() |
011570491e | ||
![]() |
a8e3f53846 | ||
![]() |
17d7b212d4 | ||
![]() |
49c2b013d9 | ||
![]() |
d118cd28d2 | ||
![]() |
9b1a56f1f9 | ||
![]() |
11564386ef | ||
![]() |
9718996b62 | ||
![]() |
11ca25db71 | ||
![]() |
1e2293decf | ||
![]() |
bf16a98aab | ||
![]() |
882ccecae8 | ||
![]() |
c2cb4f4acd | ||
![]() |
d08375b1e3 | ||
![]() |
5a40ca4a8e | ||
![]() |
6ed29d81c1 | ||
![]() |
44329157c1 | ||
![]() |
5c495b3779 |
@ -1,12 +1,11 @@
|
||||
-s dir
|
||||
--name sing-box
|
||||
--category net
|
||||
--license GPL-3.0-or-later
|
||||
--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"
|
||||
--no-deb-generate-changes
|
||||
--config-files /etc/sing-box/config.json
|
||||
|
||||
release/config/config.json=/etc/sing-box/config.json
|
30
.fpm_openwrt
30
.fpm_openwrt
@ -1,30 +0,0 @@
|
||||
-s dir
|
||||
--name sing-box
|
||||
--category net
|
||||
--license GPL-3.0-or-later
|
||||
--description "The universal proxy platform."
|
||||
--url "https://sing-box.sagernet.org/"
|
||||
--maintainer "nekohasekai <contact-git@sekai.icu>"
|
||||
--no-deb-generate-changes
|
||||
|
||||
--config-files /etc/config/sing-box
|
||||
--config-files /etc/sing-box/config.json
|
||||
|
||||
--depends ca-bundle
|
||||
--depends kmod-inet-diag
|
||||
--depends kmod-tun
|
||||
--depends firewall4
|
||||
|
||||
--before-remove release/config/openwrt.prerm
|
||||
|
||||
release/config/config.json=/etc/sing-box/config.json
|
||||
|
||||
release/config/openwrt.conf=/etc/config/sing-box
|
||||
release/config/openwrt.init=/etc/init.d/sing-box
|
||||
release/config/openwrt.keep=/lib/upgrade/keep.d/sing-box
|
||||
|
||||
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
|
28
.github/deb2ipk.sh
vendored
28
.github/deb2ipk.sh
vendored
@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# mod from https://gist.github.com/pldubouilh/c5703052986bfdd404005951dee54683
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
PROJECT=$(dirname "$0")/../..
|
||||
TMP_PATH=`mktemp -d`
|
||||
cp $2 $TMP_PATH
|
||||
pushd $TMP_PATH
|
||||
|
||||
DEB_NAME=`ls *.deb`
|
||||
ar x $DEB_NAME
|
||||
|
||||
mkdir control
|
||||
pushd control
|
||||
tar xf ../control.tar.gz
|
||||
rm md5sums
|
||||
sed "s/Architecture:\\ \w*/Architecture:\\ $1/g" ./control -i
|
||||
cat control
|
||||
tar czf ../control.tar.gz ./*
|
||||
popd
|
||||
|
||||
DEB_NAME=${DEB_NAME%.deb}
|
||||
tar czf $DEB_NAME.ipk control.tar.gz data.tar.gz debian-binary
|
||||
popd
|
||||
|
||||
cp $TMP_PATH/$DEB_NAME.ipk $3
|
||||
rm -r $TMP_PATH
|
87
.github/workflows/build.yml
vendored
87
.github/workflows/build.yml
vendored
@ -68,38 +68,31 @@ jobs:
|
||||
- calculate_version
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ linux, windows, darwin, android ]
|
||||
arch: [ "386", amd64, arm64 ]
|
||||
legacy_go: [ false ]
|
||||
include:
|
||||
- { os: linux, arch: amd64, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64" }
|
||||
- { os: linux, arch: "386", go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4" }
|
||||
- { os: linux, arch: "386", go386: softfloat, openwrt: "i386_pentium-mmx" }
|
||||
- { os: linux, arch: arm64, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic" }
|
||||
- { os: linux, arch: arm, goarm: "5", openwrt: "arm_arm926ej-s arm_cortex-a7 arm_cortex-a9 arm_fa526 arm_xscale" }
|
||||
- { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl, openwrt: "arm_arm1176jzf-s_vfp" }
|
||||
- { os: linux, arch: arm, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4" }
|
||||
- { os: linux, arch: mips, gomips: softfloat, openwrt: "mips_24kc mips_4kec mips_mips32" }
|
||||
- { os: linux, arch: mipsle, gomips: hardfloat, debian: mipsel, rpm: mipsel, openwrt: "mipsel_24kc_24kf" }
|
||||
- { os: linux, arch: mipsle, gomips: softfloat, openwrt: "mipsel_24kc mipsel_74kc mipsel_mips32" }
|
||||
- { os: linux, arch: mips64, gomips: softfloat, openwrt: "mips64_mips64r2 mips64_octeonplus" }
|
||||
- { os: linux, arch: mips64le, gomips: hardfloat, debian: mips64el, rpm: mips64el }
|
||||
- { os: linux, arch: mips64le, gomips: softfloat, openwrt: "mips64el_mips64r2" }
|
||||
- { 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, openwrt: "riscv64_generic" }
|
||||
- { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64, openwrt: "loongarch64_generic" }
|
||||
- { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64 }
|
||||
- { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64 }
|
||||
|
||||
- { os: windows, arch: amd64 }
|
||||
- { os: windows, arch: amd64, legacy_go: true }
|
||||
- { os: windows, arch: "386" }
|
||||
- { os: windows, arch: "386", legacy_go: true }
|
||||
- { os: windows, arch: arm64 }
|
||||
|
||||
- { os: darwin, arch: amd64 }
|
||||
- { os: darwin, arch: arm64 }
|
||||
- { os: windows, arch: amd64, legacy_go: true }
|
||||
|
||||
- { os: android, arch: "386", ndk: "i686-linux-android21" }
|
||||
- { os: android, arch: amd64, ndk: "x86_64-linux-android21" }
|
||||
- { os: android, arch: arm64, ndk: "aarch64-linux-android21" }
|
||||
- { os: android, arch: arm, ndk: "armv7a-linux-androideabi21" }
|
||||
- { os: android, arch: amd64, ndk: "x86_64-linux-android21" }
|
||||
- { os: android, arch: "386", ndk: "i686-linux-android21" }
|
||||
exclude:
|
||||
- { os: darwin, arch: "386" }
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
@ -154,10 +147,7 @@ jobs:
|
||||
CGO_ENABLED: "0"
|
||||
GOOS: ${{ matrix.os }}
|
||||
GOARCH: ${{ matrix.arch }}
|
||||
GO386: ${{ matrix.go386 }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
GOMIPS: ${{ matrix.gomips }}
|
||||
GOMIPS64: ${{ matrix.gomips }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build Android
|
||||
if: matrix.os == 'android'
|
||||
@ -177,19 +167,14 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Set name
|
||||
run: |-
|
||||
DIR_NAME="sing-box-${{ needs.calculate_version.outputs.version }}-${{ matrix.os }}-${{ matrix.arch }}"
|
||||
if [[ -n "${{ matrix.goarm }}" ]]; then
|
||||
DIR_NAME="${DIR_NAME}v${{ matrix.goarm }}"
|
||||
elif [[ -n "${{ matrix.go386 }}" && "${{ matrix.go386 }}" != 'sse2' ]]; then
|
||||
DIR_NAME="${DIR_NAME}-${{ matrix.go386 }}"
|
||||
elif [[ -n "${{ matrix.gomips }}" && "${{ matrix.gomips }}" != 'hardfloat' ]]; then
|
||||
DIR_NAME="${DIR_NAME}-${{ matrix.gomips }}"
|
||||
elif [[ "${{ matrix.legacy_go }}" == 'true' ]]; then
|
||||
DIR_NAME="${DIR_NAME}-legacy"
|
||||
fi
|
||||
ARM_VERSION=$([ -n '${{ matrix.goarm}}' ] && echo 'v${{ matrix.goarm}}' || true)
|
||||
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}"
|
||||
PKG_VERSION="${{ needs.calculate_version.outputs.version }}"
|
||||
PKG_VERSION="${PKG_VERSION//-/\~}-1"
|
||||
PKG_VERSION="${PKG_VERSION//-/\~}"
|
||||
echo "PKG_VERSION=${PKG_VERSION}" >> "${GITHUB_ENV}"
|
||||
- name: Package DEB
|
||||
if: matrix.debian != ''
|
||||
@ -197,10 +182,9 @@ jobs:
|
||||
set -xeuo pipefail
|
||||
sudo gem install fpm
|
||||
sudo apt-get install -y debsigs
|
||||
cp .fpm_systemd .fpm
|
||||
fpm -t deb \
|
||||
-v "$PKG_VERSION" \
|
||||
-p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.debian }}.deb" \
|
||||
-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'
|
||||
@ -215,10 +199,9 @@ jobs:
|
||||
run: |-
|
||||
set -xeuo pipefail
|
||||
sudo gem install fpm
|
||||
cp .fpm_systemd .fpm
|
||||
fpm -t rpm \
|
||||
-v "$PKG_VERSION" \
|
||||
-p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.rpm }}.rpm" \
|
||||
-p "dist/${PKG_NAME}.rpm" \
|
||||
--architecture ${{ matrix.rpm }} \
|
||||
dist/sing-box=/usr/bin/sing-box
|
||||
cat > $HOME/.rpmmacros <<EOF
|
||||
@ -235,27 +218,11 @@ jobs:
|
||||
set -xeuo pipefail
|
||||
sudo gem install fpm
|
||||
sudo apt-get install -y libarchive-tools
|
||||
cp .fpm_systemd .fpm
|
||||
fpm -t pacman \
|
||||
-v "$PKG_VERSION" \
|
||||
-p "dist/sing-box_${{ needs.calculate_version.outputs.version }}_${{ matrix.os }}_${{ matrix.pacman }}.pkg.tar.zst" \
|
||||
-p "dist/${PKG_NAME}.pkg.tar.zst" \
|
||||
--architecture ${{ matrix.pacman }} \
|
||||
dist/sing-box=/usr/bin/sing-box
|
||||
- name: Package OpenWrt
|
||||
if: matrix.openwrt != ''
|
||||
run: |-
|
||||
set -xeuo pipefail
|
||||
sudo gem install fpm
|
||||
cp .fpm_openwrt .fpm
|
||||
fpm -t deb \
|
||||
-v "$PKG_VERSION" \
|
||||
-p "dist/openwrt.deb" \
|
||||
--architecture all \
|
||||
dist/sing-box=/usr/bin/sing-box
|
||||
for architecture in ${{ matrix.openwrt }}; do
|
||||
.github/deb2ipk.sh "$architecture" "dist/openwrt.deb" "dist/sing-box_${{ needs.calculate_version.outputs.version }}_openwrt_${architecture}.ipk"
|
||||
done
|
||||
rm "dist/openwrt.deb"
|
||||
- name: Archive
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
@ -275,7 +242,7 @@ jobs:
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: binary-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.go386 && format('_{0}', matrix.go386) }}${{ matrix.gomips && format('_{0}', matrix.gomips) }}${{ matrix.legacy_go && '-legacy' || '' }}
|
||||
name: binary-${{ matrix.os }}_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.legacy_go && '-legacy' || '' }}
|
||||
path: "dist"
|
||||
build_android:
|
||||
name: Build Android
|
||||
|
6
Makefile
6
Makefile
@ -8,7 +8,7 @@ GOHOSTARCH = $(shell go env GOHOSTARCH)
|
||||
VERSION=$(shell CGO_ENABLED=0 GOOS=$(GOHOSTOS) GOARCH=$(GOHOSTARCH) go run ./cmd/internal/read_tag)
|
||||
|
||||
PARAMS = -v -trimpath -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=$(VERSION)' -s -w -buildid="
|
||||
MAIN_PARAMS = $(PARAMS) -tags "$(TAGS)"
|
||||
MAIN_PARAMS = $(PARAMS) -tags $(TAGS)
|
||||
MAIN = ./cmd/sing-box
|
||||
PREFIX ?= $(shell go env GOPATH)
|
||||
|
||||
@ -24,7 +24,7 @@ ci_build:
|
||||
go build $(MAIN_PARAMS) $(MAIN)
|
||||
|
||||
generate_completions:
|
||||
go run -v --tags "$(TAGS),generate,generate_completions" $(MAIN)
|
||||
go run -v --tags $(TAGS),generate,generate_completions $(MAIN)
|
||||
|
||||
install:
|
||||
go build -o $(PREFIX)/bin/$(NAME) $(MAIN_PARAMS) $(MAIN)
|
||||
@ -246,4 +246,4 @@ clean:
|
||||
update:
|
||||
git fetch
|
||||
git reset FETCH_HEAD --hard
|
||||
git clean -fdx
|
||||
git clean -fdx
|
@ -1 +1 @@
|
||||
Subproject commit 55f31c29bb68895ce544e0dfbf852b4b3e32b530
|
||||
Subproject commit 8354b78e5d002d636827cfeed6ed5df8ea057452
|
@ -83,7 +83,6 @@ func NewWithOptions(options Options) (N.Dialer, error) {
|
||||
dialOptions.DomainStrategy != option.DomainStrategy(C.DomainStrategyAsIS) {
|
||||
//nolint:staticcheck
|
||||
strategy = C.DomainStrategy(dialOptions.DomainStrategy)
|
||||
deprecated.Report(options.Context, deprecated.OptionLegacyDomainStrategyOptions)
|
||||
}
|
||||
server = dialOptions.DomainResolver.Server
|
||||
dnsQueryOptions = adapter.DNSQueryOptions{
|
||||
@ -96,31 +95,22 @@ func NewWithOptions(options Options) (N.Dialer, error) {
|
||||
resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay)
|
||||
} else if options.DirectResolver {
|
||||
return nil, E.New("missing domain resolver for domain server address")
|
||||
} else {
|
||||
if defaultOptions.DomainResolver != "" {
|
||||
dnsQueryOptions = defaultOptions.DomainResolveOptions
|
||||
transport, loaded := dnsTransport.Transport(defaultOptions.DomainResolver)
|
||||
if !loaded {
|
||||
return nil, E.New("default domain resolver not found: " + defaultOptions.DomainResolver)
|
||||
}
|
||||
dnsQueryOptions.Transport = transport
|
||||
resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay)
|
||||
} else {
|
||||
transports := dnsTransport.Transports()
|
||||
if len(transports) < 2 {
|
||||
dnsQueryOptions.Transport = dnsTransport.Default()
|
||||
} else if options.NewDialer {
|
||||
return nil, E.New("missing domain resolver for domain server address")
|
||||
} else if !options.DirectOutbound {
|
||||
deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver)
|
||||
}
|
||||
} else if defaultOptions.DomainResolver != "" {
|
||||
dnsQueryOptions = defaultOptions.DomainResolveOptions
|
||||
transport, loaded := dnsTransport.Transport(defaultOptions.DomainResolver)
|
||||
if !loaded {
|
||||
return nil, E.New("default domain resolver not found: " + defaultOptions.DomainResolver)
|
||||
}
|
||||
if
|
||||
//nolint:staticcheck
|
||||
dialOptions.DomainStrategy != option.DomainStrategy(C.DomainStrategyAsIS) {
|
||||
//nolint:staticcheck
|
||||
dnsQueryOptions.Strategy = C.DomainStrategy(dialOptions.DomainStrategy)
|
||||
deprecated.Report(options.Context, deprecated.OptionLegacyDomainStrategyOptions)
|
||||
dnsQueryOptions.Transport = transport
|
||||
resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay)
|
||||
} else {
|
||||
transports := dnsTransport.Transports()
|
||||
if len(transports) < 2 {
|
||||
dnsQueryOptions.Transport = dnsTransport.Default()
|
||||
} else if options.NewDialer {
|
||||
return nil, E.New("missing domain resolver for domain server address")
|
||||
} else if !options.DirectOutbound {
|
||||
deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver)
|
||||
}
|
||||
}
|
||||
dialer = NewResolveDialer(
|
||||
|
@ -89,20 +89,16 @@ func NewRealityServer(ctx context.Context, logger log.Logger, options option.Inb
|
||||
tlsConfig.MaxTimeDiff = time.Duration(options.Reality.MaxTimeDifference)
|
||||
|
||||
tlsConfig.ShortIds = make(map[[8]byte]bool)
|
||||
if len(options.Reality.ShortID) == 0 {
|
||||
tlsConfig.ShortIds[[8]byte{0}] = true
|
||||
} else {
|
||||
for i, shortIDString := range options.Reality.ShortID {
|
||||
var shortID [8]byte
|
||||
decodedLen, err := hex.Decode(shortID[:], []byte(shortIDString))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "decode short_id[", i, "]: ", shortIDString)
|
||||
}
|
||||
if decodedLen > 8 {
|
||||
return nil, E.New("invalid short_id[", i, "]: ", shortIDString)
|
||||
}
|
||||
tlsConfig.ShortIds[shortID] = true
|
||||
for i, shortIDString := range options.Reality.ShortID {
|
||||
var shortID [8]byte
|
||||
decodedLen, err := hex.Decode(shortID[:], []byte(shortIDString))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "decode short_id[", i, "]: ", shortIDString)
|
||||
}
|
||||
if decodedLen > 8 {
|
||||
return nil, E.New("invalid short_id[", i, "]: ", shortIDString)
|
||||
}
|
||||
tlsConfig.ShortIds[shortID] = true
|
||||
}
|
||||
|
||||
handshakeDialer, err := dialer.New(ctx, options.Reality.Handshake.DialerOptions, options.Reality.Handshake.ServerIsDomain())
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/fswatch"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
@ -234,12 +233,8 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
|
||||
key = content
|
||||
}
|
||||
if certificate == nil && key == nil && options.Insecure {
|
||||
timeFunc := ntp.TimeFuncFromContext(ctx)
|
||||
if timeFunc == nil {
|
||||
timeFunc = time.Now
|
||||
}
|
||||
tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return GenerateKeyPair(nil, nil, timeFunc, info.ServerName)
|
||||
return GenerateKeyPair(nil, nil, ntp.TimeFuncFromContext(ctx), info.ServerName)
|
||||
}
|
||||
} else {
|
||||
if certificate == nil {
|
||||
|
@ -35,7 +35,6 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
||||
}
|
||||
return &Transport{
|
||||
TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options),
|
||||
ctx: ctx,
|
||||
hosts: hosts.NewFile(hosts.DefaultPath),
|
||||
dialer: transportDialer,
|
||||
}, nil
|
||||
@ -58,7 +57,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
|
||||
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
|
||||
}
|
||||
}
|
||||
systemConfig := getSystemDNSConfig(t.ctx)
|
||||
systemConfig := getSystemDNSConfig()
|
||||
if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) {
|
||||
return t.exchangeSingleRequest(ctx, systemConfig, message, domain)
|
||||
} else {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
@ -24,21 +23,19 @@ type resolverConfig struct {
|
||||
|
||||
var resolvConf resolverConfig
|
||||
|
||||
func getSystemDNSConfig(ctx context.Context) *dnsConfig {
|
||||
resolvConf.tryUpdate(ctx, "/etc/resolv.conf")
|
||||
func getSystemDNSConfig() *dnsConfig {
|
||||
resolvConf.tryUpdate("/etc/resolv.conf")
|
||||
return resolvConf.dnsConfig.Load()
|
||||
}
|
||||
|
||||
func (conf *resolverConfig) init(ctx context.Context) {
|
||||
conf.dnsConfig.Store(dnsReadConfig(ctx, "/etc/resolv.conf"))
|
||||
func (conf *resolverConfig) init() {
|
||||
conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf"))
|
||||
conf.lastChecked = time.Now()
|
||||
conf.ch = make(chan struct{}, 1)
|
||||
}
|
||||
|
||||
func (conf *resolverConfig) tryUpdate(ctx context.Context, name string) {
|
||||
conf.initOnce.Do(func() {
|
||||
conf.init(ctx)
|
||||
})
|
||||
func (conf *resolverConfig) tryUpdate(name string) {
|
||||
conf.initOnce.Do(conf.init)
|
||||
|
||||
if conf.dnsConfig.Load().noReload {
|
||||
return
|
||||
@ -62,7 +59,7 @@ func (conf *resolverConfig) tryUpdate(ctx context.Context, name string) {
|
||||
return
|
||||
}
|
||||
}
|
||||
dnsConf := dnsReadConfig(ctx, name)
|
||||
dnsConf := dnsReadConfig(name)
|
||||
conf.dnsConfig.Store(dnsConf)
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ package local
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
@ -19,7 +18,7 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func dnsReadConfig(_ context.Context, _ string) *dnsConfig {
|
||||
func dnsReadConfig(_ string) *dnsConfig {
|
||||
if C.res_init() != 0 {
|
||||
return &dnsConfig{
|
||||
servers: defaultNS,
|
||||
|
@ -4,7 +4,6 @@ package local
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
@ -14,7 +13,7 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func dnsReadConfig(_ context.Context, name string) *dnsConfig {
|
||||
func dnsReadConfig(name string) *dnsConfig {
|
||||
conf := &dnsConfig{
|
||||
ndots: 1,
|
||||
timeout: 5 * time.Second,
|
||||
|
@ -1,7 +1,6 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
@ -9,13 +8,10 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func dnsReadConfig(ctx context.Context, _ string) *dnsConfig {
|
||||
func dnsReadConfig(_ string) *dnsConfig {
|
||||
conf := &dnsConfig{
|
||||
ndots: 1,
|
||||
timeout: 5 * time.Second,
|
||||
@ -26,35 +22,35 @@ func dnsReadConfig(ctx context.Context, _ string) *dnsConfig {
|
||||
conf.servers = defaultNS
|
||||
}
|
||||
}()
|
||||
addresses, err := adapterAddresses()
|
||||
aas, err := adapterAddresses()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var dnsAddresses []struct {
|
||||
ifName string
|
||||
netip.Addr
|
||||
}
|
||||
for _, address := range addresses {
|
||||
if address.OperStatus != windows.IfOperStatusUp {
|
||||
|
||||
for _, aa := range aas {
|
||||
// Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs.
|
||||
if aa.OperStatus != windows.IfOperStatusUp {
|
||||
continue
|
||||
}
|
||||
if address.IfType == windows.IF_TYPE_TUNNEL {
|
||||
|
||||
// Only take interfaces which have at least one gateway
|
||||
if aa.FirstGatewayAddress == nil {
|
||||
continue
|
||||
}
|
||||
if address.FirstGatewayAddress == nil {
|
||||
continue
|
||||
}
|
||||
for dnsServerAddress := address.FirstDnsServerAddress; dnsServerAddress != nil; dnsServerAddress = dnsServerAddress.Next {
|
||||
rawSockaddr, err := dnsServerAddress.Address.Sockaddr.Sockaddr()
|
||||
|
||||
for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next {
|
||||
sa, err := dns.Address.Sockaddr.Sockaddr()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var dnsServerAddr netip.Addr
|
||||
switch sockaddr := rawSockaddr.(type) {
|
||||
var ip netip.Addr
|
||||
switch sa := sa.(type) {
|
||||
case *syscall.SockaddrInet4:
|
||||
dnsServerAddr = netip.AddrFrom4(sockaddr.Addr)
|
||||
ip = netip.AddrFrom4([4]byte{sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]})
|
||||
case *syscall.SockaddrInet6:
|
||||
if sockaddr.Addr[0] == 0xfe && sockaddr.Addr[1] == 0xc0 {
|
||||
var addr16 [16]byte
|
||||
copy(addr16[:], sa.Addr[:])
|
||||
if addr16[0] == 0xfe && addr16[1] == 0xc0 {
|
||||
// fec0/10 IPv6 addresses are site local anycast DNS
|
||||
// addresses Microsoft sets by default if no other
|
||||
// IPv6 DNS address is set. Site local anycast is
|
||||
@ -62,27 +58,14 @@ func dnsReadConfig(ctx context.Context, _ string) *dnsConfig {
|
||||
// https://datatracker.ietf.org/doc/html/rfc3879
|
||||
continue
|
||||
}
|
||||
dnsServerAddr = netip.AddrFrom16(sockaddr.Addr)
|
||||
ip = netip.AddrFrom16(addr16)
|
||||
default:
|
||||
// Unexpected type.
|
||||
continue
|
||||
}
|
||||
dnsAddresses = append(dnsAddresses, struct {
|
||||
ifName string
|
||||
netip.Addr
|
||||
}{ifName: windows.UTF16PtrToString(address.FriendlyName), Addr: dnsServerAddr})
|
||||
conf.servers = append(conf.servers, net.JoinHostPort(ip.String(), "53"))
|
||||
}
|
||||
}
|
||||
var myInterface string
|
||||
if networkManager := service.FromContext[adapter.NetworkManager](ctx); networkManager != nil {
|
||||
myInterface = networkManager.InterfaceMonitor().MyInterface()
|
||||
}
|
||||
for _, address := range dnsAddresses {
|
||||
if address.ifName == myInterface {
|
||||
continue
|
||||
}
|
||||
conf.servers = append(conf.servers, net.JoinHostPort(address.String(), "53"))
|
||||
}
|
||||
return conf
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ func (t *UDPTransport) exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M
|
||||
conn.access.Unlock()
|
||||
defer func() {
|
||||
conn.access.Lock()
|
||||
delete(conn.callbacks, exMessage.Id)
|
||||
delete(conn.callbacks, messageId)
|
||||
conn.access.Unlock()
|
||||
}()
|
||||
rawMessage, err := exMessage.PackBuffer(buffer.FreeBytes())
|
||||
|
@ -2,22 +2,6 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.12.0-beta.4
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.11.8
|
||||
|
||||
* Improve `auto_redirect` **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
Now `auto_redirect` fixes compatibility issues between TUN and Docker bridge networks,
|
||||
see [Tun](/configuration/inbound/tun/#auto_redirect).
|
||||
|
||||
_We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we violated the rules (TestFlight users are not affected)._
|
||||
|
||||
#### 1.12.0-beta.3
|
||||
|
||||
* Fixes and improvements
|
||||
|
@ -9,10 +9,6 @@ and the data generated by the software is always on your device.
|
||||
|
||||
## Android
|
||||
|
||||
The broad package (App) visibility (QUERY_ALL_PACKAGES) permission
|
||||
is used to provide per-application proxy features for VPN,
|
||||
sing-box will not collect your app list.
|
||||
|
||||
If your configuration contains `wifi_ssid` or `wifi_bssid` routing rules,
|
||||
sing-box uses the location permission in the background
|
||||
to get information about the connected Wi-Fi network to make them work.
|
||||
|
@ -27,20 +27,19 @@ icon: material/alert-decagram
|
||||
|
||||
The type of the DNS server.
|
||||
|
||||
| Type | Format |
|
||||
|-----------------|---------------------------|
|
||||
| empty (default) | [Legacy](./legacy/) |
|
||||
| `local` | [Local](./local/) |
|
||||
| `hosts` | [Hosts](./hosts/) |
|
||||
| `tcp` | [TCP](./tcp/) |
|
||||
| `udp` | [UDP](./udp/) |
|
||||
| `tls` | [TLS](./tls/) |
|
||||
| `quic` | [QUIC](./quic/) |
|
||||
| `https` | [HTTPS](./https/) |
|
||||
| `h3` | [HTTP/3](./http3/) |
|
||||
| `dhcp` | [DHCP](./dhcp/) |
|
||||
| `fakeip` | [Fake IP](./fakeip/) |
|
||||
| `tailscale` | [Tailscale](./tailscale/) |
|
||||
| Type | Format |
|
||||
|-----------------|-----------------------------|
|
||||
| empty (default) | [Legacy](./legacy/) |
|
||||
| `tcp` | [TCP](./tcp/) |
|
||||
| `udp` | [UDP](./udp/) |
|
||||
| `tls` | [TLS](./tls/) |
|
||||
| `https` | [HTTPS](./https/) |
|
||||
| `quic` | [QUIC](./quic/) |
|
||||
| `h3` | [HTTP/3](./http3/) |
|
||||
| `predefined` | [Predefined](./predefined/) |
|
||||
| `dhcp` | [DHCP](./dhcp/) |
|
||||
| `fakeip` | [Fake IP](./fakeip/) |
|
||||
| `tailscale` | [Tailscale](./tailscale/) |
|
||||
|
||||
#### tag
|
||||
|
||||
|
@ -27,20 +27,19 @@ icon: material/alert-decagram
|
||||
|
||||
DNS 服务器的类型。
|
||||
|
||||
| 类型 | 格式 |
|
||||
|-----------------|---------------------------|
|
||||
| empty (default) | [Legacy](./legacy/) |
|
||||
| `local` | [Local](./local/) |
|
||||
| `hosts` | [Hosts](./hosts/) |
|
||||
| `tcp` | [TCP](./tcp/) |
|
||||
| `udp` | [UDP](./udp/) |
|
||||
| `tls` | [TLS](./tls/) |
|
||||
| `quic` | [QUIC](./quic/) |
|
||||
| `https` | [HTTPS](./https/) |
|
||||
| `h3` | [HTTP/3](./http3/) |
|
||||
| `dhcp` | [DHCP](./dhcp/) |
|
||||
| `fakeip` | [Fake IP](./fakeip/) |
|
||||
| `tailscale` | [Tailscale](./tailscale/) |
|
||||
| 类型 | 格式 |
|
||||
|-----------------|-----------------------------|
|
||||
| empty (default) | [Legacy](./legacy/) |
|
||||
| `tcp` | [TCP](./tcp/) |
|
||||
| `udp` | [UDP](./udp/) |
|
||||
| `tls` | [TLS](./tls/) |
|
||||
| `https` | [HTTPS](./https/) |
|
||||
| `quic` | [QUIC](./quic/) |
|
||||
| `h3` | [HTTP/3](./http3/) |
|
||||
| `predefined` | [Predefined](./predefined/) |
|
||||
| `dhcp` | [DHCP](./dhcp/) |
|
||||
| `fakeip` | [Fake IP](./fakeip/) |
|
||||
| `tailscale` | [Tailscale](./tailscale/) |
|
||||
|
||||
#### tag
|
||||
|
||||
|
@ -213,7 +213,7 @@ Set the default route to the Tun.
|
||||
|
||||
!!! note "Also enable `auto_redirect`"
|
||||
|
||||
`auto_redirect` is always recommended on Linux, it provides better routing, higher performance (better than tproxy), and avoids conflicts between TUN and Docker bridge networks.
|
||||
`auto_redirect` is always recommended on Linux, it provides better routing, higher performance (better than tproxy), and avoids conflicts with Docker bridge networks.
|
||||
|
||||
#### iproute2_table_index
|
||||
|
||||
@ -239,21 +239,20 @@ Linux iproute2 rule start index generated by `auto_route`.
|
||||
|
||||
Only supported on Linux with `auto_route` enabled.
|
||||
|
||||
Improve TUN routing and performance using nftables.
|
||||
Automatically configure iptables/nftables to redirect connections.
|
||||
|
||||
`auto_redirect` is always recommended on Linux, it provides better routing,
|
||||
Auto redirect is always recommended on Linux, it provides better routing,
|
||||
higher performance (better than tproxy),
|
||||
and avoids conflicts between TUN and Docker bridge networks.
|
||||
and avoids conflicts with Docker bridge networks.
|
||||
|
||||
Note that `auto_redirect` also works on Android,
|
||||
but due to the lack of `nftables` and `ip6tables`,
|
||||
only simple IPv4 TCP forwarding is performed.
|
||||
To share your VPN connection over hotspot or repeater on Android,
|
||||
*In Android*:
|
||||
|
||||
Only local IPv4 connections are forwarded. To share your VPN connection over hotspot or repeater,
|
||||
use [VPNHotspot](https://github.com/Mygod/VPNHotspot).
|
||||
|
||||
`auto_redirect` also automatically inserts compatibility rules
|
||||
into the OpenWrt fw4 table, i.e.
|
||||
it will work on routers without any extra configuration.
|
||||
*In Linux*:
|
||||
|
||||
`auto_route` with `auto_redirect` works as expected on routers **without intervention**.
|
||||
|
||||
Conflict with `route.default_mark` and `[dialOptions].routing_mark`.
|
||||
|
||||
@ -280,15 +279,17 @@ Enforce strict routing rules when `auto_route` is enabled:
|
||||
*In Linux*:
|
||||
|
||||
* Let unsupported network unreachable
|
||||
* For legacy reasons, when neither `strict_route` nor `auto_redirect` are enabled, all ICMP traffic will not go through TUN.
|
||||
* Make ICMP traffic route to tun instead of upstream interfaces
|
||||
* Route all connections to tun
|
||||
|
||||
It prevents IP address leaks and makes DNS hijacking work on Android.
|
||||
|
||||
*In Windows*:
|
||||
|
||||
* Let unsupported network unreachable
|
||||
* prevent DNS leak caused by
|
||||
* Add firewall rules to prevent DNS leak caused by
|
||||
Windows' [ordinary multihomed DNS resolution behavior](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd197552%28v%3Dws.10%29)
|
||||
|
||||
It may prevent some Windows applications (such as VirtualBox) from working properly in certain situations.
|
||||
It may prevent some applications (such as VirtualBox) from working properly in certain situations.
|
||||
|
||||
#### route_address
|
||||
|
||||
|
@ -217,7 +217,7 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
!!! note "也启用 `auto_redirect`"
|
||||
|
||||
在 Linux 上始终推荐使用 `auto_redirect`,它提供更好的路由, 更高的性能(优于 tproxy), 并避免 TUN 与 Docker 桥接网络冲突。
|
||||
在 Linux 上始终推荐使用 `auto_redirect`,它提供更好的路由, 更高的性能(优于 tproxy), 并避免与 Docker 桥接网络冲突。
|
||||
|
||||
#### iproute2_table_index
|
||||
|
||||
@ -241,16 +241,19 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Linux,且需要 `auto_route` 已启用。
|
||||
仅支持 Linux,且需要 `auto_route` 已启用。
|
||||
|
||||
通过使用 nftables 改善 TUN 路由和性能。
|
||||
自动配置 iptables/nftables 以重定向连接。
|
||||
|
||||
在 Linux 上始终推荐使用 `auto_redirect`,它提供更好的路由、更高的性能(优于 tproxy),并避免了 TUN 和 Docker 桥接网络之间的冲突。
|
||||
在 Linux 上始终推荐使用 auto redirect,它提供更好的路由, 更高的性能(优于 tproxy), 并避免与 Docker 桥接网络冲突。
|
||||
|
||||
请注意,`auto_redirect` 也适用于 Android,但由于缺少 `nftables` 和 `ip6tables`,仅执行简单的 IPv4 TCP 转发。
|
||||
若要在 Android 上通过热点或中继器共享 VPN 连接,请使用 [VPNHotspot](https://github.com/Mygod/VPNHotspot)。
|
||||
*在 Android 中*:
|
||||
|
||||
`auto_redirect` 还会自动将兼容性规则插入 OpenWrt 的 fw4 表中,即无需额外配置即可在路由器上工作。
|
||||
仅转发本地 IPv4 连接。 要通过热点或中继共享您的 VPN 连接,请使用 [VPNHotspot](https://github.com/Mygod/VPNHotspot)。
|
||||
|
||||
*在 Linux 中*:
|
||||
|
||||
带有 `auto_redirect` 的 `auto_route` 在路由器上**无需干预**即可按预期工作。
|
||||
|
||||
与 `route.default_mark` 和 `[dialOptions].routing_mark` 冲突。
|
||||
|
||||
@ -258,7 +261,7 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
`auto_redirect` 使用的连接输入标记。
|
||||
`auto_redriect` 使用的连接输入标记。
|
||||
|
||||
默认使用 `0x2023`。
|
||||
|
||||
@ -266,25 +269,29 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
`auto_redirect` 使用的连接输出标记。
|
||||
`auto_redriect` 使用的连接输出标记。
|
||||
|
||||
默认使用 `0x2024`。
|
||||
|
||||
#### strict_route
|
||||
|
||||
当启用 `auto_route` 时,强制执行严格的路由规则:
|
||||
启用 `auto_route` 时执行严格的路由规则。
|
||||
|
||||
*在 Linux 中*:
|
||||
*在 Linux 中*:
|
||||
|
||||
* 使不支持的网络不可达。
|
||||
* 出于历史遗留原因,当未启用 `strict_route` 或 `auto_redirect` 时,所有 ICMP 流量将不会通过 TUN。
|
||||
* 让不支持的网络无法到达
|
||||
* 使 ICMP 流量路由到 tun 而不是上游接口
|
||||
* 将所有连接路由到 tun
|
||||
|
||||
*在 Windows 中*:
|
||||
它可以防止 IP 地址泄漏,并使 DNS 劫持在 Android 上工作。
|
||||
|
||||
* 使不支持的网络不可达。
|
||||
* 阻止 Windows 的 [普通多宿主 DNS 解析行为](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd197552%28v%3Dws.10%29) 造成的 DNS 泄露
|
||||
*在 Windows 中*:
|
||||
|
||||
它可能会使某些 Windows 应用程序(如 VirtualBox)在某些情况下无法正常工作。
|
||||
* 添加防火墙规则以阻止 Windows
|
||||
的 [普通多宿主 DNS 解析行为](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd197552%28v%3Dws.10%29)
|
||||
造成的 DNS 泄露
|
||||
|
||||
它可能会使某些应用程序(如 VirtualBox)在某些情况下无法正常工作。
|
||||
|
||||
#### route_address
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
| QUIC 客户端 | 类型 |
|
||||
|:------------------------:|:----------:|
|
||||
| Chromium/Cronet | `chromium` |
|
||||
| Chromium/Cronet | `chrimium` |
|
||||
| Safari/Apple Network API | `safari` |
|
||||
| Firefox / uquic firefox | `firefox` |
|
||||
| quic-go / uquic chrome | `quic-go` |
|
||||
| quic-go / uquic chrome | `quic-go` |
|
@ -206,7 +206,7 @@ Only take effect when `domain_strategy` or `network_strategy` is set.
|
||||
|
||||
!!! failure "Deprecated in sing-box 1.12.0"
|
||||
|
||||
`domain_strategy` is deprecated and will be removed in sing-box 1.14.0, check [Migration](/migration/#migrate-outbound-domain-strategy-option-to-domain-resolver).
|
||||
`domain_strategy` is merged to [domain_resolver](#domain_resolver) in sing-box 1.12.0.
|
||||
|
||||
Available values: `prefer_ipv4`, `prefer_ipv6`, `ipv4_only`, `ipv6_only`.
|
||||
|
||||
|
@ -194,10 +194,6 @@ icon: material/new-box
|
||||
|
||||
#### domain_strategy
|
||||
|
||||
!!! failure "已在 sing-box 1.12.0 废弃"
|
||||
|
||||
`domain_strategy` 已废弃且将在 sing-box 1.14.0 中被移除,参阅 [迁移指南](/migration/#migrate-outbound-domain-strategy-option-to-domain-resolver)。
|
||||
|
||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
||||
|
||||
如果设置,域名将在请求发出之前解析为 IP。
|
||||
|
@ -8,56 +8,44 @@ icon: material/package
|
||||
|
||||
=== ":material-debian: Debian / APT"
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/apt/keyrings &&
|
||||
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc &&
|
||||
sudo chmod a+r /etc/apt/keyrings/sagernet.asc &&
|
||||
echo '
|
||||
Types: deb
|
||||
URIs: https://deb.sagernet.org/
|
||||
Suites: *
|
||||
Components: *
|
||||
Enabled: yes
|
||||
Signed-By: /etc/apt/keyrings/sagernet.asc
|
||||
' | sudo tee /etc/apt/sources.list.d/sagernet.sources &&
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install sing-box # or sing-box-beta
|
||||
```
|
||||
```bash
|
||||
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc
|
||||
sudo chmod a+r /etc/apt/keyrings/sagernet.asc
|
||||
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/sagernet.asc] https://deb.sagernet.org/ * *" | \
|
||||
sudo tee /etc/apt/sources.list.d/sagernet.list > /dev/null
|
||||
sudo apt-get update
|
||||
sudo apt-get install sing-box # or sing-box-beta
|
||||
```
|
||||
|
||||
=== ":material-redhat: Redhat / DNF 5"
|
||||
=== ":material-redhat: Redhat / DNF"
|
||||
|
||||
```bash
|
||||
sudo dnf config-manager addrepo --from-repofile=https://sing-box.app/sing-box.repo &&
|
||||
sudo dnf install sing-box # or sing-box-beta
|
||||
```
|
||||
|
||||
=== ":material-redhat: Redhat / DNF 4"
|
||||
|
||||
```bash
|
||||
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo &&
|
||||
sudo dnf -y install dnf-plugins-core &&
|
||||
sudo dnf install sing-box # or sing-box-beta
|
||||
```
|
||||
```bash
|
||||
sudo dnf -y install dnf-plugins-core
|
||||
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
||||
sudo dnf install sing-box # or sing-box-beta
|
||||
```
|
||||
(This applies to any distribution that uses `dnf` as the package manager: Fedora, CentOS, even OpenSUSE with DNF installed.)
|
||||
|
||||
## :material-download-box: Manual Installation
|
||||
|
||||
The script download and install the latest package from GitHub releases for deb or rpm based Linux distributions, ArchLinux and OpenWrt.
|
||||
|
||||
```shell
|
||||
curl -fsSL https://sing-box.app/install.sh | sh
|
||||
```
|
||||
|
||||
or latest beta:
|
||||
|
||||
```shell
|
||||
curl -fsSL https://sing-box.app/install.sh | sh -s -- --beta
|
||||
```
|
||||
|
||||
or specific version:
|
||||
|
||||
```shell
|
||||
curl -fsSL https://sing-box.app/install.sh | sh -s -- --version <version>
|
||||
```
|
||||
=== ":material-debian: Debian / DEB"
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL https://sing-box.app/deb-install.sh)
|
||||
```
|
||||
|
||||
=== ":material-redhat: Redhat / RPM"
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
||||
```
|
||||
(This applies to any distribution that uses `rpm` and `systemd`. Because of how `rpm` defines dependencies, if it installs, it probably works.)
|
||||
|
||||
=== ":simple-archlinux: Archlinux / PKG"
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL https://sing-box.app/arch-install.sh)
|
||||
```
|
||||
|
||||
## :material-book-lock-open: Managed Installation
|
||||
|
||||
|
@ -9,35 +9,22 @@ icon: material/package
|
||||
=== ":material-debian: Debian / APT"
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/apt/keyrings &&
|
||||
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc &&
|
||||
sudo chmod a+r /etc/apt/keyrings/sagernet.asc &&
|
||||
echo '
|
||||
Types: deb
|
||||
URIs: https://deb.sagernet.org/
|
||||
Suites: *
|
||||
Components: *
|
||||
Enabled: yes
|
||||
Signed-By: /etc/apt/keyrings/sagernet.asc
|
||||
' | sudo tee /etc/apt/sources.list.d/sagernet.sources &&
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install sing-box # or sing-box-beta
|
||||
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc
|
||||
sudo chmod a+r /etc/apt/keyrings/sagernet.asc
|
||||
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/sagernet.asc] https://deb.sagernet.org/ * *" | \
|
||||
sudo tee /etc/apt/sources.list.d/sagernet.list > /dev/null
|
||||
sudo apt-get update
|
||||
sudo apt-get install sing-box # or sing-box-beta
|
||||
```
|
||||
|
||||
=== ":material-redhat: Redhat / DNF 5"
|
||||
=== ":material-redhat: Redhat / DNF"
|
||||
|
||||
```bash
|
||||
sudo dnf config-manager addrepo --from-repofile=https://sing-box.app/sing-box.repo &&
|
||||
sudo dnf install sing-box # or sing-box-beta
|
||||
```
|
||||
|
||||
=== ":material-redhat: Redhat / DNF 4"
|
||||
|
||||
```bash
|
||||
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo &&
|
||||
sudo dnf -y install dnf-plugins-core &&
|
||||
sudo dnf install sing-box # or sing-box-beta
|
||||
```
|
||||
```bash
|
||||
sudo dnf -y install dnf-plugins-core
|
||||
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
||||
sudo dnf install sing-box # or sing-box-beta
|
||||
```
|
||||
(这适用于任何使用 `dnf` 作为包管理器的发行版:Fedora、CentOS,甚至安装了 DNF 的 OpenSUSE。)
|
||||
|
||||
## :material-download-box: 手动安装
|
||||
|
||||
|
@ -1,97 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
download_beta=false
|
||||
download_version=""
|
||||
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "--beta" ]]; then
|
||||
download_beta=true
|
||||
elif [[ "$arg" == "--version" ]]; then
|
||||
download_version=true
|
||||
elif [[ "$download_version" == 'true' ]]; then
|
||||
download_version="$arg"
|
||||
else
|
||||
echo "Unknown argument: $arg"
|
||||
echo "Usage: $0 [--beta] [--version <version>]"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $(command -v dpkg) ]]; then
|
||||
os="linux"
|
||||
arch=$(dpkg --print-architecture)
|
||||
package_suffix=".deb"
|
||||
package_install="dpkg -i"
|
||||
elif [[ $(command -v dnf) ]]; then
|
||||
os="linux"
|
||||
arch=$(uname -m)
|
||||
package_suffix=".rpm"
|
||||
package_install="dnf install -y"
|
||||
elif [[ $(command -v rpm) ]]; then
|
||||
os="linux"
|
||||
arch=$(uname -m)
|
||||
package_suffix=".rpm"
|
||||
package_install="rpm -i"
|
||||
elif [[ $(command -v pacman) ]]; then
|
||||
os="linux"
|
||||
arch=$(uname -m)
|
||||
package_suffix=".pkg.tar.zst"
|
||||
package_install="pacman -U --noconfirm"
|
||||
elif [[ $(command -v opkg) ]]; then
|
||||
os="openwrt"
|
||||
source /etc/os-release
|
||||
arch="$OPENWRT_ARCH"
|
||||
package_suffix=".ipk"
|
||||
package_install="opkg update && opkg install -y"
|
||||
else
|
||||
echo "Missing supported package manager."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$download_version" ]]; then
|
||||
if [[ "$download_beta" != 'true' ]]; then
|
||||
if [[ -n "$GITHUB_TOKEN" ]]; then
|
||||
latest_release=$(curl -s --fail-with-body -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/SagerNet/sing-box/releases/latest)
|
||||
else
|
||||
latest_release=$(curl -s --fail-with-body https://api.github.com/repos/SagerNet/sing-box/releases/latest)
|
||||
fi
|
||||
curl_exit_status=$?
|
||||
if [[ $curl_exit_status -ne 0 ]]; then
|
||||
echo "$latest_release"
|
||||
exit $?
|
||||
fi
|
||||
download_version=$(echo "$latest_release" | grep tag_name | cut -d ":" -f2 | sed 's/\"//g;s/\,//g;s/\ //g;s/v//')
|
||||
else
|
||||
if [[ -n "$GITHUB_TOKEN" ]]; then
|
||||
latest_release=$(curl -s --fail-with-body -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/SagerNet/sing-box/releases)
|
||||
else
|
||||
latest_release=$(curl -s --fail-with-body https://api.github.com/repos/SagerNet/sing-box/releases)
|
||||
fi
|
||||
curl_exit_status=$?
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "$latest_release"
|
||||
exit $?
|
||||
fi
|
||||
download_version=$(echo "$latest_release" | grep tag_name | head -n 1 | cut -d ":" -f2 | sed 's/\"//g;s/\,//g;s/\ //g;s/v//')
|
||||
fi
|
||||
fi
|
||||
|
||||
package_name="sing-box_${download_version}_${os}_${arch}${package_suffix}"
|
||||
package_url="https://github.com/SagerNet/sing-box/releases/download/v${download_version}/${package_name}"
|
||||
|
||||
echo "Downloading $package_url"
|
||||
if [[ -n "$GITHUB_TOKEN" ]]; then
|
||||
curl --fail-with-body -Lo "$package_name" -H "Authorization: token ${GITHUB_TOKEN}" "$package_url"
|
||||
else
|
||||
curl --fail-with-body -Lo "$package_name" "$package_url"
|
||||
fi
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ $(command -v sudo) ]]; then
|
||||
package_install="sudo $package_install"
|
||||
fi
|
||||
|
||||
echo "$package_install $package_name" && $package_install "$package_name" && rm "$package_name"
|
@ -292,7 +292,7 @@ DNS servers are refactored for better performance and scalability.
|
||||
}
|
||||
],
|
||||
"fakeip": {
|
||||
"enabled": true,
|
||||
"enable": true,
|
||||
"inet4_range": "198.18.0.0/15",
|
||||
"inet6_range": "fc00::/18"
|
||||
}
|
||||
@ -516,13 +516,13 @@ DNS servers are refactored for better performance and scalability.
|
||||
The legacy outbound DNS rules are deprecated and can be replaced by new domain resolver options.
|
||||
|
||||
!!! info "References"
|
||||
|
||||
|
||||
[DNS rule](/configuration/dns/rule/#outbound) /
|
||||
[Dial Fields](/configuration/shared/dial/#domain_resolver) /
|
||||
[Route](/configuration/route/#domain_resolver)
|
||||
|
||||
=== ":material-card-remove: Deprecated"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -556,8 +556,7 @@ The legacy outbound DNS rules are deprecated and can be replaced by new domain r
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "local"
|
||||
"type": "local"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -587,58 +586,6 @@ The legacy outbound DNS rules are deprecated and can be replaced by new domain r
|
||||
}
|
||||
```
|
||||
|
||||
### Migrate outbound domain strategy option to domain resolver
|
||||
|
||||
!!! info "References"
|
||||
|
||||
[Dial Fields](/configuration/shared/dial/#domain_strategy)
|
||||
|
||||
The `domain_strategy` option in Dial Fields has been deprecated and can be replaced with the new domain resolver option.
|
||||
|
||||
Note that due to the use of Dial Fields by some of the new DNS servers introduced in sing-box 1.12,
|
||||
some people mistakenly believe that `domain_strategy` is the same feature as in the legacy DNS servers.
|
||||
|
||||
=== ":material-card-remove: Deprecated"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"server": "example.org",
|
||||
"server_port": 2080,
|
||||
"domain_strategy": "prefer_ipv4",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-card-multiple: New"
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "local"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"server": "example.org",
|
||||
"server_port": 2080,
|
||||
"domain_resolver": {
|
||||
"server": "local",
|
||||
"strategy": "prefer_ipv4"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 1.11.0
|
||||
|
||||
### Migrate legacy special outbounds to rule actions
|
||||
|
@ -16,7 +16,7 @@ DNS 服务器已经重构。
|
||||
=== "Local"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -28,9 +28,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -46,7 +46,7 @@ DNS 服务器已经重构。
|
||||
=== "TCP"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -58,9 +58,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -77,7 +77,7 @@ DNS 服务器已经重构。
|
||||
=== "UDP"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -89,9 +89,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -108,7 +108,7 @@ DNS 服务器已经重构。
|
||||
=== "TLS"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -120,9 +120,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -139,7 +139,7 @@ DNS 服务器已经重构。
|
||||
=== "HTTPS"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -151,9 +151,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -170,7 +170,7 @@ DNS 服务器已经重构。
|
||||
=== "QUIC"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -182,9 +182,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -201,7 +201,7 @@ DNS 服务器已经重构。
|
||||
=== "HTTP3"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -213,9 +213,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -232,7 +232,7 @@ DNS 服务器已经重构。
|
||||
=== "DHCP"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -247,9 +247,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -269,7 +269,7 @@ DNS 服务器已经重构。
|
||||
=== "FakeIP"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -292,16 +292,16 @@ DNS 服务器已经重构。
|
||||
}
|
||||
],
|
||||
"fakeip": {
|
||||
"enabled": true,
|
||||
"enable": true,
|
||||
"inet4_range": "198.18.0.0/15",
|
||||
"inet6_range": "fc00::/18"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -333,7 +333,7 @@ DNS 服务器已经重构。
|
||||
=== "RCode"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -345,9 +345,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -368,7 +368,7 @@ DNS 服务器已经重构。
|
||||
=== "带有域名地址的服务器"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -385,9 +385,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -410,7 +410,7 @@ DNS 服务器已经重构。
|
||||
=== "带有域策略的服务器"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -434,9 +434,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -466,7 +466,7 @@ DNS 服务器已经重构。
|
||||
=== "带有客户端子网的服务器"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -483,9 +483,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@ -556,8 +556,7 @@ DNS 服务器已经重构。
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "local"
|
||||
"type": "local"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -587,57 +586,6 @@ DNS 服务器已经重构。
|
||||
}
|
||||
```
|
||||
|
||||
### 迁移出站域名策略选项到域名解析器
|
||||
|
||||
拨号字段中的 `domain_strategy` 选项已被弃用,可以用新的域名解析器选项替代。
|
||||
|
||||
请注意,由于 sing-box 1.12 中引入的一些新 DNS 服务器使用了拨号字段,一些人错误地认为 `domain_strategy` 与旧 DNS 服务器中的功能相同。
|
||||
|
||||
!!! info "参考"
|
||||
|
||||
[拨号字段](/configuration/shared/dial/#domain_strategy)
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"server": "example.org",
|
||||
"server_port": 2080,
|
||||
"domain_strategy": "prefer_ipv4",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "local"
|
||||
}
|
||||
]
|
||||
},
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"server": "example.org",
|
||||
"server_port": 2080,
|
||||
"domain_resolver": {
|
||||
"server": "local",
|
||||
"strategy": "prefer_ipv4"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 1.11.0
|
||||
|
||||
### 迁移旧的特殊出站到规则动作
|
||||
@ -653,7 +601,7 @@ DNS 服务器已经重构。
|
||||
=== "Block"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
@ -666,7 +614,7 @@ DNS 服务器已经重构。
|
||||
"rules": [
|
||||
{
|
||||
...,
|
||||
|
||||
|
||||
"outbound": "block"
|
||||
}
|
||||
]
|
||||
@ -675,14 +623,14 @@ DNS 服务器已经重构。
|
||||
```
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
...,
|
||||
|
||||
|
||||
"action": "reject"
|
||||
}
|
||||
]
|
||||
@ -693,13 +641,13 @@ DNS 服务器已经重构。
|
||||
=== "DNS"
|
||||
|
||||
=== ":material-card-remove: 弃用的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"inbound": [
|
||||
{
|
||||
...,
|
||||
|
||||
|
||||
"sniff": true
|
||||
}
|
||||
],
|
||||
@ -719,9 +667,9 @@ DNS 服务器已经重构。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
=== ":material-card-multiple: 新的"
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"route": {
|
||||
@ -1185,4 +1133,4 @@ sing-box 1.9.0 使 QueryFullProcessImageNameW 输出 Win32 路径(如 `C:\fold
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
@ -161,7 +161,6 @@ var OptionLegacyDNSFakeIPOptions = Note{
|
||||
Description: "legacy DNS fakeip options",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
EnvName: "LEGACY_DNS_FAKEIP_OPTIONS",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-to-new-dns-server-formats",
|
||||
}
|
||||
|
||||
@ -170,7 +169,6 @@ var OptionOutboundDNSRuleItem = Note{
|
||||
Description: "outbound DNS rule item",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
EnvName: "OUTBOUND_DNS_RULE_ITEM",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-outbound-dns-rule-items-to-domain-resolver",
|
||||
}
|
||||
|
||||
@ -179,7 +177,6 @@ var OptionMissingDomainResolver = Note{
|
||||
Description: "missing `route.default_domain_resolver` or `domain_resolver` in dial fields",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
EnvName: "MISSING_DOMAIN_RESOLVER",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-outbound-dns-rule-items-to-domain-resolver",
|
||||
}
|
||||
|
||||
@ -188,19 +185,9 @@ var OptionLegacyECHOptions = Note{
|
||||
Description: "legacy ECH options",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.13.0",
|
||||
EnvName: "LEGACY_ECH_OPTIONS",
|
||||
MigrationLink: "https://sing-box.sagernet.org/deprecated/#legacy-ech-fields",
|
||||
}
|
||||
|
||||
var OptionLegacyDomainStrategyOptions = Note{
|
||||
Name: "legacy-domain-strategy-options",
|
||||
Description: "legacy domain strategy options",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
EnvName: "LEGACY_DOMAIN_STRATEGY_OPTIONS",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-domain-strategy-options",
|
||||
}
|
||||
|
||||
var Options = []Note{
|
||||
OptionBadMatchSource,
|
||||
OptionGEOIP,
|
||||
@ -217,5 +204,4 @@ var Options = []Note{
|
||||
OptionOutboundDNSRuleItem,
|
||||
OptionMissingDomainResolver,
|
||||
OptionLegacyECHOptions,
|
||||
OptionLegacyDomainStrategyOptions,
|
||||
}
|
||||
|
@ -116,10 +116,6 @@ func (s *platformInterfaceStub) FindProcessInfo(ctx context.Context, network str
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) SendNotification(notification *platform.Notification) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type interfaceMonitorStub struct{}
|
||||
|
||||
func (s *interfaceMonitorStub) Start() error {
|
||||
@ -149,11 +145,8 @@ func (s *interfaceMonitorStub) RegisterCallback(callback tun.DefaultInterfaceUpd
|
||||
func (s *interfaceMonitorStub) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
|
||||
}
|
||||
|
||||
func (s *interfaceMonitorStub) RegisterMyInterface(interfaceName string) {
|
||||
}
|
||||
|
||||
func (s *interfaceMonitorStub) MyInterface() string {
|
||||
return ""
|
||||
func (s *platformInterfaceStub) SendNotification(notification *platform.Notification) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func FormatConfig(configContent string) (*StringBox, error) {
|
||||
|
@ -15,10 +15,9 @@ var (
|
||||
|
||||
type platformDefaultInterfaceMonitor struct {
|
||||
*platformInterfaceWrapper
|
||||
logger logger.Logger
|
||||
element *list.Element[tun.NetworkUpdateCallback]
|
||||
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
|
||||
myInterface string
|
||||
element *list.Element[tun.NetworkUpdateCallback]
|
||||
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) Start() error {
|
||||
@ -103,15 +102,3 @@ func (m *platformDefaultInterfaceMonitor) updateDefaultInterface(interfaceName s
|
||||
callback(newInterface, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) RegisterMyInterface(interfaceName string) {
|
||||
m.defaultInterfaceAccess.Lock()
|
||||
defer m.defaultInterfaceAccess.Unlock()
|
||||
m.myInterface = interfaceName
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) MyInterface() string {
|
||||
m.defaultInterfaceAccess.Lock()
|
||||
defer m.defaultInterfaceAccess.Unlock()
|
||||
return m.myInterface
|
||||
}
|
||||
|
@ -164,7 +164,6 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "query tun name")
|
||||
}
|
||||
options.InterfaceMonitor.RegisterMyInterface(options.Name)
|
||||
dupFd, err := dup(int(tunFd))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "dup tun file descriptor")
|
||||
|
2
go.mod
2
go.mod
@ -32,7 +32,7 @@ require (
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250316154757-6f9e732e5056
|
||||
github.com/sagernet/sing-tun v0.6.5-0.20250412112220-15069fc1c20a
|
||||
github.com/sagernet/sing-tun v0.6.3-0.20250409030157-219c612399be
|
||||
github.com/sagernet/sing-vmess v0.2.0
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||
github.com/sagernet/tailscale v1.80.3-mod.2
|
||||
|
4
go.sum
4
go.sum
@ -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-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-tun v0.6.5-0.20250412112220-15069fc1c20a h1:2aLxZFD2HPCLrnFGpH+KBuPqMOk0cuaDE2dgEvANuMk=
|
||||
github.com/sagernet/sing-tun v0.6.5-0.20250412112220-15069fc1c20a/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||
github.com/sagernet/sing-tun v0.6.3-0.20250409030157-219c612399be h1:E/JnQ1DEz5XIH6VVk3dIMD7aIX5o79jPkbyw57tWlJs=
|
||||
github.com/sagernet/sing-tun v0.6.3-0.20250409030157-219c612399be/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||
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/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||
|
@ -94,7 +94,7 @@ func (i *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata a
|
||||
case 2:
|
||||
destination.Addr = i.overrideDestination.Addr
|
||||
case 3:
|
||||
destination.Port = i.overrideDestination.Port
|
||||
destination.Port = metadata.Destination.Port
|
||||
}
|
||||
metadata.Destination = destination
|
||||
if i.overrideOption != 0 {
|
||||
|
@ -396,16 +396,12 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
|
||||
func (g *URLTestGroup) performUpdateCheck() {
|
||||
var updated bool
|
||||
if outbound, exists := g.Select(N.NetworkTCP); outbound != nil && (g.selectedOutboundTCP == nil || (exists && outbound != g.selectedOutboundTCP)) {
|
||||
if g.selectedOutboundTCP != nil {
|
||||
updated = true
|
||||
}
|
||||
g.selectedOutboundTCP = outbound
|
||||
updated = true
|
||||
}
|
||||
if outbound, exists := g.Select(N.NetworkUDP); outbound != nil && (g.selectedOutboundUDP == nil || (exists && outbound != g.selectedOutboundUDP)) {
|
||||
if g.selectedOutboundUDP != nil {
|
||||
updated = true
|
||||
}
|
||||
g.selectedOutboundUDP = outbound
|
||||
updated = true
|
||||
}
|
||||
if updated {
|
||||
g.interruptGroup.Interrupt(g.interruptExternalConnections)
|
||||
|
@ -26,6 +26,11 @@ func RegisterEndpoint(registry *endpoint.Registry) {
|
||||
endpoint.Register[option.WireGuardEndpointOptions](registry, C.TypeWireGuard, NewEndpoint)
|
||||
}
|
||||
|
||||
var (
|
||||
_ adapter.Endpoint = (*Endpoint)(nil)
|
||||
_ adapter.InterfaceUpdateListener = (*Endpoint)(nil)
|
||||
)
|
||||
|
||||
type Endpoint struct {
|
||||
endpoint.Adapter
|
||||
ctx context.Context
|
||||
@ -122,6 +127,10 @@ func (w *Endpoint) Close() error {
|
||||
return w.endpoint.Close()
|
||||
}
|
||||
|
||||
func (w *Endpoint) InterfaceUpdated() {
|
||||
w.endpoint.BindUpdate()
|
||||
}
|
||||
|
||||
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
|
||||
return w.router.PreMatch(adapter.InboundContext{
|
||||
Inbound: w.Tag(),
|
||||
|
@ -25,6 +25,11 @@ func RegisterOutbound(registry *outbound.Registry) {
|
||||
outbound.Register[option.LegacyWireGuardOutboundOptions](registry, C.TypeWireGuard, NewOutbound)
|
||||
}
|
||||
|
||||
var (
|
||||
_ adapter.Endpoint = (*Endpoint)(nil)
|
||||
_ adapter.InterfaceUpdateListener = (*Endpoint)(nil)
|
||||
)
|
||||
|
||||
type Outbound struct {
|
||||
outbound.Adapter
|
||||
ctx context.Context
|
||||
@ -126,6 +131,10 @@ func (o *Outbound) Close() error {
|
||||
return o.endpoint.Close()
|
||||
}
|
||||
|
||||
func (o *Outbound) InterfaceUpdated() {
|
||||
o.endpoint.BindUpdate()
|
||||
}
|
||||
|
||||
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
switch network {
|
||||
case N.NetworkTCP:
|
||||
|
13
release/config/openwrt.init
Executable file → Normal file
13
release/config/openwrt.init
Executable file → Normal file
@ -1,27 +1,26 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
USE_PROCD=1
|
||||
START=99
|
||||
PROG="/usr/bin/sing-box"
|
||||
|
||||
start_service() {
|
||||
config_load "sing-box"
|
||||
|
||||
local enabled config_file working_directory
|
||||
local log_stderr
|
||||
local log_stdout log_stderr
|
||||
config_get_bool enabled "main" "enabled" "0"
|
||||
[ "$enabled" -eq "1" ] || return 0
|
||||
|
||||
config_get config_file "main" "conffile" "/etc/sing-box/config.json"
|
||||
config_get working_directory "main" "workdir" "/usr/share/sing-box"
|
||||
config_get_bool log_stdout "main" "log_stdout" "1"
|
||||
config_get_bool log_stderr "main" "log_stderr" "1"
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command "$PROG" run -c "$config_file" -D "$working_directory"
|
||||
procd_set_param file "$config_file"
|
||||
procd_swet_param command "$PROG" run -c "$conffile" -D "$workdir"
|
||||
procd_set_param file "$conffile"
|
||||
procd_set_param stderr "$log_stderr"
|
||||
procd_set_param limits core="unlimited"
|
||||
procd_set_param limits nofile="1000000 1000000"
|
||||
sprocd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param respawn
|
||||
|
||||
procd_close_instance
|
||||
@ -29,4 +28,4 @@ start_service() {
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "sing-box"
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
/etc/sing-box/
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
[ -s ${IPKG_INSTROOT}/lib/functions.sh ] || exit 0
|
||||
. ${IPKG_INSTROOT}/lib/functions.sh
|
||||
default_prerm $0 $@
|
@ -150,7 +150,7 @@ func (e *Endpoint) Start(resolve bool) error {
|
||||
connectAddr netip.AddrPort
|
||||
reserved [3]uint8
|
||||
)
|
||||
if len(e.peers) == 1 && e.peers[0].endpoint.IsValid() {
|
||||
if len(e.peers) == 1 {
|
||||
isConnect = true
|
||||
connectAddr = e.peers[0].endpoint
|
||||
reserved = e.peers[0].reserved
|
||||
@ -208,6 +208,10 @@ func (e *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
return e.tunDevice.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
||||
func (e *Endpoint) BindUpdate() error {
|
||||
return e.device.BindUpdate()
|
||||
}
|
||||
|
||||
func (e *Endpoint) Close() error {
|
||||
if e.device != nil {
|
||||
e.device.Close()
|
||||
|
Loading…
x
Reference in New Issue
Block a user