Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e586d9e9bc | ||
|
|
8c7eaa4477 | ||
|
|
8464c8cb7c | ||
|
|
39d7127651 | ||
|
|
e2077009c4 | ||
|
|
700a8eb425 | ||
|
|
3b0cba0852 | ||
|
|
f5554dd8b8 | ||
|
|
4d0362d530 | ||
|
|
97ccd2ca04 | ||
|
|
1ed6654ad4 | ||
|
|
5385f75f53 | ||
|
|
ad97d4e11f | ||
|
|
09d4e91b77 | ||
|
|
3dbdda9555 | ||
|
|
1f4ed6ff8f | ||
|
|
6ddbe19bc0 | ||
|
|
d7205ecc60 | ||
|
|
9e243e0ff9 | ||
|
|
02bc3e0a0a | ||
|
|
87be6dc235 | ||
|
|
c1c30976dc | ||
|
|
9bac18bcd1 | ||
|
|
ceda5cc95d | ||
|
|
27d6b63e71 | ||
|
|
b57abcc73c | ||
|
|
f1147965dd | ||
|
|
45f3234c73 | ||
|
|
aae3fded32 | ||
|
|
090494faf5 | ||
|
|
db5719e22f | ||
|
|
064fb9b873 | ||
|
|
f6a1e123fc | ||
|
|
3066dfe3b3 | ||
|
|
1128fdd8c7 | ||
|
|
cfd9879b17 | ||
|
|
9ceb660c57 | ||
|
|
7d00d7df28 | ||
|
|
21b1ac26b9 | ||
|
|
7fec8d842e | ||
|
|
07c678fb85 | ||
|
|
baecfc7778 | ||
|
|
07de36ecdb | ||
|
|
2c8a8303cd | ||
|
|
e5991cae0b | ||
|
|
1349acfd5a | ||
|
|
98ff897f35 | ||
|
|
6144c8e340 | ||
|
|
c8caac9f67 | ||
|
|
81e9eda357 | ||
|
|
7cba3da108 | ||
|
|
82d06b43e7 | ||
|
|
a7ac91f573 | ||
|
|
0540a95a43 | ||
|
|
94707dfcdd | ||
|
|
8a17043502 | ||
|
|
b0aaa86806 | ||
|
|
8a2d3fbb28 | ||
|
|
4652019608 | ||
|
|
06fa5abf63 | ||
|
|
996fbbf0c3 | ||
|
|
142ff1b455 | ||
|
|
74d662f7a3 | ||
|
|
085f603377 | ||
|
|
460fae83dc | ||
|
|
bb9bd9bff6 | ||
|
|
c2354ebf25 | ||
|
|
c1f4755c4e | ||
|
|
0ca5909b06 | ||
|
|
e77a8114c5 | ||
|
|
f1393235ff | ||
|
|
bdba2365de | ||
|
|
ce0da5b557 | ||
|
|
3853201412 | ||
|
|
7003ef40a3 | ||
|
|
59ec92228c | ||
|
|
0eeb2da323 | ||
|
|
977b0fac02 | ||
|
|
51964801ff | ||
|
|
e08c052fc9 | ||
|
|
53927d8bbd | ||
|
|
968b9bc217 | ||
|
|
69dc87aa6d | ||
|
|
4193df375f | ||
|
|
5ff7006326 | ||
|
|
a89107ea9d | ||
|
|
9ffdbba2ed | ||
|
|
65c71049ea | ||
|
|
7d4e6a7f4e | ||
|
|
d612620c5d | ||
|
|
8a9a77a438 | ||
|
|
a2098c18e1 | ||
|
|
cf2181dd3a | ||
|
|
5899e95ff1 | ||
|
|
d7160c19cf | ||
|
|
da9e22b4e6 | ||
|
|
0e120f8a44 | ||
|
|
d918863ac5 | ||
|
|
2ae192305c | ||
|
|
71d1879bd6 | ||
|
|
917514e09f | ||
|
|
5327aeaea4 | ||
|
|
93ae3f7a1e | ||
|
|
f24a2aed7d | ||
|
|
0517ceef76 | ||
|
|
830ea46932 | ||
|
|
cd0fcd5ddc | ||
|
|
003176f069 | ||
|
|
71d92518c1 | ||
|
|
b5dcd6bf59 | ||
|
|
11c7b4a866 | ||
|
|
ee14135298 | ||
|
|
cbcf005f37 | ||
|
|
daee0b154e | ||
|
|
d530c724c0 | ||
|
|
7f698c1104 | ||
|
|
7a4a44c6d2 | ||
|
|
44277e5dd2 | ||
|
|
1f470c69c4 | ||
|
|
742adacce7 | ||
|
|
32e1d5a5e2 | ||
|
|
cb9f4ce597 | ||
|
|
4b1a6185ba | ||
|
|
8d85c92356 | ||
|
|
c6164c9eca | ||
|
|
3c85b8bc48 | ||
|
|
8b8fb4344c | ||
|
|
e85a38e059 | ||
|
|
f3ac91673a | ||
|
|
0f1e58b917 | ||
|
|
c4cfe24aef | ||
|
|
3d73b159ba | ||
|
|
0ae1afef44 | ||
|
|
a5e2a4073b | ||
|
|
b6cb3948a3 | ||
|
|
7b0f5061dc | ||
|
|
76f20482f7 | ||
|
|
e735a5bdc8 | ||
|
|
70381e93c8 | ||
|
|
07a40716e8 | ||
|
|
5fea5956db | ||
|
|
d20a389043 | ||
|
|
4a4180bde5 | ||
|
|
7ecb6daabb | ||
|
|
712bdd9ae5 | ||
|
|
a3b74591a7 | ||
|
|
2f4abc6523 | ||
|
|
965ab075d9 |
10
.github/workflows/debug.yml
vendored
10
.github/workflows/debug.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
@@ -78,7 +78,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
@@ -208,7 +208,7 @@ jobs:
|
|||||||
TAGS: with_clash_api,with_quic
|
TAGS: with_clash_api,with_quic
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
|
|||||||
126
.github/workflows/docker.yml
vendored
126
.github/workflows/docker.yml
vendored
@@ -1,39 +1,133 @@
|
|||||||
name: Build Docker Images
|
name: Publish Docker Images
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types:
|
types:
|
||||||
- released
|
- published
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "The tag version you want to build"
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY_IMAGE: ghcr.io/sagernet/sing-box
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- linux/amd64
|
||||||
|
- linux/arm/v6
|
||||||
|
- linux/arm/v7
|
||||||
|
- linux/arm64
|
||||||
|
- linux/386
|
||||||
|
- linux/ppc64le
|
||||||
|
- linux/riscv64
|
||||||
|
- linux/s390x
|
||||||
steps:
|
steps:
|
||||||
|
- name: Get commit to build
|
||||||
|
id: ref
|
||||||
|
run: |-
|
||||||
|
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
|
||||||
|
ref="${{ github.ref_name }}"
|
||||||
|
else
|
||||||
|
ref="${{ github.event.inputs.tag }}"
|
||||||
|
fi
|
||||||
|
echo "ref=$ref"
|
||||||
|
echo "ref=$ref" >> $GITHUB_OUTPUT
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
|
with:
|
||||||
|
ref: ${{ steps.ref.outputs.ref }}
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
platform=${{ matrix.platform }}
|
||||||
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
|
- name: Setup QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
- name: Setup Docker Buildx
|
- name: Setup Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Setup QEMU for Docker Buildx
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Docker metadata
|
- name: Docker meta
|
||||||
id: metadata
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/sagernet/sing-box
|
images: ${{ env.REGISTRY_IMAGE }}
|
||||||
- name: Build and release Docker images
|
- name: Build and push by digest
|
||||||
uses: docker/build-push-action@v5
|
id: build
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
platforms: linux/386,linux/amd64,linux/arm64,linux/s390x
|
platforms: ${{ matrix.platform }}
|
||||||
target: dist
|
context: .
|
||||||
build-args: |
|
build-args: |
|
||||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||||
tags: |
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
ghcr.io/sagernet/sing-box:latest
|
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||||
ghcr.io/sagernet/sing-box:${{ github.ref_name }}
|
- name: Export digest
|
||||||
push: true
|
run: |
|
||||||
|
mkdir -p /tmp/digests
|
||||||
|
digest="${{ steps.build.outputs.digest }}"
|
||||||
|
touch "/tmp/digests/${digest#sha256:}"
|
||||||
|
- name: Upload digest
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: digests-${{ env.PLATFORM_PAIR }}
|
||||||
|
path: /tmp/digests/*
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
merge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
steps:
|
||||||
|
- name: Get commit to build
|
||||||
|
id: ref
|
||||||
|
run: |-
|
||||||
|
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
|
||||||
|
ref="${{ github.ref_name }}"
|
||||||
|
else
|
||||||
|
ref="${{ github.event.inputs.tag }}"
|
||||||
|
fi
|
||||||
|
echo "ref=$ref"
|
||||||
|
echo "ref=$ref" >> $GITHUB_OUTPUT
|
||||||
|
if [[ $ref == *"-"* ]]; then
|
||||||
|
latest=latest-beta
|
||||||
|
else
|
||||||
|
latest=latest
|
||||||
|
fi
|
||||||
|
echo "latest=$latest"
|
||||||
|
echo "latest=$latest" >> $GITHUB_OUTPUT
|
||||||
|
- name: Download digests
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: /tmp/digests
|
||||||
|
pattern: digests-*
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Create manifest list and push
|
||||||
|
working-directory: /tmp/digests
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools create \
|
||||||
|
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}" \
|
||||||
|
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}" \
|
||||||
|
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
|
||||||
|
- name: Inspect image
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}
|
||||||
|
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}
|
||||||
|
|||||||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ^1.22
|
go-version: ^1.22
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v4
|
uses: golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: --timeout=30m
|
args: --timeout=30m
|
||||||
|
|||||||
14
.github/workflows/linux.yml
vendored
14
.github/workflows/linux.yml
vendored
@@ -10,15 +10,23 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.22
|
go-version: ^1.22
|
||||||
|
- name: Extract signing key
|
||||||
|
run: |-
|
||||||
|
mkdir -p $HOME/.gnupg
|
||||||
|
cat > $HOME/.gnupg/sagernet.key <<EOF
|
||||||
|
${{ secrets.GPG_KEY }}
|
||||||
|
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||||
|
EOF
|
||||||
|
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
uses: goreleaser/goreleaser-action@v5
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
distribution: goreleaser-pro
|
distribution: goreleaser-pro
|
||||||
version: latest
|
version: latest
|
||||||
@@ -27,3 +35,5 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||||
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
|
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
|
||||||
|
NFPM_KEY_PATH: ${{ env.HOME }}/.gnupg/sagernet.key
|
||||||
|
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
|
|||||||
3
.github/workflows/stale.yml
vendored
3
.github/workflows/stale.yml
vendored
@@ -12,4 +12,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
|
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
days-before-close: 5
|
days-before-close: 5
|
||||||
|
exempt-issue-labels: 'bug,enhancement'
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,3 +14,5 @@
|
|||||||
/*.xcframework/
|
/*.xcframework/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/config.d/
|
/config.d/
|
||||||
|
/venv/
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,7 @@ linters:
|
|||||||
- gci
|
- gci
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- paralleltest
|
- paralleltest
|
||||||
|
- ineffassign
|
||||||
run:
|
|
||||||
skip-dirs:
|
|
||||||
- transport/simple-obfs
|
|
||||||
- transport/clashssr
|
|
||||||
- transport/cloudflaretls
|
|
||||||
- transport/shadowtls/tls
|
|
||||||
- transport/shadowtls/tls_go119
|
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
gci:
|
gci:
|
||||||
@@ -23,4 +16,13 @@ linters-settings:
|
|||||||
- prefix(github.com/sagernet/)
|
- prefix(github.com/sagernet/)
|
||||||
- default
|
- default
|
||||||
staticcheck:
|
staticcheck:
|
||||||
go: '1.20'
|
checks:
|
||||||
|
- all
|
||||||
|
- -SA1003
|
||||||
|
|
||||||
|
run:
|
||||||
|
go: "1.23"
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exclude-dirs:
|
||||||
|
- transport/simple-obfs
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ builds:
|
|||||||
- linux_arm_7
|
- linux_arm_7
|
||||||
- linux_s390x
|
- linux_s390x
|
||||||
- linux_riscv64
|
- linux_riscv64
|
||||||
|
- linux_mips64le
|
||||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
||||||
@@ -36,7 +37,6 @@ nfpms:
|
|||||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||||
builds:
|
builds:
|
||||||
- main
|
- main
|
||||||
vendor: sagernet
|
|
||||||
homepage: https://sing-box.sagernet.org/
|
homepage: https://sing-box.sagernet.org/
|
||||||
maintainer: nekohasekai <contact-git@sekai.icu>
|
maintainer: nekohasekai <contact-git@sekai.icu>
|
||||||
description: The universal proxy platform.
|
description: The universal proxy platform.
|
||||||
@@ -55,11 +55,20 @@ nfpms:
|
|||||||
dst: /usr/lib/systemd/system/sing-box@.service
|
dst: /usr/lib/systemd/system/sing-box@.service
|
||||||
- src: LICENSE
|
- src: LICENSE
|
||||||
dst: /usr/share/licenses/sing-box/LICENSE
|
dst: /usr/share/licenses/sing-box/LICENSE
|
||||||
|
deb:
|
||||||
|
signature:
|
||||||
|
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
||||||
|
fields:
|
||||||
|
Bugs: https://github.com/SagerNet/sing-box/issues
|
||||||
|
rpm:
|
||||||
|
signature:
|
||||||
|
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
||||||
conflicts:
|
conflicts:
|
||||||
- sing-box-beta
|
- sing-box-beta
|
||||||
- id: package_beta
|
- id: package_beta
|
||||||
<<: *template
|
<<: *template
|
||||||
package_name: sing-box-beta
|
package_name: sing-box-beta
|
||||||
|
file_name_template: '{{ .ProjectName }}-beta_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||||
formats:
|
formats:
|
||||||
- deb
|
- deb
|
||||||
- rpm
|
- rpm
|
||||||
@@ -71,10 +80,8 @@ furies:
|
|||||||
- account: sagernet
|
- account: sagernet
|
||||||
ids:
|
ids:
|
||||||
- package
|
- package
|
||||||
skip: |-
|
disable: "{{ not (not .Prerelease) }}"
|
||||||
{{ eq .Prerelease "" }}
|
|
||||||
- account: sagernet
|
- account: sagernet
|
||||||
ids:
|
ids:
|
||||||
- package_beta
|
- package_beta
|
||||||
skip: |-
|
disable: "{{ not .Prerelease }}"
|
||||||
{{ ne .Prerelease "" }}
|
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ builds:
|
|||||||
- -v
|
- -v
|
||||||
- -trimpath
|
- -trimpath
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
|
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }}
|
||||||
|
- -s
|
||||||
|
- -buildid=
|
||||||
tags:
|
tags:
|
||||||
- with_gvisor
|
- with_gvisor
|
||||||
- with_quic
|
- with_quic
|
||||||
@@ -25,9 +27,11 @@ builds:
|
|||||||
- linux_amd64_v1
|
- linux_amd64_v1
|
||||||
- linux_amd64_v3
|
- linux_amd64_v3
|
||||||
- linux_arm64
|
- linux_arm64
|
||||||
|
- linux_arm_6
|
||||||
- linux_arm_7
|
- linux_arm_7
|
||||||
- linux_s390x
|
- linux_s390x
|
||||||
- linux_riscv64
|
- linux_riscv64
|
||||||
|
- linux_mips64le
|
||||||
- windows_amd64_v1
|
- windows_amd64_v1
|
||||||
- windows_amd64_v3
|
- windows_amd64_v3
|
||||||
- windows_386
|
- windows_386
|
||||||
@@ -113,7 +117,6 @@ nfpms:
|
|||||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||||
builds:
|
builds:
|
||||||
- main
|
- main
|
||||||
vendor: sagernet
|
|
||||||
homepage: https://sing-box.sagernet.org/
|
homepage: https://sing-box.sagernet.org/
|
||||||
maintainer: nekohasekai <contact-git@sekai.icu>
|
maintainer: nekohasekai <contact-git@sekai.icu>
|
||||||
description: The universal proxy platform.
|
description: The universal proxy platform.
|
||||||
@@ -136,6 +139,8 @@ nfpms:
|
|||||||
deb:
|
deb:
|
||||||
signature:
|
signature:
|
||||||
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
||||||
|
fields:
|
||||||
|
Bugs: https://github.com/SagerNet/sing-box/issues
|
||||||
rpm:
|
rpm:
|
||||||
signature:
|
signature:
|
||||||
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
||||||
|
|||||||
67
Makefile
67
Makefile
@@ -81,7 +81,6 @@ release_repo:
|
|||||||
go run ./cmd/internal/build goreleaser release -f .goreleaser.fury.yaml --clean
|
go run ./cmd/internal/build goreleaser release -f .goreleaser.fury.yaml --clean
|
||||||
|
|
||||||
release_install:
|
release_install:
|
||||||
go install -v github.com/goreleaser/goreleaser@latest
|
|
||||||
go install -v github.com/tcnksm/ghr@latest
|
go install -v github.com/tcnksm/ghr@latest
|
||||||
|
|
||||||
update_android_version:
|
update_android_version:
|
||||||
@@ -105,10 +104,12 @@ publish_android:
|
|||||||
publish_android_appcenter:
|
publish_android_appcenter:
|
||||||
cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadPlayRelease
|
cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadPlayRelease
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: find why and remove `-destination 'generic/platform=iOS'`
|
||||||
build_ios:
|
build_ios:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFI.xcarchive && \
|
rm -rf build/SFI.xcarchive && \
|
||||||
xcodebuild archive -scheme SFI -configuration Release -archivePath build/SFI.xcarchive
|
xcodebuild archive -scheme SFI -configuration Release -destination 'generic/platform=iOS' -archivePath build/SFI.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
upload_ios_app_store:
|
upload_ios_app_store:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
@@ -119,55 +120,61 @@ release_ios: build_ios upload_ios_app_store
|
|||||||
build_macos:
|
build_macos:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFM.xcarchive && \
|
rm -rf build/SFM.xcarchive && \
|
||||||
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive
|
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
upload_macos_app_store:
|
upload_macos_app_store:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
||||||
|
|
||||||
release_macos: build_macos upload_macos_app_store
|
release_macos: build_macos upload_macos_app_store
|
||||||
|
|
||||||
build_macos_independent:
|
build_macos_standalone:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFT.System.xcarchive && \
|
rm -rf build/SFM.System.xcarchive && \
|
||||||
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive
|
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
notarize_macos_independent:
|
build_macos_dmg:
|
||||||
cd ../sing-box-for-apple && \
|
|
||||||
xcodebuild -exportArchive -archivePath "build/SFM.System.xcarchive" -exportOptionsPlist SFM.System/Upload.plist -allowProvisioningUpdates
|
|
||||||
|
|
||||||
wait_notarize_macos_independent:
|
|
||||||
sleep 60
|
|
||||||
|
|
||||||
export_macos_independent:
|
|
||||||
rm -rf dist/SFM
|
rm -rf dist/SFM
|
||||||
mkdir -p dist/SFM
|
mkdir -p dist/SFM
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
xcodebuild -exportNotarizedApp -archivePath build/SFM.System.xcarchive -exportPath "../sing-box/dist/SFM"
|
rm -rf build/SFM.System && \
|
||||||
|
rm -rf build/SFM.dmg && \
|
||||||
|
xcodebuild -exportArchive \
|
||||||
|
-archivePath "build/SFM.System.xcarchive" \
|
||||||
|
-exportOptionsPlist SFM.System/Export.plist -allowProvisioningUpdates \
|
||||||
|
-exportPath "build/SFM.System" && \
|
||||||
|
create-dmg \
|
||||||
|
--volname "sing-box" \
|
||||||
|
--volicon "build/SFM.System/SFM.app/Contents/Resources/AppIcon.icns" \
|
||||||
|
--icon "SFM.app" 0 0 \
|
||||||
|
--hide-extension "SFM.app" \
|
||||||
|
--app-drop-link 0 0 \
|
||||||
|
--skip-jenkins \
|
||||||
|
--notarize "notarytool-password" \
|
||||||
|
"../sing-box/dist/SFM/SFM.dmg" "build/SFM.System/SFM.app"
|
||||||
|
|
||||||
upload_macos_independent:
|
upload_macos_dmg:
|
||||||
cd dist/SFM && \
|
cd dist/SFM && \
|
||||||
rm -f *.zip && \
|
cp SFM.dmg "SFM-${VERSION}-universal.dmg" && \
|
||||||
zip -ry "SFM-${VERSION}-universal.zip" SFM.app && \
|
ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dmg"
|
||||||
ghr --replace --draft --prerelease "v${VERSION}" *.zip
|
|
||||||
|
|
||||||
release_macos_independent: build_macos_independent notarize_macos_independent wait_notarize_macos_independent export_macos_independent upload_macos_independent
|
release_macos_standalone: build_macos_standalone build_macos_dmg upload_macos_dmg
|
||||||
|
|
||||||
build_tvos:
|
build_tvos:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFT.xcarchive && \
|
rm -rf build/SFT.xcarchive && \
|
||||||
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive
|
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
upload_tvos_app_store:
|
upload_tvos_app_store:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
||||||
|
|
||||||
release_tvos: build_tvos upload_tvos_app_store
|
release_tvos: build_tvos upload_tvos_app_store
|
||||||
|
|
||||||
update_apple_version:
|
update_apple_version:
|
||||||
go run ./cmd/internal/update_apple_version
|
go run ./cmd/internal/update_apple_version
|
||||||
|
|
||||||
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_independent
|
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos
|
||||||
|
|
||||||
release_apple_beta: update_apple_version release_ios release_macos release_tvos
|
release_apple_beta: update_apple_version release_ios release_macos release_tvos
|
||||||
|
|
||||||
@@ -194,17 +201,19 @@ 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.3
|
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.4
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.3
|
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.4
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
mkdocs serve
|
venv/bin/mkdocs serve
|
||||||
|
|
||||||
publish_docs:
|
publish_docs:
|
||||||
mkdocs gh-deploy -m "Update" --force --ignore-version --no-history
|
venv/bin/mkdocs gh-deploy -m "Update" --force --ignore-version --no-history
|
||||||
|
|
||||||
docs_install:
|
docs_install:
|
||||||
pip install --force-reinstall mkdocs-material=="9.*" mkdocs-static-i18n=="1.2.*"
|
python -m venv venv
|
||||||
|
source ./venv/bin/activate && pip install --force-reinstall mkdocs-material=="9.*" mkdocs-static-i18n=="1.2.*"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin dist sing-box
|
rm -rf bin dist sing-box
|
||||||
rm -f $(shell go env GOPATH)/sing-box
|
rm -f $(shell go env GOPATH)/sing-box
|
||||||
|
|||||||
@@ -8,10 +8,6 @@ The universal proxy platform.
|
|||||||
|
|
||||||
https://sing-box.sagernet.org
|
https://sing-box.sagernet.org
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
https://community.sagernet.org/c/sing-box/
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
|
"github.com/sagernet/sing-dns"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
)
|
)
|
||||||
@@ -30,6 +31,9 @@ type CacheFile interface {
|
|||||||
StoreFakeIP() bool
|
StoreFakeIP() bool
|
||||||
FakeIPStorage
|
FakeIPStorage
|
||||||
|
|
||||||
|
StoreRDRC() bool
|
||||||
|
dns.RDRCStore
|
||||||
|
|
||||||
LoadMode() string
|
LoadMode() string
|
||||||
StoreMode(mode string) error
|
StoreMode(mode string) error
|
||||||
LoadSelected(group string) string
|
LoadSelected(group string) string
|
||||||
|
|||||||
@@ -51,11 +51,13 @@ type InboundContext struct {
|
|||||||
|
|
||||||
// rule cache
|
// rule cache
|
||||||
|
|
||||||
IPCIDRMatchSource bool
|
IPCIDRMatchSource bool
|
||||||
SourceAddressMatch bool
|
SourceAddressMatch bool
|
||||||
SourcePortMatch bool
|
SourcePortMatch bool
|
||||||
DestinationAddressMatch bool
|
DestinationAddressMatch bool
|
||||||
DestinationPortMatch bool
|
DestinationPortMatch bool
|
||||||
|
DidMatch bool
|
||||||
|
IgnoreDestinationIPCIDRMatch bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InboundContext) ResetRuleCache() {
|
func (c *InboundContext) ResetRuleCache() {
|
||||||
@@ -64,6 +66,7 @@ func (c *InboundContext) ResetRuleCache() {
|
|||||||
c.SourcePortMatch = false
|
c.SourcePortMatch = false
|
||||||
c.DestinationAddressMatch = false
|
c.DestinationAddressMatch = false
|
||||||
c.DestinationPortMatch = false
|
c.DestinationPortMatch = false
|
||||||
|
c.DidMatch = false
|
||||||
}
|
}
|
||||||
|
|
||||||
type inboundContextKey struct{}
|
type inboundContextKey struct{}
|
||||||
@@ -96,3 +99,12 @@ func ExtendContext(ctx context.Context) (context.Context, *InboundContext) {
|
|||||||
}
|
}
|
||||||
return WithContext(ctx, &newMetadata), &newMetadata
|
return WithContext(ctx, &newMetadata), &newMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func OverrideContext(ctx context.Context) context.Context {
|
||||||
|
if metadata := ContextFrom(ctx); metadata != nil {
|
||||||
|
var newMetadata InboundContext
|
||||||
|
newMetadata = *metadata
|
||||||
|
return WithContext(ctx, &newMetadata)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ func RouterFromContext(ctx context.Context) Router {
|
|||||||
|
|
||||||
type HeadlessRule interface {
|
type HeadlessRule interface {
|
||||||
Match(metadata *InboundContext) bool
|
Match(metadata *InboundContext) bool
|
||||||
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
@@ -79,18 +80,19 @@ type Rule interface {
|
|||||||
Type() string
|
Type() string
|
||||||
UpdateGeosite() error
|
UpdateGeosite() error
|
||||||
Outbound() string
|
Outbound() string
|
||||||
String() string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSRule interface {
|
type DNSRule interface {
|
||||||
Rule
|
Rule
|
||||||
DisableCache() bool
|
DisableCache() bool
|
||||||
RewriteTTL() *uint32
|
RewriteTTL() *uint32
|
||||||
|
ClientSubnet() *netip.Prefix
|
||||||
|
WithAddressLimit() bool
|
||||||
|
MatchAddressLimit(metadata *InboundContext) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuleSet interface {
|
type RuleSet interface {
|
||||||
StartContext(ctx context.Context, startContext RuleSetStartContext) error
|
StartContext(ctx context.Context, startContext RuleSetStartContext) error
|
||||||
PostStart() error
|
|
||||||
Metadata() RuleSetMetadata
|
Metadata() RuleSetMetadata
|
||||||
Close() error
|
Close() error
|
||||||
HeadlessRule
|
HeadlessRule
|
||||||
@@ -99,6 +101,7 @@ type RuleSet interface {
|
|||||||
type RuleSetMetadata struct {
|
type RuleSetMetadata struct {
|
||||||
ContainsProcessRule bool
|
ContainsProcessRule bool
|
||||||
ContainsWIFIRule bool
|
ContainsWIFIRule bool
|
||||||
|
ContainsIPCIDRRule bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuleSetStartContext interface {
|
type RuleSetStartContext interface {
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ type V2RayServerTransportHandler interface {
|
|||||||
|
|
||||||
type V2RayClientTransport interface {
|
type V2RayClientTransport interface {
|
||||||
DialContext(ctx context.Context) (net.Conn, error)
|
DialContext(ctx context.Context) (net.Conn, error)
|
||||||
|
Close() error
|
||||||
}
|
}
|
||||||
|
|||||||
10
box.go
10
box.go
@@ -203,7 +203,7 @@ func (s *Box) PreStart() error {
|
|||||||
defer func() {
|
defer func() {
|
||||||
v := recover()
|
v := recover()
|
||||||
if v != nil {
|
if v != nil {
|
||||||
log.Error(E.Cause(err, "origin error"))
|
println(err.Error())
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
panic("panic on early close: " + fmt.Sprint(v))
|
panic("panic on early close: " + fmt.Sprint(v))
|
||||||
}
|
}
|
||||||
@@ -222,9 +222,9 @@ func (s *Box) Start() error {
|
|||||||
defer func() {
|
defer func() {
|
||||||
v := recover()
|
v := recover()
|
||||||
if v != nil {
|
if v != nil {
|
||||||
log.Error(E.Cause(err, "origin error"))
|
println(err.Error())
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
panic("panic on early close: " + fmt.Sprint(v))
|
println("panic on early start: " + fmt.Sprint(v))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
s.Close()
|
s.Close()
|
||||||
@@ -235,7 +235,7 @@ func (s *Box) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Box) preStart() error {
|
func (s *Box) preStart() error {
|
||||||
monitor := taskmonitor.New(s.logger, C.DefaultStartTimeout)
|
monitor := taskmonitor.New(s.logger, C.StartTimeout)
|
||||||
monitor.Start("start logger")
|
monitor.Start("start logger")
|
||||||
err := s.logFactory.Start()
|
err := s.logFactory.Start()
|
||||||
monitor.Finish()
|
monitor.Finish()
|
||||||
@@ -331,7 +331,7 @@ func (s *Box) Close() error {
|
|||||||
default:
|
default:
|
||||||
close(s.done)
|
close(s.done)
|
||||||
}
|
}
|
||||||
monitor := taskmonitor.New(s.logger, C.DefaultStopTimeout)
|
monitor := taskmonitor.New(s.logger, C.StopTimeout)
|
||||||
var errors error
|
var errors error
|
||||||
for serviceName, service := range s.postServices {
|
for serviceName, service := range s.postServices {
|
||||||
monitor.Start("close ", serviceName)
|
monitor.Start("close ", serviceName)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *Box) startOutbounds() error {
|
func (s *Box) startOutbounds() error {
|
||||||
monitor := taskmonitor.New(s.logger, C.DefaultStartTimeout)
|
monitor := taskmonitor.New(s.logger, C.StartTimeout)
|
||||||
outboundTags := make(map[adapter.Outbound]string)
|
outboundTags := make(map[adapter.Outbound]string)
|
||||||
outbounds := make(map[string]adapter.Outbound)
|
outbounds := make(map[string]adapter.Outbound)
|
||||||
for i, outboundToStart := range s.outbounds {
|
for i, outboundToStart := range s.outbounds {
|
||||||
|
|||||||
Submodule clients/android updated: 1a7b9dc6fd...defe07a26f
Submodule clients/apple updated: db8cbfa865...41ed30a5fa
@@ -26,8 +26,8 @@ func main() {
|
|||||||
common.Must(decoder.Decode(&project))
|
common.Must(decoder.Decode(&project))
|
||||||
objectsMap := project["objects"].(map[string]any)
|
objectsMap := project["objects"].(map[string]any)
|
||||||
projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
|
projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
|
||||||
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfa"}, newVersion.VersionString())
|
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfavt"}, newVersion.VersionString())
|
||||||
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfa.independent", "io.nekohasekai.sfa.system"}, newVersion.String())
|
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfavt.standalone", "io.nekohasekai.sfavt.system"}, newVersion.String())
|
||||||
if updated0 || updated1 {
|
if updated0 || updated1 {
|
||||||
log.Info("updated version to ", newVersion.VersionString(), " (", newVersion.String(), ")")
|
log.Info("updated version to ", newVersion.VersionString(), " (", newVersion.String(), ")")
|
||||||
}
|
}
|
||||||
|
|||||||
87
cmd/sing-box/cmd_rule_set_match.go
Normal file
87
cmd/sing-box/cmd_rule_set_match.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/common/srs"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing-box/route"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var flagRuleSetMatchFormat string
|
||||||
|
|
||||||
|
var commandRuleSetMatch = &cobra.Command{
|
||||||
|
Use: "match <rule-set path> <domain>",
|
||||||
|
Short: "Check if a domain matches the rule set",
|
||||||
|
Args: cobra.ExactArgs(2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := ruleSetMatch(args[0], args[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
commandRuleSetMatch.Flags().StringVarP(&flagRuleSetMatchFormat, "format", "f", "source", "rule-set format")
|
||||||
|
commandRuleSet.AddCommand(commandRuleSetMatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ruleSetMatch(sourcePath string, domain string) error {
|
||||||
|
var (
|
||||||
|
reader io.Reader
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if sourcePath == "stdin" {
|
||||||
|
reader = os.Stdin
|
||||||
|
} else {
|
||||||
|
reader, err = os.Open(sourcePath)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "read rule-set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "read rule-set")
|
||||||
|
}
|
||||||
|
var plainRuleSet option.PlainRuleSet
|
||||||
|
switch flagRuleSetMatchFormat {
|
||||||
|
case C.RuleSetFormatSource:
|
||||||
|
var compat option.PlainRuleSetCompat
|
||||||
|
compat, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
plainRuleSet = compat.Upgrade()
|
||||||
|
case C.RuleSetFormatBinary:
|
||||||
|
plainRuleSet, err = srs.Read(bytes.NewReader(content), false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return E.New("unknown rule set format: ", flagRuleSetMatchFormat)
|
||||||
|
}
|
||||||
|
for i, ruleOptions := range plainRuleSet.Rules {
|
||||||
|
var currentRule adapter.HeadlessRule
|
||||||
|
currentRule, err = route.NewHeadlessRule(nil, ruleOptions)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "parse rule_set.rules.[", i, "]")
|
||||||
|
}
|
||||||
|
if currentRule.Match(&adapter.InboundContext{
|
||||||
|
Domain: domain,
|
||||||
|
}) {
|
||||||
|
println(F.ToString("match rules.[", i, "]: ", currentRule))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -199,7 +199,7 @@ func run() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func closeMonitor(ctx context.Context) {
|
func closeMonitor(ctx context.Context) {
|
||||||
time.Sleep(C.DefaultStopFatalTimeout)
|
time.Sleep(C.FatalStopTimeout)
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ package badtls
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -18,20 +20,32 @@ import (
|
|||||||
var _ N.ReadWaiter = (*ReadWaitConn)(nil)
|
var _ N.ReadWaiter = (*ReadWaitConn)(nil)
|
||||||
|
|
||||||
type ReadWaitConn struct {
|
type ReadWaitConn struct {
|
||||||
*tls.STDConn
|
tls.Conn
|
||||||
halfAccess *sync.Mutex
|
halfAccess *sync.Mutex
|
||||||
rawInput *bytes.Buffer
|
rawInput *bytes.Buffer
|
||||||
input *bytes.Reader
|
input *bytes.Reader
|
||||||
hand *bytes.Buffer
|
hand *bytes.Buffer
|
||||||
readWaitOptions N.ReadWaitOptions
|
readWaitOptions N.ReadWaitOptions
|
||||||
|
tlsReadRecord func() error
|
||||||
|
tlsHandlePostHandshakeMessage func() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) {
|
func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) {
|
||||||
stdConn, isSTDConn := conn.(*tls.STDConn)
|
var (
|
||||||
if !isSTDConn {
|
loaded bool
|
||||||
|
tlsReadRecord func() error
|
||||||
|
tlsHandlePostHandshakeMessage func() error
|
||||||
|
)
|
||||||
|
for _, tlsCreator := range tlsRegistry {
|
||||||
|
loaded, tlsReadRecord, tlsHandlePostHandshakeMessage = tlsCreator(conn)
|
||||||
|
if loaded {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !loaded {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
rawConn := reflect.Indirect(reflect.ValueOf(stdConn))
|
rawConn := reflect.Indirect(reflect.ValueOf(conn))
|
||||||
rawHalfConn := rawConn.FieldByName("in")
|
rawHalfConn := rawConn.FieldByName("in")
|
||||||
if !rawHalfConn.IsValid() || rawHalfConn.Kind() != reflect.Struct {
|
if !rawHalfConn.IsValid() || rawHalfConn.Kind() != reflect.Struct {
|
||||||
return nil, E.New("badtls: invalid half conn")
|
return nil, E.New("badtls: invalid half conn")
|
||||||
@@ -57,11 +71,13 @@ func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) {
|
|||||||
}
|
}
|
||||||
hand := (*bytes.Buffer)(unsafe.Pointer(rawHand.UnsafeAddr()))
|
hand := (*bytes.Buffer)(unsafe.Pointer(rawHand.UnsafeAddr()))
|
||||||
return &ReadWaitConn{
|
return &ReadWaitConn{
|
||||||
STDConn: stdConn,
|
Conn: conn,
|
||||||
halfAccess: halfAccess,
|
halfAccess: halfAccess,
|
||||||
rawInput: rawInput,
|
rawInput: rawInput,
|
||||||
input: input,
|
input: input,
|
||||||
hand: hand,
|
hand: hand,
|
||||||
|
tlsReadRecord: tlsReadRecord,
|
||||||
|
tlsHandlePostHandshakeMessage: tlsHandlePostHandshakeMessage,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,19 +87,19 @@ func (c *ReadWaitConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
||||||
err = c.Handshake()
|
err = c.HandshakeContext(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.halfAccess.Lock()
|
c.halfAccess.Lock()
|
||||||
defer c.halfAccess.Unlock()
|
defer c.halfAccess.Unlock()
|
||||||
for c.input.Len() == 0 {
|
for c.input.Len() == 0 {
|
||||||
err = tlsReadRecord(c.STDConn)
|
err = c.tlsReadRecord()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for c.hand.Len() > 0 {
|
for c.hand.Len() > 0 {
|
||||||
err = tlsHandlePostHandshakeMessage(c.STDConn)
|
err = c.tlsHandlePostHandshakeMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -100,7 +116,7 @@ func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
|||||||
if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
|
if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
|
||||||
// recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
|
// recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
|
||||||
c.rawInput.Bytes()[0] == 21 {
|
c.rawInput.Bytes()[0] == 21 {
|
||||||
_ = tlsReadRecord(c.STDConn)
|
_ = c.tlsReadRecord()
|
||||||
// return n, err // will be io.EOF on closeNotify
|
// return n, err // will be io.EOF on closeNotify
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,11 +125,27 @@ func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ReadWaitConn) Upstream() any {
|
func (c *ReadWaitConn) Upstream() any {
|
||||||
return c.STDConn
|
return c.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname tlsReadRecord crypto/tls.(*Conn).readRecord
|
var tlsRegistry []func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error)
|
||||||
func tlsReadRecord(c *tls.STDConn) error
|
|
||||||
|
|
||||||
//go:linkname tlsHandlePostHandshakeMessage crypto/tls.(*Conn).handlePostHandshakeMessage
|
func init() {
|
||||||
func tlsHandlePostHandshakeMessage(c *tls.STDConn) error
|
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
|
||||||
|
tlsConn, loaded := conn.(*tls.STDConn)
|
||||||
|
if !loaded {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return true, func() error {
|
||||||
|
return stdTLSReadRecord(tlsConn)
|
||||||
|
}, func() error {
|
||||||
|
return stdTLSHandlePostHandshakeMessage(tlsConn)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname stdTLSReadRecord crypto/tls.(*Conn).readRecord
|
||||||
|
func stdTLSReadRecord(c *tls.STDConn) error
|
||||||
|
|
||||||
|
//go:linkname stdTLSHandlePostHandshakeMessage crypto/tls.(*Conn).handlePostHandshakeMessage
|
||||||
|
func stdTLSHandlePostHandshakeMessage(c *tls.STDConn) error
|
||||||
|
|||||||
31
common/badtls/read_wait_ech.go
Normal file
31
common/badtls/read_wait_ech.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//go:build go1.21 && !without_badtls && with_ech
|
||||||
|
|
||||||
|
package badtls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/sagernet/cloudflare-tls"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
|
||||||
|
tlsConn, loaded := common.Cast[*tls.Conn](conn)
|
||||||
|
if !loaded {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return true, func() error {
|
||||||
|
return echReadRecord(tlsConn)
|
||||||
|
}, func() error {
|
||||||
|
return echHandlePostHandshakeMessage(tlsConn)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname echReadRecord github.com/sagernet/cloudflare-tls.(*Conn).readRecord
|
||||||
|
func echReadRecord(c *tls.Conn) error
|
||||||
|
|
||||||
|
//go:linkname echHandlePostHandshakeMessage github.com/sagernet/cloudflare-tls.(*Conn).handlePostHandshakeMessage
|
||||||
|
func echHandlePostHandshakeMessage(c *tls.Conn) error
|
||||||
31
common/badtls/read_wait_utls.go
Normal file
31
common/badtls/read_wait_utls.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//go:build go1.21 && !without_badtls && with_utls
|
||||||
|
|
||||||
|
package badtls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/utls"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
|
||||||
|
tlsConn, loaded := common.Cast[*tls.UConn](conn)
|
||||||
|
if !loaded {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return true, func() error {
|
||||||
|
return utlsReadRecord(tlsConn.Conn)
|
||||||
|
}, func() error {
|
||||||
|
return utlsHandlePostHandshakeMessage(tlsConn.Conn)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname utlsReadRecord github.com/sagernet/utls.(*Conn).readRecord
|
||||||
|
func utlsReadRecord(c *tls.Conn) error
|
||||||
|
|
||||||
|
//go:linkname utlsHandlePostHandshakeMessage github.com/sagernet/utls.(*Conn).handlePostHandshakeMessage
|
||||||
|
func utlsHandlePostHandshakeMessage(c *tls.Conn) error
|
||||||
@@ -32,14 +32,20 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
|||||||
var dialer net.Dialer
|
var dialer net.Dialer
|
||||||
var listener net.ListenConfig
|
var listener net.ListenConfig
|
||||||
if options.BindInterface != "" {
|
if options.BindInterface != "" {
|
||||||
bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
|
var interfaceFinder control.InterfaceFinder
|
||||||
|
if router != nil {
|
||||||
|
interfaceFinder = router.InterfaceFinder()
|
||||||
|
} else {
|
||||||
|
interfaceFinder = control.NewDefaultInterfaceFinder()
|
||||||
|
}
|
||||||
|
bindFunc := control.BindToInterface(interfaceFinder, options.BindInterface, -1)
|
||||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||||
listener.Control = control.Append(listener.Control, bindFunc)
|
listener.Control = control.Append(listener.Control, bindFunc)
|
||||||
} else if router.AutoDetectInterface() {
|
} else if router != nil && router.AutoDetectInterface() {
|
||||||
bindFunc := router.AutoDetectInterfaceFunc()
|
bindFunc := router.AutoDetectInterfaceFunc()
|
||||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||||
listener.Control = control.Append(listener.Control, bindFunc)
|
listener.Control = control.Append(listener.Control, bindFunc)
|
||||||
} else if router.DefaultInterface() != "" {
|
} else if router != nil && router.DefaultInterface() != "" {
|
||||||
bindFunc := control.BindToInterface(router.InterfaceFinder(), router.DefaultInterface(), -1)
|
bindFunc := control.BindToInterface(router.InterfaceFinder(), router.DefaultInterface(), -1)
|
||||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||||
listener.Control = control.Append(listener.Control, bindFunc)
|
listener.Control = control.Append(listener.Control, bindFunc)
|
||||||
@@ -47,7 +53,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
|||||||
if options.RoutingMark != 0 {
|
if options.RoutingMark != 0 {
|
||||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
||||||
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
|
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
|
||||||
} else if router.DefaultMark() != 0 {
|
} else if router != nil && router.DefaultMark() != 0 {
|
||||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(router.DefaultMark()))
|
dialer.Control = control.Append(dialer.Control, control.RoutingMark(router.DefaultMark()))
|
||||||
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
|
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
|
||||||
}
|
}
|
||||||
@@ -63,6 +69,9 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
|||||||
} else {
|
} else {
|
||||||
dialer.Timeout = C.TCPTimeout
|
dialer.Timeout = C.TCPTimeout
|
||||||
}
|
}
|
||||||
|
// TODO: Add an option to customize the keep alive period
|
||||||
|
dialer.KeepAlive = C.TCPKeepAliveInitial
|
||||||
|
dialer.Control = control.Append(dialer.Control, control.SetKeepAlivePeriod(C.TCPKeepAliveInitial, C.TCPKeepAliveInterval))
|
||||||
var udpFragment bool
|
var udpFragment bool
|
||||||
if options.UDPFragment != nil {
|
if options.UDPFragment != nil {
|
||||||
udpFragment = *options.UDPFragment
|
udpFragment = *options.UDPFragment
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package dialer
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/tfo-go"
|
"github.com/metacubex/tfo-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tcpDialer = tfo.Dialer
|
type tcpDialer = tfo.Dialer
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
|
|||||||
if options.IsWireGuardListener {
|
if options.IsWireGuardListener {
|
||||||
return NewDefault(router, options)
|
return NewDefault(router, options)
|
||||||
}
|
}
|
||||||
|
if router == nil {
|
||||||
|
return NewDefault(nil, options)
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
err error
|
err error
|
||||||
@@ -25,13 +28,12 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
|
|||||||
} else {
|
} else {
|
||||||
dialer = NewDetour(router, options.Detour)
|
dialer = NewDetour(router, options.Detour)
|
||||||
}
|
}
|
||||||
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
|
if options.Detour == "" {
|
||||||
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {
|
|
||||||
dialer = NewResolveDialer(
|
dialer = NewResolveDialer(
|
||||||
router,
|
router,
|
||||||
dialer,
|
dialer,
|
||||||
options.Detour == "" && !options.TCPFastOpen,
|
options.Detour == "" && !options.TCPFastOpen,
|
||||||
domainStrategy,
|
dns.DomainStrategy(options.DomainStrategy),
|
||||||
time.Duration(options.FallbackDelay))
|
time.Duration(options.FallbackDelay))
|
||||||
}
|
}
|
||||||
return dialer, nil
|
return dialer, nil
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import (
|
|||||||
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"
|
||||||
"github.com/sagernet/tfo-go"
|
|
||||||
|
"github.com/metacubex/tfo-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type slowOpenConn struct {
|
type slowOpenConn struct {
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
package mux
|
package mux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-mux"
|
"github.com/sagernet/sing-mux"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +35,7 @@ func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mux.NewClient(mux.Options{
|
return mux.NewClient(mux.Options{
|
||||||
Dialer: dialer,
|
Dialer: &clientDialer{dialer},
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
Protocol: options.Protocol,
|
Protocol: options.Protocol,
|
||||||
MaxConnections: options.MaxConnections,
|
MaxConnections: options.MaxConnections,
|
||||||
@@ -40,3 +45,15 @@ func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.
|
|||||||
Brutal: brutalOptions,
|
Brutal: brutalOptions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type clientDialer struct {
|
||||||
|
N.Dialer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *clientDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
return d.Dialer.DialContext(adapter.OverrideContext(ctx), network, destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *clientDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
return d.Dialer.ListenPacket(adapter.OverrideContext(ctx), destination)
|
||||||
|
}
|
||||||
|
|||||||
@@ -60,12 +60,12 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
|
|||||||
|
|
||||||
isIPv4 := ip.Is4()
|
isIPv4 := ip.Is4()
|
||||||
|
|
||||||
value, err := syscall.Sysctl(spath)
|
value, err := unix.SysctlRaw(spath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := []byte(value)
|
buf := value
|
||||||
|
|
||||||
// from darwin-xnu/bsd/netinet/in_pcblist.c:get_pcblist_n
|
// from darwin-xnu/bsd/netinet/in_pcblist.c:get_pcblist_n
|
||||||
// size/offset are round up (aligned) to 8 bytes in darwin
|
// size/offset are round up (aligned) to 8 bytes in darwin
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ func getExecPathFromPID(pid uint32) (string, error) {
|
|||||||
r1, _, err := syscall.SyscallN(
|
r1, _, err := syscall.SyscallN(
|
||||||
procQueryFullProcessImageNameW.Addr(),
|
procQueryFullProcessImageNameW.Addr(),
|
||||||
uintptr(h),
|
uintptr(h),
|
||||||
uintptr(1),
|
uintptr(0),
|
||||||
uintptr(unsafe.Pointer(&buf[0])),
|
uintptr(unsafe.Pointer(&buf[0])),
|
||||||
uintptr(unsafe.Pointer(&size)),
|
uintptr(unsafe.Pointer(&size)),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,30 +16,40 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type LinuxSystemProxy struct {
|
type LinuxSystemProxy struct {
|
||||||
hasGSettings bool
|
hasGSettings bool
|
||||||
hasKWriteConfig5 bool
|
kWriteConfigCmd string
|
||||||
sudoUser string
|
sudoUser string
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
supportSOCKS bool
|
supportSOCKS bool
|
||||||
isEnabled bool
|
isEnabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*LinuxSystemProxy, error) {
|
func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*LinuxSystemProxy, error) {
|
||||||
hasGSettings := common.Error(exec.LookPath("gsettings")) == nil
|
hasGSettings := common.Error(exec.LookPath("gsettings")) == nil
|
||||||
hasKWriteConfig5 := common.Error(exec.LookPath("kwriteconfig5")) == nil
|
kWriteConfigCmds := []string{
|
||||||
|
"kwriteconfig5",
|
||||||
|
"kwriteconfig6",
|
||||||
|
}
|
||||||
|
var kWriteConfigCmd string
|
||||||
|
for _, cmd := range kWriteConfigCmds {
|
||||||
|
if common.Error(exec.LookPath(cmd)) == nil {
|
||||||
|
kWriteConfigCmd = cmd
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
var sudoUser string
|
var sudoUser string
|
||||||
if os.Getuid() == 0 {
|
if os.Getuid() == 0 {
|
||||||
sudoUser = os.Getenv("SUDO_USER")
|
sudoUser = os.Getenv("SUDO_USER")
|
||||||
}
|
}
|
||||||
if !hasGSettings && !hasKWriteConfig5 {
|
if !hasGSettings && kWriteConfigCmd == "" {
|
||||||
return nil, E.New("unsupported desktop environment")
|
return nil, E.New("unsupported desktop environment")
|
||||||
}
|
}
|
||||||
return &LinuxSystemProxy{
|
return &LinuxSystemProxy{
|
||||||
hasGSettings: hasGSettings,
|
hasGSettings: hasGSettings,
|
||||||
hasKWriteConfig5: hasKWriteConfig5,
|
kWriteConfigCmd: kWriteConfigCmd,
|
||||||
sudoUser: sudoUser,
|
sudoUser: sudoUser,
|
||||||
serverAddr: serverAddr,
|
serverAddr: serverAddr,
|
||||||
supportSOCKS: supportSOCKS,
|
supportSOCKS: supportSOCKS,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,8 +80,8 @@ func (p *LinuxSystemProxy) Enable() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.hasKWriteConfig5 {
|
if p.kWriteConfigCmd != "" {
|
||||||
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
|
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -83,7 +93,7 @@ func (p *LinuxSystemProxy) Enable() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
|
err = p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -103,8 +113,8 @@ func (p *LinuxSystemProxy) Disable() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.hasKWriteConfig5 {
|
if p.kWriteConfigCmd != "" {
|
||||||
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
|
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -150,7 +160,7 @@ func (p *LinuxSystemProxy) setKDEProxy(proxyTypes ...string) error {
|
|||||||
proxyUrl = "http://" + p.serverAddr.String()
|
proxyUrl = "http://" + p.serverAddr.String()
|
||||||
}
|
}
|
||||||
err := p.runAsUser(
|
err := p.runAsUser(
|
||||||
"kwriteconfig5",
|
p.kWriteConfigCmd,
|
||||||
"--file",
|
"--file",
|
||||||
"kioslaverc",
|
"kioslaverc",
|
||||||
"--group",
|
"--group",
|
||||||
|
|||||||
@@ -18,28 +18,45 @@ type (
|
|||||||
PacketSniffer = func(ctx context.Context, packet []byte) (*adapter.InboundContext, error)
|
PacketSniffer = func(ctx context.Context, packet []byte) (*adapter.InboundContext, error)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func Skip(metadata adapter.InboundContext) bool {
|
||||||
|
// skip server first protocols
|
||||||
|
switch metadata.Destination.Port {
|
||||||
|
case 25, 465, 587:
|
||||||
|
// SMTP
|
||||||
|
return true
|
||||||
|
case 143, 993:
|
||||||
|
// IMAP
|
||||||
|
return true
|
||||||
|
case 110, 995:
|
||||||
|
// POP3
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) (*adapter.InboundContext, error) {
|
func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) (*adapter.InboundContext, error) {
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
timeout = C.ReadPayloadTimeout
|
timeout = C.ReadPayloadTimeout
|
||||||
}
|
}
|
||||||
deadline := time.Now().Add(timeout)
|
deadline := time.Now().Add(timeout)
|
||||||
var errors []error
|
var errors []error
|
||||||
|
for i := 0; ; i++ {
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
err := conn.SetReadDeadline(deadline)
|
err := conn.SetReadDeadline(deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "set read deadline")
|
return nil, E.Cause(err, "set read deadline")
|
||||||
}
|
}
|
||||||
_, err = buffer.ReadOnceFrom(conn)
|
_, err = buffer.ReadOnceFrom(conn)
|
||||||
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
_ = conn.SetReadDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return nil, E.Cause(err, "read payload")
|
return nil, E.Cause(err, "read payload")
|
||||||
}
|
}
|
||||||
|
errors = nil
|
||||||
|
var metadata *adapter.InboundContext
|
||||||
for _, sniffer := range sniffers {
|
for _, sniffer := range sniffers {
|
||||||
metadata, err := sniffer(ctx, bytes.NewReader(buffer.Bytes()))
|
metadata, err = sniffer(ctx, bytes.NewReader(buffer.Bytes()))
|
||||||
if metadata != nil {
|
if metadata != nil {
|
||||||
return metadata, nil
|
return metadata, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ func (c *echClientConfig) DialEarly(ctx context.Context, conn net.PacketConn, ad
|
|||||||
return quic.DialEarly(ctx, conn, addr, c.config, config)
|
return quic.DialEarly(ctx, conn, addr, c.config, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config, enableDatagrams bool) http.RoundTripper {
|
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config) http.RoundTripper {
|
||||||
return &http3.RoundTripper{
|
return &http3.RoundTripper{
|
||||||
TLSClientConfig: c.config,
|
TLSClientConfig: c.config,
|
||||||
QuicConfig: quicConfig,
|
QUICConfig: quicConfig,
|
||||||
EnableDatagrams: enableDatagrams,
|
|
||||||
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||||
quicConn, err := quic.DialEarly(ctx, conn, serverAddr.UDPAddr(), tlsCfg, cfg)
|
quicConn, err := quic.DialEarly(ctx, conn, serverAddr.UDPAddr(), tlsCfg, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
5
constant/quic.go
Normal file
5
constant/quic.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build with_quic
|
||||||
|
|
||||||
|
package constant
|
||||||
|
|
||||||
|
const WithQUIC = true
|
||||||
5
constant/quic_stub.go
Normal file
5
constant/quic_stub.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !with_quic
|
||||||
|
|
||||||
|
package constant
|
||||||
|
|
||||||
|
const WithQUIC = false
|
||||||
@@ -3,15 +3,18 @@ package constant
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TCPTimeout = 5 * time.Second
|
TCPKeepAliveInitial = 10 * time.Minute
|
||||||
ReadPayloadTimeout = 300 * time.Millisecond
|
TCPKeepAliveInterval = 75 * time.Second
|
||||||
DNSTimeout = 10 * time.Second
|
TCPTimeout = 5 * time.Second
|
||||||
QUICTimeout = 30 * time.Second
|
ReadPayloadTimeout = 300 * time.Millisecond
|
||||||
STUNTimeout = 15 * time.Second
|
DNSTimeout = 10 * time.Second
|
||||||
UDPTimeout = 5 * time.Minute
|
QUICTimeout = 30 * time.Second
|
||||||
DefaultURLTestInterval = 3 * time.Minute
|
STUNTimeout = 15 * time.Second
|
||||||
DefaultURLTestIdleTimeout = 30 * time.Minute
|
UDPTimeout = 5 * time.Minute
|
||||||
DefaultStartTimeout = 10 * time.Second
|
DefaultURLTestInterval = 3 * time.Minute
|
||||||
DefaultStopTimeout = 5 * time.Second
|
DefaultURLTestIdleTimeout = 30 * time.Minute
|
||||||
DefaultStopFatalTimeout = 10 * time.Second
|
StartTimeout = 10 * time.Second
|
||||||
|
StopTimeout = 5 * time.Second
|
||||||
|
FatalStopTimeout = 10 * time.Second
|
||||||
|
FakeIPMetadataSaveInterval = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,10 +2,217 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 1.9.6
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
### 1.9.5
|
||||||
|
|
||||||
|
* Update quic-go to v0.47.0
|
||||||
|
* Fix direct dialer not resolving domain
|
||||||
|
* Fix no error return when empty DNS cache retrieved
|
||||||
|
* Fix build with go1.23
|
||||||
|
* Fix stream sniffer
|
||||||
|
* Fix bad redirect in clash-api
|
||||||
|
* Fix wireguard events chan leak
|
||||||
|
* Fix cached conn eats up read deadlines
|
||||||
|
* Fix disconnected interface selected as default in windows
|
||||||
|
* Update Bundle Identifiers for Apple platform clients **1**
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [Migration](/migration/#bundle-identifier-updates-in-apple-platform-clients).
|
||||||
|
|
||||||
|
We are still working on getting all sing-box apps back on the App Store.
|
||||||
|
|
||||||
|
This work is expected to be completed within a week
|
||||||
|
(SFI on the App Store and others on TestFlight are already available).
|
||||||
|
|
||||||
|
### 1.9.4
|
||||||
|
|
||||||
|
* Update quic-go to v0.46.0
|
||||||
|
* Update Hysteria2 BBR congestion control
|
||||||
|
* Filter HTTPS ipv4hint/ipv6hint with domain strategy
|
||||||
|
* Fix crash on Android when using process rules
|
||||||
|
* Fix non-IP queries accepted by address filter rules
|
||||||
|
* Fix UDP server for shadowsocks AEAD multi-user inbounds
|
||||||
|
* Fix default next protos for v2ray QUIC transport
|
||||||
|
* Fix default end value of port range configuration options
|
||||||
|
* Fix reset v2ray transports
|
||||||
|
* Fix panic caused by rule-set generation of duplicate keys for `domain_suffix`
|
||||||
|
* Fix UDP connnection leak when sniffing
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
_Due to problems with our Apple developer account,
|
||||||
|
sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
||||||
|
If your company or organization is willing to help us return to the App Store,
|
||||||
|
please [contact us](mailto:contact@sagernet.org)._
|
||||||
|
|
||||||
|
### 1.9.3
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
### 1.9.2
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
### 1.9.1
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
### 1.9.0
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
Important changes since 1.8:
|
||||||
|
|
||||||
|
* `domain_suffix` behavior update **1**
|
||||||
|
* `process_path` format update on Windows **2**
|
||||||
|
* Add address filter DNS rule items **3**
|
||||||
|
* Add support for `client-subnet` DNS options **4**
|
||||||
|
* Add rejected DNS response cache support **5**
|
||||||
|
* Add `bypass_domain` and `search_domain` platform HTTP proxy options **6**
|
||||||
|
* Fix missing `rule_set_ipcidr_match_source` item in DNS rules **7**
|
||||||
|
* Handle Windows power events
|
||||||
|
* Always disable cache for fake-ip DNS transport if `dns.independent_cache` disabled
|
||||||
|
* Improve DNS truncate behavior
|
||||||
|
* Update Hysteria protocol
|
||||||
|
* Update quic-go to v0.43.1
|
||||||
|
* Update gVisor to 20240422.0
|
||||||
|
* Mitigating TunnelVision attacks **8**
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [Migration](/migration/#domain_suffix-behavior-update).
|
||||||
|
|
||||||
|
**2**:
|
||||||
|
|
||||||
|
See [Migration](/migration/#process_path-format-update-on-windows).
|
||||||
|
|
||||||
|
**3**:
|
||||||
|
|
||||||
|
The new DNS feature allows you to more precisely bypass Chinese websites via **DNS leaks**. Do not use plain local DNS
|
||||||
|
if using this method.
|
||||||
|
|
||||||
|
See [Address Filter Fields](/configuration/dns/rule#address-filter-fields).
|
||||||
|
|
||||||
|
[Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) updated.
|
||||||
|
|
||||||
|
**4**:
|
||||||
|
|
||||||
|
See [DNS](/configuration/dns), [DNS Server](/configuration/dns/server) and [DNS Rules](/configuration/dns/rule).
|
||||||
|
|
||||||
|
Since this feature makes the scenario mentioned in `alpha.1` no longer leak DNS requests,
|
||||||
|
the [Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) has been updated.
|
||||||
|
|
||||||
|
**5**:
|
||||||
|
|
||||||
|
The new feature allows you to cache the check results of
|
||||||
|
[Address filter DNS rule items](/configuration/dns/rule/#address-filter-fields) until expiration.
|
||||||
|
|
||||||
|
**6**:
|
||||||
|
|
||||||
|
See [TUN](/configuration/inbound/tun) inbound.
|
||||||
|
|
||||||
|
**7**:
|
||||||
|
|
||||||
|
See [DNS Rule](/configuration/dns/rule/).
|
||||||
|
|
||||||
|
**8**:
|
||||||
|
|
||||||
|
See [TunnelVision](/manual/misc/tunnelvision).
|
||||||
|
|
||||||
|
#### 1.9.0-rc.22
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-rc.20
|
||||||
|
|
||||||
|
* Prioritize `*_route_address` in linux auto-route
|
||||||
|
* Fix `*_route_address` in darwin auto-route
|
||||||
|
|
||||||
|
#### 1.8.14
|
||||||
|
|
||||||
|
* Fix hysteria2 panic
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-rc.18
|
||||||
|
|
||||||
|
* Add custom prefix support in EDNS0 client subnet options
|
||||||
|
* Fix hysteria2 crash
|
||||||
|
* Fix `store_rdrc` corrupted
|
||||||
|
* Update quic-go to v0.43.1
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-rc.16
|
||||||
|
|
||||||
|
* Mitigating TunnelVision attacks **1**
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [TunnelVision](/manual/misc/tunnelvision).
|
||||||
|
|
||||||
|
#### 1.9.0-rc.15
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.8.13
|
||||||
|
|
||||||
|
* Fix fake-ip mapping
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-rc.14
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-rc.13
|
||||||
|
|
||||||
|
* Update Hysteria protocol
|
||||||
|
* Update quic-go to v0.43.0
|
||||||
|
* Update gVisor to 20240422.0
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.8.12
|
||||||
|
|
||||||
|
* Now we have official APT and DNF repositories **1**
|
||||||
|
* Fix packet MTU for QUIC protocols
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
Including stable and beta versions, see https://sing-box.sagernet.org/installation/package-manager/
|
||||||
|
|
||||||
|
#### 1.9.0-rc.11
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.8.11
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.8.10
|
#### 1.8.10
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-beta.17
|
||||||
|
|
||||||
|
* Update `quic-go` to v0.42.0
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-beta.16
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
_Our Testflight distribution has been temporarily blocked by Apple (possibly due to too many beta versions)
|
||||||
|
and you cannot join the test, install or update the sing-box beta app right now.
|
||||||
|
Please wait patiently for processing._
|
||||||
|
|
||||||
|
#### 1.9.0-beta.14
|
||||||
|
|
||||||
|
* Update gVisor to 20240212.0-65-g71212d503
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.8.9
|
#### 1.8.9
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
@@ -14,14 +221,125 @@ icon: material/alert-decagram
|
|||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-beta.7
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-beta.6
|
||||||
|
|
||||||
|
* Fix address filter DNS rule items **1**
|
||||||
|
* Fix DNS outbound responding with wrong data
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
Fixed an issue where address filter DNS rule was incorrectly rejected under certain circumstances.
|
||||||
|
If you have enabled `store_rdrc` to save results, consider clearing the cache file.
|
||||||
|
|
||||||
#### 1.8.7
|
#### 1.8.7
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.15
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.14
|
||||||
|
|
||||||
|
* Improve DNS truncate behavior
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.13
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.8.6
|
#### 1.8.6
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.12
|
||||||
|
|
||||||
|
* Handle Windows power events
|
||||||
|
* Always disable cache for fake-ip DNS transport if `dns.independent_cache` disabled
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.11
|
||||||
|
|
||||||
|
* Fix missing `rule_set_ipcidr_match_source` item in DNS rules **1**
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [DNS Rule](/configuration/dns/rule/).
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.10
|
||||||
|
|
||||||
|
* Add `bypass_domain` and `search_domain` platform HTTP proxy options **1**
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [TUN](/configuration/inbound/tun) inbound.
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.8
|
||||||
|
|
||||||
|
* Add rejected DNS response cache support **1**
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
The new feature allows you to cache the check results of
|
||||||
|
[Address filter DNS rule items](/configuration/dns/rule/#address-filter-fields) until expiration.
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.7
|
||||||
|
|
||||||
|
* Update gVisor to 20240206.0
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.6
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.3
|
||||||
|
|
||||||
|
* Update `quic-go` to v0.41.0
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.2
|
||||||
|
|
||||||
|
* Add support for `client-subnet` DNS options **1**
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [DNS](/configuration/dns), [DNS Server](/configuration/dns/server) and [DNS Rules](/configuration/dns/rule).
|
||||||
|
|
||||||
|
Since this feature makes the scenario mentioned in `alpha.1` no longer leak DNS requests,
|
||||||
|
the [Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) has been updated.
|
||||||
|
|
||||||
|
#### 1.9.0-alpha.1
|
||||||
|
|
||||||
|
* `domain_suffix` behavior update **1**
|
||||||
|
* `process_path` format update on Windows **2**
|
||||||
|
* Add address filter DNS rule items **3**
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [Migration](/migration/#domain_suffix-behavior-update).
|
||||||
|
|
||||||
|
**2**:
|
||||||
|
|
||||||
|
See [Migration](/migration/#process_path-format-update-on-windows).
|
||||||
|
|
||||||
|
**3**:
|
||||||
|
|
||||||
|
The new DNS feature allows you to more precisely bypass Chinese websites via **DNS leaks**. Do not use plain local DNS
|
||||||
|
if using this method.
|
||||||
|
|
||||||
|
See [Address Filter Fields](/configuration/dns/rule#address-filter-fields).
|
||||||
|
|
||||||
|
[Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) updated.
|
||||||
|
|
||||||
#### 1.8.5
|
#### 1.8.5
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
@@ -38,7 +356,7 @@ icon: material/alert-decagram
|
|||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.8.0
|
### 1.8.0
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
@@ -329,7 +647,7 @@ New commands manage GeoIP, Geosite and rule set resources, and help you migrate
|
|||||||
|
|
||||||
Logical rules in route rules, DNS rules, and the new headless rule now allow nesting of logical rules.
|
Logical rules in route rules, DNS rules, and the new headless rule now allow nesting of logical rules.
|
||||||
|
|
||||||
#### 1.7.0
|
### 1.7.0
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
@@ -371,7 +689,7 @@ see [TCP Brutal](/configuration/shared/tcp-brutal/) for details.
|
|||||||
|
|
||||||
**5**:
|
**5**:
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
#### 1.7.0-rc.3
|
#### 1.7.0-rc.3
|
||||||
|
|
||||||
@@ -408,7 +726,7 @@ Only supported in graphical clients on Android and iOS.
|
|||||||
|
|
||||||
**1**:
|
**1**:
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
#### 1.7.0-beta.3
|
#### 1.7.0-beta.3
|
||||||
|
|
||||||
@@ -489,7 +807,7 @@ Introduced in V2Ray 5.10.0.
|
|||||||
|
|
||||||
The new HTTPUpgrade transport has better performance than WebSocket and is better suited for CDN abuse.
|
The new HTTPUpgrade transport has better performance than WebSocket and is better suited for CDN abuse.
|
||||||
|
|
||||||
#### 1.6.0
|
### 1.6.0
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
@@ -668,7 +986,7 @@ introduce new issues.
|
|||||||
None of the existing Golang BBR congestion control implementations have been reviewed or unit tested.
|
None of the existing Golang BBR congestion control implementations have been reviewed or unit tested.
|
||||||
This update is intended to address the multi-send defects of the old implementation and may introduce new issues.
|
This update is intended to address the multi-send defects of the old implementation and may introduce new issues.
|
||||||
|
|
||||||
#### 1.5.0
|
### 1.5.0
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
@@ -862,7 +1180,7 @@ All inbounds and outbounds are supported, including `Naiveproxy`, `Hysteria`, `T
|
|||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.4.0
|
### 1.4.0
|
||||||
|
|
||||||
* Fix bugs and update dependencies
|
* Fix bugs and update dependencies
|
||||||
|
|
||||||
@@ -1004,7 +1322,7 @@ The old testflight link and app are no longer valid.
|
|||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.3.0
|
### 1.3.0
|
||||||
|
|
||||||
* Fix bugs and update dependencies
|
* Fix bugs and update dependencies
|
||||||
|
|
||||||
@@ -1196,7 +1514,7 @@ to `domain` rule.
|
|||||||
* Flush DNS cache for macOS when tun start/close
|
* Flush DNS cache for macOS when tun start/close
|
||||||
* Fix tun's DNS hijacking compatibility with systemd-resolved
|
* Fix tun's DNS hijacking compatibility with systemd-resolved
|
||||||
|
|
||||||
#### 1.2.0
|
### 1.2.0
|
||||||
|
|
||||||
* Fix bugs and update dependencies
|
* Fix bugs and update dependencies
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,13 @@ platform-specific function implementation, such as TUN transparent proxy impleme
|
|||||||
|
|
||||||
## :material-download: Download
|
## :material-download: Download
|
||||||
|
|
||||||
* [App Store](https://apps.apple.com/us/app/sing-box/id6451272673)
|
* [App Store](https://apps.apple.com/app/sing-box-vt/id6673731168)
|
||||||
* [TestFlight (Beta)](https://testflight.apple.com/join/AcqO44FH)
|
* TestFlight (Beta)
|
||||||
|
|
||||||
|
TestFlight quota is only available to [sponsors](https://github.com/sponsors/nekohasekai)
|
||||||
|
(one-time sponsorships are accepted).
|
||||||
|
Once you donate, you can get an invitation by join our Telegram group for sponsors from [@yet_another_sponsor_bot](https://t.me/yet_another_sponsor_bot)
|
||||||
|
or sending us your Apple ID [via email](mailto:contact@sagernet.org).
|
||||||
|
|
||||||
## :material-file-download: Download (macOS standalone version)
|
## :material-file-download: Download (macOS standalone version)
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
由 Project S 维护,提供统一的体验与平台特定的功能。
|
由 Project S 维护,提供统一的体验与平台特定的功能。
|
||||||
|
|
||||||
| 平台 | 客户端 |
|
| 平台 | 客户端 |
|
||||||
|---------------------------------------|-----------------------------------------|
|
|---------------------------------------|------------------------------------------|
|
||||||
| :material-android: Android | [sing-box for Android](./android/) |
|
| :material-android: Android | [sing-box for Android](./android/) |
|
||||||
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
|
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
|
||||||
| :material-laptop: Desktop | 施工中 |
|
| :material-laptop: Desktop | 施工中 |
|
||||||
|
|
||||||
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
|
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
|
||||||
VPN 客户端功能, 但代码质量很差且包含广告。
|
VPN 客户端功能, 但代码质量很差且包含广告。
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.9.0"
|
||||||
|
|
||||||
|
:material-plus: [client_subnet](#client_subnet)
|
||||||
|
|
||||||
# DNS
|
# DNS
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
@@ -13,6 +21,7 @@
|
|||||||
"disable_expire": false,
|
"disable_expire": false,
|
||||||
"independent_cache": false,
|
"independent_cache": false,
|
||||||
"reverse_mapping": false,
|
"reverse_mapping": false,
|
||||||
|
"client_subnet": "",
|
||||||
"fakeip": {}
|
"fakeip": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,8 +30,8 @@
|
|||||||
|
|
||||||
### Fields
|
### Fields
|
||||||
|
|
||||||
| Key | Format |
|
| Key | Format |
|
||||||
|----------|--------------------------------|
|
|----------|---------------------------------|
|
||||||
| `server` | List of [DNS Server](./server/) |
|
| `server` | List of [DNS Server](./server/) |
|
||||||
| `rules` | List of [DNS Rule](./rule/) |
|
| `rules` | List of [DNS Rule](./rule/) |
|
||||||
| `fakeip` | [FakeIP](./fakeip/) |
|
| `fakeip` | [FakeIP](./fakeip/) |
|
||||||
@@ -60,6 +69,12 @@ Stores a reverse mapping of IP addresses after responding to a DNS query in orde
|
|||||||
Since this process relies on the act of resolving domain names by an application before making a request, it can be
|
Since this process relies on the act of resolving domain names by an application before making a request, it can be
|
||||||
problematic in environments such as macOS, where DNS is proxied and cached by the system.
|
problematic in environments such as macOS, where DNS is proxied and cached by the system.
|
||||||
|
|
||||||
#### fakeip
|
#### client_subnet
|
||||||
|
|
||||||
[FakeIP](./fakeip/) settings.
|
!!! question "Since sing-box 1.9.0"
|
||||||
|
|
||||||
|
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||||
|
|
||||||
|
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||||
|
|
||||||
|
Can be overrides by `servers.[].client_subnet` or `rules.[].client_subnet`.
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.9.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: [client_subnet](#client_subnet)
|
||||||
|
|
||||||
# DNS
|
# DNS
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
@@ -13,6 +21,7 @@
|
|||||||
"disable_expire": false,
|
"disable_expire": false,
|
||||||
"independent_cache": false,
|
"independent_cache": false,
|
||||||
"reverse_mapping": false,
|
"reverse_mapping": false,
|
||||||
|
"client_subnet": "",
|
||||||
"fakeip": {}
|
"fakeip": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,6 +67,16 @@
|
|||||||
|
|
||||||
由于此过程依赖于应用程序在发出请求之前解析域名的行为,因此在 macOS 等 DNS 由系统代理和缓存的环境中可能会出现问题。
|
由于此过程依赖于应用程序在发出请求之前解析域名的行为,因此在 macOS 等 DNS 由系统代理和缓存的环境中可能会出现问题。
|
||||||
|
|
||||||
|
#### client_subnet
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.9.0 起"
|
||||||
|
|
||||||
|
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||||
|
|
||||||
|
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||||
|
|
||||||
|
可以被 `servers.[].client_subnet` 或 `rules.[].client_subnet` 覆盖。
|
||||||
|
|
||||||
#### fakeip
|
#### fakeip
|
||||||
|
|
||||||
[FakeIP](./fakeip/) 设置。
|
[FakeIP](./fakeip/) 设置。
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
---
|
---
|
||||||
icon: material/alert-decagram
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.9.0"
|
||||||
|
|
||||||
|
:material-plus: [geoip](#geoip)
|
||||||
|
:material-plus: [ip_cidr](#ip_cidr)
|
||||||
|
:material-plus: [ip_is_private](#ip_is_private)
|
||||||
|
:material-plus: [client_subnet](#client_subnet)
|
||||||
|
:material-plus: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|
||||||
:material-plus: [rule_set](#rule_set)
|
:material-plus: [rule_set](#rule_set)
|
||||||
@@ -53,11 +61,19 @@ icon: material/alert-decagram
|
|||||||
"source_geoip": [
|
"source_geoip": [
|
||||||
"private"
|
"private"
|
||||||
],
|
],
|
||||||
|
"geoip": [
|
||||||
|
"cn"
|
||||||
|
],
|
||||||
"source_ip_cidr": [
|
"source_ip_cidr": [
|
||||||
"10.0.0.0/24",
|
"10.0.0.0/24",
|
||||||
"192.168.0.1"
|
"192.168.0.1"
|
||||||
],
|
],
|
||||||
"source_ip_is_private": false,
|
"source_ip_is_private": false,
|
||||||
|
"ip_cidr": [
|
||||||
|
"10.0.0.0/24",
|
||||||
|
"192.168.0.1"
|
||||||
|
],
|
||||||
|
"ip_is_private": false,
|
||||||
"source_port": [
|
"source_port": [
|
||||||
12345
|
12345
|
||||||
],
|
],
|
||||||
@@ -101,13 +117,15 @@ icon: material/alert-decagram
|
|||||||
"geoip-cn",
|
"geoip-cn",
|
||||||
"geosite-cn"
|
"geosite-cn"
|
||||||
],
|
],
|
||||||
|
"rule_set_ipcidr_match_source": false,
|
||||||
"invert": false,
|
"invert": false,
|
||||||
"outbound": [
|
"outbound": [
|
||||||
"direct"
|
"direct"
|
||||||
],
|
],
|
||||||
"server": "local",
|
"server": "local",
|
||||||
"disable_cache": false,
|
"disable_cache": false,
|
||||||
"rewrite_ttl": 100
|
"rewrite_ttl": 100,
|
||||||
|
"client_subnet": "127.0.0.1/24"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "logical",
|
"type": "logical",
|
||||||
@@ -115,7 +133,8 @@ icon: material/alert-decagram
|
|||||||
"rules": [],
|
"rules": [],
|
||||||
"server": "local",
|
"server": "local",
|
||||||
"disable_cache": false,
|
"disable_cache": false,
|
||||||
"rewrite_ttl": 100
|
"rewrite_ttl": 100,
|
||||||
|
"client_subnet": "127.0.0.1/24"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -266,11 +285,9 @@ Match Clash mode.
|
|||||||
|
|
||||||
#### wifi_ssid
|
#### wifi_ssid
|
||||||
|
|
||||||
<!-- md:version 1.7.0-beta.4 -->
|
|
||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
Match WiFi SSID.
|
Match WiFi SSID.
|
||||||
|
|
||||||
@@ -278,7 +295,7 @@ Match WiFi SSID.
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
Match WiFi BSSID.
|
Match WiFi BSSID.
|
||||||
|
|
||||||
@@ -288,6 +305,12 @@ Match WiFi BSSID.
|
|||||||
|
|
||||||
Match [Rule Set](/configuration/route/#rule_set).
|
Match [Rule Set](/configuration/route/#rule_set).
|
||||||
|
|
||||||
|
#### rule_set_ipcidr_match_source
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.9.0"
|
||||||
|
|
||||||
|
Make `ipcidr` in rule sets match the source IP.
|
||||||
|
|
||||||
#### invert
|
#### invert
|
||||||
|
|
||||||
Invert match result.
|
Invert match result.
|
||||||
@@ -312,6 +335,46 @@ Disable cache and save cache in this query.
|
|||||||
|
|
||||||
Rewrite TTL in DNS responses.
|
Rewrite TTL in DNS responses.
|
||||||
|
|
||||||
|
#### client_subnet
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.9.0"
|
||||||
|
|
||||||
|
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||||
|
|
||||||
|
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||||
|
|
||||||
|
Will overrides `dns.client_subnet` and `servers.[].client_subnet`.
|
||||||
|
|
||||||
|
### Address Filter Fields
|
||||||
|
|
||||||
|
Only takes effect for IP address requests. When the query results do not match the address filtering rule items, the current rule will be skipped.
|
||||||
|
|
||||||
|
!!! info ""
|
||||||
|
|
||||||
|
`ip_cidr` items in included rule sets also takes effect as an address filtering field.
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
Enable `experimental.cache_file.store_rdrc` to cache results.
|
||||||
|
|
||||||
|
#### geoip
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.9.0"
|
||||||
|
|
||||||
|
Match GeoIP with query response.
|
||||||
|
|
||||||
|
#### ip_cidr
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.9.0"
|
||||||
|
|
||||||
|
Match IP CIDR with query response.
|
||||||
|
|
||||||
|
#### ip_is_private
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.9.0"
|
||||||
|
|
||||||
|
Match private IP with query response.
|
||||||
|
|
||||||
### Logical Fields
|
### Logical Fields
|
||||||
|
|
||||||
#### type
|
#### type
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
---
|
---
|
||||||
icon: material/alert-decagram
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.9.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: [geoip](#geoip)
|
||||||
|
:material-plus: [ip_cidr](#ip_cidr)
|
||||||
|
:material-plus: [ip_is_private](#ip_is_private)
|
||||||
|
:material-plus: [client_subnet](#client_subnet)
|
||||||
|
:material-plus: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [rule_set](#rule_set)
|
:material-plus: [rule_set](#rule_set)
|
||||||
@@ -53,10 +61,19 @@ icon: material/alert-decagram
|
|||||||
"source_geoip": [
|
"source_geoip": [
|
||||||
"private"
|
"private"
|
||||||
],
|
],
|
||||||
|
"geoip": [
|
||||||
|
"cn"
|
||||||
|
],
|
||||||
"source_ip_cidr": [
|
"source_ip_cidr": [
|
||||||
"10.0.0.0/24"
|
"10.0.0.0/24",
|
||||||
|
"192.168.0.1"
|
||||||
],
|
],
|
||||||
"source_ip_is_private": false,
|
"source_ip_is_private": false,
|
||||||
|
"ip_cidr": [
|
||||||
|
"10.0.0.0/24",
|
||||||
|
"192.168.0.1"
|
||||||
|
],
|
||||||
|
"ip_is_private": false,
|
||||||
"source_port": [
|
"source_port": [
|
||||||
12345
|
12345
|
||||||
],
|
],
|
||||||
@@ -100,19 +117,22 @@ icon: material/alert-decagram
|
|||||||
"geoip-cn",
|
"geoip-cn",
|
||||||
"geosite-cn"
|
"geosite-cn"
|
||||||
],
|
],
|
||||||
|
"rule_set_ipcidr_match_source": false,
|
||||||
"invert": false,
|
"invert": false,
|
||||||
"outbound": [
|
"outbound": [
|
||||||
"direct"
|
"direct"
|
||||||
],
|
],
|
||||||
"server": "local",
|
"server": "local",
|
||||||
"disable_cache": false
|
"disable_cache": false,
|
||||||
|
"client_subnet": "127.0.0.1/24"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "logical",
|
"type": "logical",
|
||||||
"mode": "and",
|
"mode": "and",
|
||||||
"rules": [],
|
"rules": [],
|
||||||
"server": "local",
|
"server": "local",
|
||||||
"disable_cache": false
|
"disable_cache": false,
|
||||||
|
"client_subnet": "127.0.0.1/24"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -265,7 +285,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
仅在 Android 与 iOS 的图形客户端中支持。
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
匹配 WiFi SSID。
|
匹配 WiFi SSID。
|
||||||
|
|
||||||
@@ -273,7 +293,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
仅在 Android 与 iOS 的图形客户端中支持。
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
匹配 WiFi BSSID。
|
匹配 WiFi BSSID。
|
||||||
|
|
||||||
@@ -283,6 +303,12 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
|||||||
|
|
||||||
匹配[规则集](/zh/configuration/route/#rule_set)。
|
匹配[规则集](/zh/configuration/route/#rule_set)。
|
||||||
|
|
||||||
|
#### rule_set_ipcidr_match_source
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.9.0 起"
|
||||||
|
|
||||||
|
使规则集中的 `ipcidr` 规则匹配源 IP。
|
||||||
|
|
||||||
#### invert
|
#### invert
|
||||||
|
|
||||||
反选匹配结果。
|
反选匹配结果。
|
||||||
@@ -307,6 +333,46 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
|||||||
|
|
||||||
重写 DNS 回应中的 TTL。
|
重写 DNS 回应中的 TTL。
|
||||||
|
|
||||||
|
#### client_subnet
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.9.0 起"
|
||||||
|
|
||||||
|
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||||
|
|
||||||
|
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||||
|
|
||||||
|
将覆盖 `dns.client_subnet` 与 `servers.[].client_subnet`。
|
||||||
|
|
||||||
|
### 地址筛选字段
|
||||||
|
|
||||||
|
仅对IP地址请求生效。 当查询结果与地址筛选规则项不匹配时,将跳过当前规则。
|
||||||
|
|
||||||
|
!!! info ""
|
||||||
|
|
||||||
|
引用的规则集中的 `ip_cidr` 项也作为地址筛选字段生效。
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
启用 `experimental.cache_file.store_rdrc` 以缓存结果。
|
||||||
|
|
||||||
|
#### geoip
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.9.0 起"
|
||||||
|
|
||||||
|
与查询响应匹配 GeoIP。
|
||||||
|
|
||||||
|
#### ip_cidr
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.9.0 起"
|
||||||
|
|
||||||
|
与查询相应匹配 IP CIDR。
|
||||||
|
|
||||||
|
#### ip_is_private
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.9.0 起"
|
||||||
|
|
||||||
|
与查询响应匹配非公开 IP。
|
||||||
|
|
||||||
### 逻辑字段
|
### 逻辑字段
|
||||||
|
|
||||||
#### type
|
#### type
|
||||||
@@ -319,4 +385,4 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
|||||||
|
|
||||||
#### rules
|
#### rules
|
||||||
|
|
||||||
包括的规则。
|
包括的规则。
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.9.0"
|
||||||
|
|
||||||
|
:material-plus: [client_subnet](#client_subnet)
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -5,17 +13,17 @@
|
|||||||
"dns": {
|
"dns": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"tag": "google",
|
"tag": "",
|
||||||
"address": "tls://dns.google",
|
"address": "",
|
||||||
"address_resolver": "local",
|
"address_resolver": "",
|
||||||
"address_strategy": "prefer_ipv4",
|
"address_strategy": "",
|
||||||
"strategy": "ipv4_only",
|
"strategy": "",
|
||||||
"detour": "direct"
|
"detour": "",
|
||||||
|
"client_subnet": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fields
|
### Fields
|
||||||
@@ -80,10 +88,22 @@ Default domain strategy for resolving the domain names.
|
|||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
||||||
|
|
||||||
Take no effect if override by other settings.
|
Take no effect if overridden by other settings.
|
||||||
|
|
||||||
#### detour
|
#### detour
|
||||||
|
|
||||||
Tag of an outbound for connecting to the dns server.
|
Tag of an outbound for connecting to the dns server.
|
||||||
|
|
||||||
Default outbound will be used if empty.
|
Default outbound will be used if empty.
|
||||||
|
|
||||||
|
#### client_subnet
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.9.0"
|
||||||
|
|
||||||
|
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||||
|
|
||||||
|
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||||
|
|
||||||
|
Can be overrides by `rules.[].client_subnet`.
|
||||||
|
|
||||||
|
Will overrides `dns.client_subnet`.
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.9.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: [client_subnet](#client_subnet)
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -5,17 +13,17 @@
|
|||||||
"dns": {
|
"dns": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"tag": "google",
|
"tag": "",
|
||||||
"address": "tls://dns.google",
|
"address": "",
|
||||||
"address_resolver": "local",
|
"address_resolver": "",
|
||||||
"address_strategy": "prefer_ipv4",
|
"address_strategy": "",
|
||||||
"strategy": "ipv4_only",
|
"strategy": "",
|
||||||
"detour": "direct"
|
"detour": "",
|
||||||
|
"client_subnet": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 字段
|
### 字段
|
||||||
@@ -87,3 +95,15 @@ DNS 服务器的地址。
|
|||||||
用于连接到 DNS 服务器的出站的标签。
|
用于连接到 DNS 服务器的出站的标签。
|
||||||
|
|
||||||
如果为空,将使用默认出站。
|
如果为空,将使用默认出站。
|
||||||
|
|
||||||
|
#### client_subnet
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.9.0 起"
|
||||||
|
|
||||||
|
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||||
|
|
||||||
|
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||||
|
|
||||||
|
可以被 `rules.[].client_subnet` 覆盖。
|
||||||
|
|
||||||
|
将覆盖 `dns.client_subnet`。
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ icon: material/new-box
|
|||||||
|
|
||||||
!!! question "Since sing-box 1.8.0"
|
!!! question "Since sing-box 1.8.0"
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.9.0"
|
||||||
|
|
||||||
|
:material-plus: [store_rdrc](#store_rdrc)
|
||||||
|
:material-plus: [rdrc_timeout](#rdrc_timeout)
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -11,7 +16,9 @@ icon: material/new-box
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"path": "",
|
"path": "",
|
||||||
"cache_id": "",
|
"cache_id": "",
|
||||||
"store_fakeip": false
|
"store_fakeip": false,
|
||||||
|
"store_rdrc": false,
|
||||||
|
"rdrc_timeout": ""
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -29,6 +36,23 @@ Path to the cache file.
|
|||||||
|
|
||||||
#### cache_id
|
#### cache_id
|
||||||
|
|
||||||
Identifier in cache file.
|
Identifier in the cache file
|
||||||
|
|
||||||
If not empty, configuration specified data will use a separate store keyed by it.
|
If not empty, configuration specified data will use a separate store keyed by it.
|
||||||
|
|
||||||
|
#### store_fakeip
|
||||||
|
|
||||||
|
Store fakeip in the cache file
|
||||||
|
|
||||||
|
#### store_rdrc
|
||||||
|
|
||||||
|
Store rejected DNS response cache in the cache file
|
||||||
|
|
||||||
|
The check results of [Address filter DNS rule items](/configuration/dns/rule/#address-filter-fields)
|
||||||
|
will be cached until expiration.
|
||||||
|
|
||||||
|
#### rdrc_timeout
|
||||||
|
|
||||||
|
Timeout of rejected DNS response cache.
|
||||||
|
|
||||||
|
`7d` is used by default.
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ icon: material/new-box
|
|||||||
|
|
||||||
!!! question "自 sing-box 1.8.0 起"
|
!!! question "自 sing-box 1.8.0 起"
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.9.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: [store_rdrc](#store_rdrc)
|
||||||
|
:material-plus: [rdrc_timeout](#rdrc_timeout)
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -11,7 +16,9 @@ icon: material/new-box
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"path": "",
|
"path": "",
|
||||||
"cache_id": "",
|
"cache_id": "",
|
||||||
"store_fakeip": false
|
"store_fakeip": false,
|
||||||
|
"store_rdrc": false,
|
||||||
|
"rdrc_timeout": ""
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -30,3 +37,19 @@ icon: material/new-box
|
|||||||
缓存文件中的标识符。
|
缓存文件中的标识符。
|
||||||
|
|
||||||
如果不为空,配置特定的数据将使用由其键控的单独存储。
|
如果不为空,配置特定的数据将使用由其键控的单独存储。
|
||||||
|
|
||||||
|
#### store_fakeip
|
||||||
|
|
||||||
|
将 fakeip 存储在缓存文件中。
|
||||||
|
|
||||||
|
#### store_rdrc
|
||||||
|
|
||||||
|
将拒绝的 DNS 响应缓存存储在缓存文件中。
|
||||||
|
|
||||||
|
[地址筛选 DNS 规则项](/zh/configuration/dns/rule/#_3) 的检查结果将被缓存至过期。
|
||||||
|
|
||||||
|
#### rdrc_timeout
|
||||||
|
|
||||||
|
拒绝的 DNS 响应缓存超时。
|
||||||
|
|
||||||
|
默认使用 `7d`。
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|
||||||
:material-delete-alert: [store_mode](#store_mode)
|
:material-delete-alert: [store_mode](#store_mode)
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|
||||||
:material-delete-alert: [store_mode](#store_mode)
|
:material-delete-alert: [store_mode](#store_mode)
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
# Experimental
|
# Experimental
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
# 实验性
|
# 实验性
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|||||||
@@ -42,6 +42,6 @@ No authentication required if empty.
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
To work on Android and iOS without privileges, use tun.platform.http_proxy instead.
|
To work on Android and Apple platforms without privileges, use tun.platform.http_proxy instead.
|
||||||
|
|
||||||
Automatically set system proxy configuration when start and clean up when stop.
|
Automatically set system proxy configuration when start and clean up when stop.
|
||||||
|
|||||||
@@ -15,24 +15,24 @@
|
|||||||
|
|
||||||
### Fields
|
### Fields
|
||||||
|
|
||||||
| Type | Format | Injectable |
|
| Type | Format | Injectable |
|
||||||
|---------------|-------------------------------|------------|
|
|---------------|-------------------------------|------------------|
|
||||||
| `direct` | [Direct](./direct/) | X |
|
| `direct` | [Direct](./direct/) | :material-close: |
|
||||||
| `mixed` | [Mixed](./mixed/) | TCP |
|
| `mixed` | [Mixed](./mixed/) | TCP |
|
||||||
| `socks` | [SOCKS](./socks/) | TCP |
|
| `socks` | [SOCKS](./socks/) | TCP |
|
||||||
| `http` | [HTTP](./http/) | TCP |
|
| `http` | [HTTP](./http/) | TCP |
|
||||||
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
||||||
| `vmess` | [VMess](./vmess/) | TCP |
|
| `vmess` | [VMess](./vmess/) | TCP |
|
||||||
| `trojan` | [Trojan](./trojan/) | TCP |
|
| `trojan` | [Trojan](./trojan/) | TCP |
|
||||||
| `naive` | [Naive](./naive/) | X |
|
| `naive` | [Naive](./naive/) | :material-close: |
|
||||||
| `hysteria` | [Hysteria](./hysteria/) | X |
|
| `hysteria` | [Hysteria](./hysteria/) | :material-close: |
|
||||||
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
||||||
| `tuic` | [TUIC](./tuic/) | X |
|
| `tuic` | [TUIC](./tuic/) | :material-close: |
|
||||||
| `hysteria2` | [Hysteria2](./hysteria2/) | X |
|
| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: |
|
||||||
| `vless` | [VLESS](./vless/) | TCP |
|
| `vless` | [VLESS](./vless/) | TCP |
|
||||||
| `tun` | [Tun](./tun/) | X |
|
| `tun` | [Tun](./tun/) | :material-close: |
|
||||||
| `redirect` | [Redirect](./redirect/) | X |
|
| `redirect` | [Redirect](./redirect/) | :material-close: |
|
||||||
| `tproxy` | [TProxy](./tproxy/) | X |
|
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
|
||||||
|
|
||||||
#### tag
|
#### tag
|
||||||
|
|
||||||
|
|||||||
@@ -15,24 +15,24 @@
|
|||||||
|
|
||||||
### 字段
|
### 字段
|
||||||
|
|
||||||
| 类型 | 格式 | 注入支持 |
|
| 类型 | 格式 | 注入支持 |
|
||||||
|---------------|------------------------------|------|
|
|---------------|-------------------------------|------------------|
|
||||||
| `direct` | [Direct](./direct/) | X |
|
| `direct` | [Direct](./direct/) | :material-close: |
|
||||||
| `mixed` | [Mixed](./mixed/) | TCP |
|
| `mixed` | [Mixed](./mixed/) | TCP |
|
||||||
| `socks` | [SOCKS](./socks/) | TCP |
|
| `socks` | [SOCKS](./socks/) | TCP |
|
||||||
| `http` | [HTTP](./http/) | TCP |
|
| `http` | [HTTP](./http/) | TCP |
|
||||||
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
||||||
| `vmess` | [VMess](./vmess/) | TCP |
|
| `vmess` | [VMess](./vmess/) | TCP |
|
||||||
| `trojan` | [Trojan](./trojan/) | TCP |
|
| `trojan` | [Trojan](./trojan/) | TCP |
|
||||||
| `naive` | [Naive](./naive/) | X |
|
| `naive` | [Naive](./naive/) | :material-close: |
|
||||||
| `hysteria` | [Hysteria](./hysteria/) | X |
|
| `hysteria` | [Hysteria](./hysteria/) | :material-close: |
|
||||||
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
||||||
| `tuic` | [TUIC](./tuic/) | X |
|
| `tuic` | [TUIC](./tuic/) | :material-close: |
|
||||||
| `hysteria2` | [Hysteria2](./hysteria2/) | X |
|
| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: |
|
||||||
| `vless` | [VLESS](./vless/) | TCP |
|
| `vless` | [VLESS](./vless/) | TCP |
|
||||||
| `tun` | [Tun](./tun/) | X |
|
| `tun` | [Tun](./tun/) | :material-close: |
|
||||||
| `redirect` | [Redirect](./redirect/) | X |
|
| `redirect` | [Redirect](./redirect/) | :material-close: |
|
||||||
| `tproxy` | [TProxy](./tproxy/) | X |
|
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
|
||||||
|
|
||||||
#### tag
|
#### tag
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,6 @@ No authentication required if empty.
|
|||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
To work on Android and iOS without privileges, use tun.platform.http_proxy instead.
|
To work on Android and Apple platforms without privileges, use tun.platform.http_proxy instead.
|
||||||
|
|
||||||
Automatically set system proxy configuration when start and clean up when stop.
|
Automatically set system proxy configuration when start and clean up when stop.
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
---
|
---
|
||||||
icon: material/alert-decagram
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.9.0"
|
||||||
|
|
||||||
|
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
|
||||||
|
:material-plus: [platform.http_proxy.match_domain](#platformhttp_proxymatch_domain)
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|
||||||
:material-plus: [gso](#gso)
|
:material-plus: [gso](#gso)
|
||||||
@@ -73,7 +78,9 @@ icon: material/alert-decagram
|
|||||||
"http_proxy": {
|
"http_proxy": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.1",
|
||||||
"server_port": 8080
|
"server_port": 8080,
|
||||||
|
"bypass_domain": [],
|
||||||
|
"match_domain": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -140,7 +147,7 @@ Enforce strict routing rules when `auto_route` is enabled:
|
|||||||
* Let unsupported network unreachable
|
* Let unsupported network unreachable
|
||||||
* Route all connections to tun
|
* Route all connections to tun
|
||||||
|
|
||||||
It prevents address leaks and makes DNS hijacking work on Android, but your device will not be accessible by others.
|
It prevents address leaks and makes DNS hijacking work on Android.
|
||||||
|
|
||||||
*In Windows*:
|
*In Windows*:
|
||||||
|
|
||||||
@@ -260,6 +267,38 @@ Platform-specific settings, provided by client applications.
|
|||||||
|
|
||||||
System HTTP proxy settings.
|
System HTTP proxy settings.
|
||||||
|
|
||||||
|
#### platform.http_proxy.enabled
|
||||||
|
|
||||||
|
Enable system HTTP proxy.
|
||||||
|
|
||||||
|
#### platform.http_proxy.server
|
||||||
|
|
||||||
|
==Required==
|
||||||
|
|
||||||
|
HTTP proxy server address.
|
||||||
|
|
||||||
|
#### platform.http_proxy.server_port
|
||||||
|
|
||||||
|
==Required==
|
||||||
|
|
||||||
|
HTTP proxy server port.
|
||||||
|
|
||||||
|
#### platform.http_proxy.bypass_domain
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
On Apple platforms, `bypass_domain` items matches hostname **suffixes**.
|
||||||
|
|
||||||
|
Hostnames that bypass the HTTP proxy.
|
||||||
|
|
||||||
|
#### platform.http_proxy.match_domain
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Apple platforms.
|
||||||
|
|
||||||
|
Hostnames that use the HTTP proxy.
|
||||||
|
|
||||||
### Listen Fields
|
### Listen Fields
|
||||||
|
|
||||||
See [Listen Fields](/configuration/shared/listen/) for details.
|
See [Listen Fields](/configuration/shared/listen/) for details.
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
---
|
---
|
||||||
icon: material/alert-decagram
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.9.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
|
||||||
|
:material-plus: [platform.http_proxy.match_domain](#platformhttp_proxymatch_domain)
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [gso](#gso)
|
:material-plus: [gso](#gso)
|
||||||
@@ -73,7 +78,9 @@ icon: material/alert-decagram
|
|||||||
"http_proxy": {
|
"http_proxy": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"server": "127.0.0.1",
|
"server": "127.0.0.1",
|
||||||
"server_port": 8080
|
"server_port": 8080,
|
||||||
|
"bypass_domain": [],
|
||||||
|
"match_domain": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -140,7 +147,7 @@ tun 接口的 IPv6 前缀。
|
|||||||
* 让不支持的网络无法到达
|
* 让不支持的网络无法到达
|
||||||
* 将所有连接路由到 tun
|
* 将所有连接路由到 tun
|
||||||
|
|
||||||
它可以防止地址泄漏,并使 DNS 劫持在 Android 上工作,但你的设备将无法其他设备被访问。
|
它可以防止地址泄漏,并使 DNS 劫持在 Android 上工作。
|
||||||
|
|
||||||
*在 Windows 中*:
|
*在 Windows 中*:
|
||||||
|
|
||||||
@@ -257,6 +264,38 @@ TCP/IP 栈。
|
|||||||
|
|
||||||
系统 HTTP 代理设置。
|
系统 HTTP 代理设置。
|
||||||
|
|
||||||
|
##### platform.http_proxy.enabled
|
||||||
|
|
||||||
|
启用系统 HTTP 代理。
|
||||||
|
|
||||||
|
##### platform.http_proxy.server
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
系统 HTTP 代理服务器地址。
|
||||||
|
|
||||||
|
##### platform.http_proxy.server_port
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
系统 HTTP 代理服务器端口。
|
||||||
|
|
||||||
|
##### platform.http_proxy.bypass_domain
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
在 Apple 平台,`bypass_domain` 项匹配主机名 **后缀**.
|
||||||
|
|
||||||
|
绕过代理的主机名列表。
|
||||||
|
|
||||||
|
##### platform.http_proxy.match_domain
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
代理的主机名列表。
|
||||||
|
|
||||||
### 监听字段
|
### 监听字段
|
||||||
|
|
||||||
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 字段
|
### Fields
|
||||||
|
|
||||||
No fields.
|
No fields.
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/new-box
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|
||||||
:material-plus: [gso](#gso)
|
:material-plus: [gso](#gso)
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/new-box
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [gso](#gso)
|
:material-plus: [gso](#gso)
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
# Route
|
# Route
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
# 路由
|
# 路由
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|
||||||
:material-plus: [rule_set](#rule_set)
|
:material-plus: [rule_set](#rule_set)
|
||||||
@@ -109,6 +105,7 @@ icon: material/alert-decagram
|
|||||||
"geoip-cn",
|
"geoip-cn",
|
||||||
"geosite-cn"
|
"geosite-cn"
|
||||||
],
|
],
|
||||||
|
"rule_set_ipcidr_match_source": false,
|
||||||
"invert": false,
|
"invert": false,
|
||||||
"outbound": "direct"
|
"outbound": "direct"
|
||||||
},
|
},
|
||||||
@@ -284,7 +281,7 @@ Match Clash mode.
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
Match WiFi SSID.
|
Match WiFi SSID.
|
||||||
|
|
||||||
@@ -292,7 +289,7 @@ Match WiFi SSID.
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
Match WiFi BSSID.
|
Match WiFi BSSID.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [rule_set](#rule_set)
|
:material-plus: [rule_set](#rule_set)
|
||||||
@@ -107,6 +103,7 @@ icon: material/alert-decagram
|
|||||||
"geoip-cn",
|
"geoip-cn",
|
||||||
"geosite-cn"
|
"geosite-cn"
|
||||||
],
|
],
|
||||||
|
"rule_set_ipcidr_match_source": false,
|
||||||
"invert": false,
|
"invert": false,
|
||||||
"outbound": "direct"
|
"outbound": "direct"
|
||||||
},
|
},
|
||||||
@@ -282,7 +279,7 @@ icon: material/alert-decagram
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
仅在 Android 与 iOS 的图形客户端中支持。
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
匹配 WiFi SSID。
|
匹配 WiFi SSID。
|
||||||
|
|
||||||
@@ -290,7 +287,7 @@ icon: material/alert-decagram
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
仅在 Android 与 iOS 的图形客户端中支持。
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
匹配 WiFi BSSID。
|
匹配 WiFi BSSID。
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/new-box
|
|
||||||
---
|
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
!!! question "Since sing-box 1.8.0"
|
!!! question "Since sing-box 1.8.0"
|
||||||
@@ -128,7 +124,7 @@ Match source IP CIDR.
|
|||||||
|
|
||||||
!!! info ""
|
!!! info ""
|
||||||
|
|
||||||
`ip_cidr` is an alias for `source_ip_cidr` when the Rule Set is used in DNS rules or `rule_set_ipcidr_match_source` enabled in route rules.
|
`ip_cidr` is an alias for `source_ip_cidr` when `rule_set_ipcidr_match_source` enabled in route/DNS rules.
|
||||||
|
|
||||||
Match IP CIDR.
|
Match IP CIDR.
|
||||||
|
|
||||||
@@ -172,7 +168,7 @@ Match android package name.
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
Match WiFi SSID.
|
Match WiFi SSID.
|
||||||
|
|
||||||
@@ -180,7 +176,7 @@ Match WiFi SSID.
|
|||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
||||||
Only supported in graphical clients on Android and iOS.
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
Match WiFi BSSID.
|
Match WiFi BSSID.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/new-box
|
|
||||||
---
|
|
||||||
|
|
||||||
# Rule Set
|
# Rule Set
|
||||||
|
|
||||||
!!! question "Since sing-box 1.8.0"
|
!!! question "Since sing-box 1.8.0"
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/new-box
|
|
||||||
---
|
|
||||||
|
|
||||||
# Source Format
|
# Source Format
|
||||||
|
|
||||||
!!! question "Since sing-box 1.8.0"
|
!!! question "Since sing-box 1.8.0"
|
||||||
|
|||||||
@@ -83,7 +83,10 @@
|
|||||||
|
|
||||||
如果设置,域名将在请求发出之前解析为 IP。
|
如果设置,域名将在请求发出之前解析为 IP。
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
| 出站 | 受影响的域名 | 默认回退值 |
|
||||||
|
|----------|--------------------------|-------------------------------------------|
|
||||||
|
| `direct` | 请求中的域名 | `inbound.domain_strategy` |
|
||||||
|
| others | 服务器地址中的域名 | / |
|
||||||
|
|
||||||
#### fallback_delay
|
#### fallback_delay
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.8.0"
|
!!! quote "Changes in sing-box 1.8.0"
|
||||||
|
|
||||||
:material-alert-decagram: [utls](#utls)
|
:material-alert-decagram: [utls](#utls)
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
---
|
|
||||||
icon: material/alert-decagram
|
|
||||||
---
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|
||||||
:material-alert-decagram: [utls](#utls)
|
:material-alert-decagram: [utls](#utls)
|
||||||
|
|||||||
@@ -6,26 +6,18 @@ icon: material/file-code
|
|||||||
|
|
||||||
## :material-graph: Requirements
|
## :material-graph: Requirements
|
||||||
|
|
||||||
Before sing-box 1.4.0:
|
### sing-box 1.10
|
||||||
|
|
||||||
* Go 1.18.5 - 1.20.x
|
* Go 1.20.0 - ~
|
||||||
|
|
||||||
Since sing-box 1.4.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ with tag `with_quic` enabled
|
|
||||||
|
|
||||||
Since sing-box 1.5.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ with tag `with_quic` or `with_ech` enabled
|
|
||||||
|
|
||||||
Since sing-box 1.8.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
|
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
|
||||||
* Go 1.21.0 - ~ with tag `with_ech` enabled
|
* Go 1.21.0 - ~ with tag `with_ech` enabled
|
||||||
|
|
||||||
|
### sing-box 1.9
|
||||||
|
|
||||||
|
* Go 1.18.5 - 1.22.x
|
||||||
|
* Go 1.20.0 - 1.22.x with tag `with_quic`, or `with_utls` enabled
|
||||||
|
* Go 1.21.0 - 1.22.x with tag `with_ech` enabled
|
||||||
|
|
||||||
You can download and install Go from: https://go.dev/doc/install, latest version is recommended.
|
You can download and install Go from: https://go.dev/doc/install, latest version is recommended.
|
||||||
|
|
||||||
## :material-fast-forward: Simple Build
|
## :material-fast-forward: Simple Build
|
||||||
@@ -57,16 +49,16 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
|||||||
| Build Tag | Enabled by default | Description |
|
| Build Tag | Enabled by default | Description |
|
||||||
|------------------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). |
|
| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). |
|
||||||
| `with_grpc` | :material-close:️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
|
| `with_grpc` | :material-close:️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
|
||||||
| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). |
|
| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). |
|
||||||
| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). |
|
| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). |
|
||||||
| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). |
|
| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). |
|
||||||
| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). |
|
| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). |
|
||||||
| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). |
|
| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). |
|
||||||
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). |
|
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). |
|
||||||
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). |
|
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). |
|
||||||
| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). |
|
| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). |
|
||||||
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). |
|
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). |
|
||||||
| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
|
| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
|
||||||
|
|
||||||
It is not recommended to change the default build tag list unless you really know what you are adding.
|
It is not recommended to change the default build tag list unless you really know what you are adding.
|
||||||
|
|||||||
@@ -6,25 +6,17 @@ icon: material/file-code
|
|||||||
|
|
||||||
## :material-graph: 要求
|
## :material-graph: 要求
|
||||||
|
|
||||||
sing-box 1.4.0 前:
|
### sing-box 1.10
|
||||||
|
|
||||||
* Go 1.18.5 - 1.20.x
|
* Go 1.20.0 - ~
|
||||||
|
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
|
||||||
|
* Go 1.21.0 - ~ with tag `with_ech` enabled
|
||||||
|
|
||||||
从 sing-box 1.4.0:
|
### sing-box 1.9
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
* Go 1.18.5 - 1.22.x
|
||||||
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic`
|
* Go 1.20.0 - 1.22.x with tag `with_quic`, or `with_utls` enabled
|
||||||
|
* Go 1.21.0 - 1.22.x with tag `with_ech` enabled
|
||||||
从 sing-box 1.5.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic` 或 `with_ech`
|
|
||||||
|
|
||||||
从 sing-box 1.8.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic` 或 `with_utls`
|
|
||||||
* Go 1.20.1 - ~ 如果启用构建标记 `with_ech`
|
|
||||||
|
|
||||||
您可以从 https://go.dev/doc/install 下载并安装 Go,推荐使用最新版本。
|
您可以从 https://go.dev/doc/install 下载并安装 Go,推荐使用最新版本。
|
||||||
|
|
||||||
@@ -54,19 +46,19 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
|||||||
|
|
||||||
## :material-folder-settings: 构建标记
|
## :material-folder-settings: 构建标记
|
||||||
|
|
||||||
| 构建标记 | 默认启动 | 说明 |
|
| 构建标记 | 默认启动 | 说明 |
|
||||||
|------------------------------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). |
|
| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). |
|
||||||
| `with_grpc` | :material-close:️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
|
| `with_grpc` | :material-close:️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
|
||||||
| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). |
|
| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). |
|
||||||
| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). |
|
| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). |
|
||||||
| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). |
|
| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). |
|
||||||
| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). |
|
| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). |
|
||||||
| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). |
|
| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). |
|
||||||
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). |
|
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). |
|
||||||
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). |
|
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). |
|
||||||
| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). |
|
| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). |
|
||||||
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). |
|
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). |
|
||||||
| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
|
| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
|
||||||
|
|
||||||
除非您确实知道您正在启用什么,否则不建议更改默认构建标签列表。
|
除非您确实知道您正在启用什么,否则不建议更改默认构建标签列表。
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ icon: material/package
|
|||||||
=== ":material-debian: Debian / APT"
|
=== ":material-debian: Debian / APT"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo curl -fsSL https://deb.sagernet.org/gpg.key -o /etc/apt/keyrings/sagernet.asc
|
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc
|
||||||
sudo chmod a+r /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/ * *" | \
|
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 tee /etc/apt/sources.list.d/sagernet.list > /dev/null
|
||||||
@@ -21,17 +21,10 @@ icon: material/package
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo dnf -y install dnf-plugins-core
|
sudo dnf -y install dnf-plugins-core
|
||||||
sudo dnf config-manager --add-repo https://sing-box.app/rpm.repo
|
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
||||||
sudo dnf install sing-box # or sing-box-beta
|
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-redhat: CentOS / YUM"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo yum install -y yum-utils
|
|
||||||
sudo yum-config-manager --add-repo https://sing-box.app/rpm.repo
|
|
||||||
sudo yum install sing-box # or sing-box-beta
|
|
||||||
```
|
|
||||||
|
|
||||||
## :material-download-box: Manual Installation
|
## :material-download-box: Manual Installation
|
||||||
|
|
||||||
@@ -46,6 +39,7 @@ icon: material/package
|
|||||||
```bash
|
```bash
|
||||||
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
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"
|
=== ":simple-archlinux: Archlinux / PKG"
|
||||||
|
|
||||||
@@ -57,38 +51,55 @@ icon: material/package
|
|||||||
|
|
||||||
=== ":material-linux: Linux"
|
=== ":material-linux: Linux"
|
||||||
|
|
||||||
| Type | Platform | Link | Command | Actively maintained |
|
| Type | Platform | Command | Link |
|
||||||
|----------|---------------|-------------------------|------------------------------|---------------------|
|
|----------|---------------|------------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||||
| APK | Alpine | [sing-box][alpine] | `apk add sing-box` | :material-check: |
|
| AUR | Arch Linux | `? -S sing-box` | [][aur] |
|
||||||
| AUR | Arch Linux | [sing-box][aur] ᴬᵁᴿ | `? -S sing-box` | :material-check: |
|
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
||||||
| nixpkgs | NixOS | [sing-box][nixpkgs] | `nix-env -iA nixos.sing-box` | :material-check: |
|
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
||||||
| Homebrew | macOS / Linux | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
||||||
|
| DEB | AOSC | `apt install sing-box` | [][aosc] |
|
||||||
|
|
||||||
=== ":material-apple: macOS"
|
=== ":material-apple: macOS"
|
||||||
|
|
||||||
| Type | Platform | Link | Command | Actively maintained |
|
| Type | Platform | Command | Link |
|
||||||
|----------|----------|------------------|-------------------------|---------------------|
|
|----------|----------|-------------------------|------------------------------------------------------------------------------------------------|
|
||||||
| Homebrew | macOS | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
| Homebrew | macOS | `brew install sing-box` | [][brew] |
|
||||||
|
|
||||||
=== ":material-microsoft-windows: Windows"
|
=== ":material-microsoft-windows: Windows"
|
||||||
|
|
||||||
| Type | Platform | Link | Command | Actively maintained |
|
| Type | Platform | Command | Link |
|
||||||
|------------|--------------------|---------------------|------------------------------|---------------------|
|
|------------|----------|---------------------------|-----------------------------------------------------------------------------------------------------|
|
||||||
| Scoop | Windows | [sing-box][scoop] | `scoop install sing-box` | :material-check: |
|
| Scoop | Windows | `scoop install sing-box` | [][scoop] |
|
||||||
| Chocolatey | Windows | [sing-box][choco] | `choco install sing-box` | :material-check: |
|
| Chocolatey | Windows | `choco install sing-box` | [][choco] |
|
||||||
| winget | Windows | [sing-box][winget] | `winget install sing-box` | :material-alert: |
|
| winget | Windows | `winget install sing-box` | [][winget] |
|
||||||
|
|
||||||
=== ":material-android: Android"
|
=== ":material-android: Android"
|
||||||
|
|
||||||
| Type | Platform | Link | Command | Actively maintained |
|
| Type | Platform | Command | Link |
|
||||||
|------------|--------------------|---------------------|------------------------------|---------------------|
|
|--------|----------|--------------------|----------------------------------------------------------------------------------------------|
|
||||||
| Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: |
|
| Termux | Android | `pkg add sing-box` | [][termux] |
|
||||||
|
|
||||||
=== ":material-freebsd: FreeBSD"
|
=== ":material-freebsd: FreeBSD"
|
||||||
|
|
||||||
| Type | Platform | Link | Command | Actively maintained |
|
| Type | Platform | Command | Link |
|
||||||
|------------|----------|-------------------|------------------------|---------------------|
|
|------------|----------|------------------------|--------------------------------------------------------------------------------------------|
|
||||||
| FreshPorts | FreeBSD | [sing-box][ports] | `pkg install sing-box` | :material-alert: |
|
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||||
|
|
||||||
|
## :material-alert: Problematic Sources
|
||||||
|
|
||||||
|
| Type | Platform | Link | Promblem(s) |
|
||||||
|
|------------|----------|-------------------------------------------------------------------------------------------|------------------------------------------------------------------|
|
||||||
|
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | Problematic build tag list modification; Not actively maintained |
|
||||||
|
| Homebrew | / | [homebrew-core][brew] | Problematic build tag list modification |
|
||||||
|
| Termux | Android | [termux-packages][termux] | Problematic build tag list modification |
|
||||||
|
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | Old Go (go1.20) |
|
||||||
|
|
||||||
|
If you are a user of them, please report issues to them:
|
||||||
|
|
||||||
|
1. Please do not modify release build tags without full understanding of the related functionality: enabling non-default
|
||||||
|
labels may result in decreased performance; the lack of default labels may cause user confusion.
|
||||||
|
2. sing-box supports compiling with some older Go versions, but it is not recommended (especially versions that are no
|
||||||
|
longer supported by Go).
|
||||||
|
|
||||||
## :material-book-multiple: Service Management
|
## :material-book-multiple: Service Management
|
||||||
|
|
||||||
@@ -128,4 +139,6 @@ you can manage the service using the following command:
|
|||||||
|
|
||||||
[ports]: https://www.freshports.org/net/sing-box
|
[ports]: https://www.freshports.org/net/sing-box
|
||||||
|
|
||||||
|
[aosc]: https://packages.aosc.io/packages/sing-box
|
||||||
|
|
||||||
[systemd]: https://systemd.io/
|
[systemd]: https://systemd.io/
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ icon: material/package
|
|||||||
=== ":material-debian: Debian / APT"
|
=== ":material-debian: Debian / APT"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo curl -fsSL https://deb.sagernet.org/gpg.key -o /etc/apt/keyrings/sagernet.asc
|
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc
|
||||||
sudo chmod a+r /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/ * *" | \
|
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 tee /etc/apt/sources.list.d/sagernet.list > /dev/null
|
||||||
@@ -21,17 +21,10 @@ icon: material/package
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo dnf -y install dnf-plugins-core
|
sudo dnf -y install dnf-plugins-core
|
||||||
sudo dnf config-manager --add-repo https://sing-box.app/rpm.repo
|
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
||||||
sudo dnf install sing-box # or sing-box-beta
|
sudo dnf install sing-box # or sing-box-beta
|
||||||
```
|
```
|
||||||
|
(这适用于任何使用 `dnf` 作为包管理器的发行版:Fedora、CentOS,甚至安装了 DNF 的 OpenSUSE。)
|
||||||
=== ":material-redhat: CentOS / YUM"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo yum install -y yum-utils
|
|
||||||
sudo yum-config-manager --add-repo https://sing-box.app/rpm.repo
|
|
||||||
sudo yum install sing-box # or sing-box-beta
|
|
||||||
```
|
|
||||||
|
|
||||||
## :material-download-box: 手动安装
|
## :material-download-box: 手动安装
|
||||||
|
|
||||||
@@ -46,6 +39,7 @@ icon: material/package
|
|||||||
```bash
|
```bash
|
||||||
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
||||||
```
|
```
|
||||||
|
(这适用于任何使用 `rpm` 和 `systemd` 的发行版。由于 `rpm` 定义依赖关系的方式,如果安装成功,就多半能用。)
|
||||||
|
|
||||||
=== ":simple-archlinux: Archlinux / PKG"
|
=== ":simple-archlinux: Archlinux / PKG"
|
||||||
|
|
||||||
@@ -57,38 +51,54 @@ icon: material/package
|
|||||||
|
|
||||||
=== ":material-linux: Linux"
|
=== ":material-linux: Linux"
|
||||||
|
|
||||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
| 类型 | 平台 | 链接 | 命令 |
|
||||||
|----------|------------|---------------------|------------------------------|------------------|
|
|----------|---------------|------------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||||
| Alpine | Alpine | [sing-box][alpine] | `apk add sing-box` | :material-check: |
|
| AUR | Arch Linux | `? -S sing-box` | [][aur] |
|
||||||
| AUR | Arch Linux | [sing-box][aur] ᴬᵁᴿ | `? -S sing-box` | :material-check: |
|
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
||||||
| nixpkgs | NixOS | [sing-box][nixpkgs] | `nix-env -iA nixos.sing-box` | :material-check: |
|
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
||||||
| Homebrew | Linux | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
||||||
|
| DEB | AOSC | `apt install sing-box` | [][aosc] |
|
||||||
|
|
||||||
=== ":material-apple: macOS"
|
=== ":material-apple: macOS"
|
||||||
|
|
||||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
| 类型 | 平台 | 链接 | 命令 |
|
||||||
|----------|-------|------------------|-------------------------|------------------|
|
|----------|-------|-------------------------|------------------------------------------------------------------------------------------------|
|
||||||
| Homebrew | macOS | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
| Homebrew | macOS | `brew install sing-box` | [][brew] |
|
||||||
|
|
||||||
=== ":material-microsoft-windows: Windows"
|
=== ":material-microsoft-windows: Windows"
|
||||||
|
|
||||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
| 类型 | 平台 | 链接 | 命令 |
|
||||||
|------------|---------|--------------------|---------------------------|------------------|
|
|------------|---------|---------------------------|-----------------------------------------------------------------------------------------------------|
|
||||||
| Scoop | Windows | [sing-box][scoop] | `scoop install sing-box` | :material-check: |
|
| Scoop | Windows | `scoop install sing-box` | [][scoop] |
|
||||||
| Chocolatey | Windows | [sing-box][choco] | `choco install sing-box` | :material-check: |
|
| Chocolatey | Windows | `choco install sing-box` | [][choco] |
|
||||||
| winget | Windows | [sing-box][winget] | `winget install sing-box` | :material-alert: |
|
| winget | Windows | `winget install sing-box` | [][winget] |
|
||||||
|
|
||||||
=== ":material-android: Android"
|
=== ":material-android: Android"
|
||||||
|
|
||||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
| 类型 | 平台 | 链接 | 命令 |
|
||||||
|--------|---------|--------------------|--------------------|------------------|
|
|--------|---------|--------------------|----------------------------------------------------------------------------------------------|
|
||||||
| Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: |
|
| Termux | Android | `pkg add sing-box` | [][termux] |
|
||||||
|
|
||||||
=== ":material-freebsd: FreeBSD"
|
=== ":material-freebsd: FreeBSD"
|
||||||
|
|
||||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
| 类型 | 平台 | 链接 | 命令 |
|
||||||
|------------|---------|-------------------|------------------------|------------------|
|
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
|
||||||
| FreshPorts | FreeBSD | [sing-box][ports] | `pkg install sing-box` | :material-alert: |
|
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||||
|
|
||||||
|
|
||||||
|
## :material-alert: 存在问题的源
|
||||||
|
|
||||||
|
| 类型 | 平台 | 链接 | 原因 |
|
||||||
|
|------------|---------|-------------------------------------------------------------------------------------------|-----------------------|
|
||||||
|
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改; 没有活跃维护 |
|
||||||
|
| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 |
|
||||||
|
| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 |
|
||||||
|
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) |
|
||||||
|
|
||||||
|
如果您是其用户,请向他们报告问题:
|
||||||
|
|
||||||
|
1. 在未完全了解相关功能的情况下,请勿修改发布版本标签:启用非默认标签可能会导致性能下降;缺少默认标签可能会引起用户混淆。
|
||||||
|
2. sing-box 支持使用一些较旧的 Go 版本进行编译,但不推荐使用(特别是已不再受 Go 支持的版本)。
|
||||||
|
|
||||||
## :material-book-multiple: 服务管理
|
## :material-book-multiple: 服务管理
|
||||||
|
|
||||||
@@ -124,4 +134,6 @@ icon: material/package
|
|||||||
|
|
||||||
[ports]: https://www.freshports.org/net/sing-box
|
[ports]: https://www.freshports.org/net/sing-box
|
||||||
|
|
||||||
|
[aosc]: https://packages.aosc.io/packages/sing-box
|
||||||
|
|
||||||
[systemd]: https://systemd.io/
|
[systemd]: https://systemd.io/
|
||||||
|
|||||||
@@ -2,5 +2,6 @@
|
|||||||
name=sing-box
|
name=sing-box
|
||||||
baseurl=https://rpm.sagernet.org/
|
baseurl=https://rpm.sagernet.org/
|
||||||
enabled=1
|
enabled=1
|
||||||
|
repo_gpgcheck=1
|
||||||
gpgcheck=1
|
gpgcheck=1
|
||||||
gpgkey=https://deb.sagernet.org/gpg.key
|
gpgkey=https://sing-box.app/gpg.key
|
||||||
38
docs/manual/misc/tunnelvision.md
Normal file
38
docs/manual/misc/tunnelvision.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
icon: material/book-lock-open
|
||||||
|
---
|
||||||
|
|
||||||
|
# TunnelVision
|
||||||
|
|
||||||
|
TunnelVision is an attack that uses DHCP option 121 to set higher priority routes
|
||||||
|
so that traffic does not go through the VPN.
|
||||||
|
|
||||||
|
Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-3661
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
### Android
|
||||||
|
|
||||||
|
Android does not handle DHCP option 121 and is not affected.
|
||||||
|
|
||||||
|
### Apple platforms
|
||||||
|
|
||||||
|
Update [sing-box graphical client](/clients/apple/#download) to `1.9.0-rc.16` or newer,
|
||||||
|
then enable `includeAllNetworks` in `Settings` — `Packet Tunnel` and you will be unaffected.
|
||||||
|
|
||||||
|
Note: when `includeAllNetworks` is enabled, the default TUN stack is changed to `gvisor`,
|
||||||
|
and the `system` and `mixed` stacks are not available.
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
Update sing-box to `1.9.0-rc.16` or newer, rules generated by `auto-route` are unaffected.
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
No solution yet.
|
||||||
|
|
||||||
|
## Workarounds
|
||||||
|
|
||||||
|
* Don't connect to untrusted networks
|
||||||
|
* Relay untrusted network through another device
|
||||||
|
* Just ignore it
|
||||||
@@ -4,16 +4,17 @@ icon: material/lightning-bolt
|
|||||||
|
|
||||||
# Hysteria 2
|
# Hysteria 2
|
||||||
|
|
||||||
The most popular Chinese-made simple protocol based on QUIC, the selling point is Brutal,
|
Hysteria 2 is a simple, Chinese-made protocol based on QUIC.
|
||||||
a congestion control algorithm that can resist packet loss by manually specifying the required rate by the user.
|
The selling point is Brutal, a congestion control algorithm that
|
||||||
|
tries to achieve a user-defined bandwidth despite packet loss.
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
|
|
||||||
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies.
|
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more obvious characteristics than TCP based proxies.
|
||||||
|
|
||||||
| Specification | Binary Characteristics | Active Detect Hiddenness |
|
| Specification | Resists passive detection | Resists active probes |
|
||||||
|---------------------------------------------------------------------------|------------------------|--------------------------|
|
|---------------------------------------------------------------------------|---------------------------|-----------------------|
|
||||||
| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: |
|
| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: |
|
||||||
|
|
||||||
## :material-text-box-check: Password Generator
|
## :material-text-box-check: Password Generator
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ To use sing-box with the official program, you need to fill in that combination
|
|||||||
Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your server.
|
Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your server.
|
||||||
|
|
||||||
=== ":material-harddisk: With local certificate"
|
=== ":material-harddisk: With local certificate"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"inbounds": [
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ icon: material/send
|
|||||||
|
|
||||||
# Shadowsocks
|
# Shadowsocks
|
||||||
|
|
||||||
As the most well-known Chinese-made proxy protocol,
|
Shadowsocks is the most well-known Chinese-made proxy protocol.
|
||||||
Shadowsocks exists in multiple versions,
|
It exists in multiple versions, but only AEAD 2022 ciphers
|
||||||
but only AEAD 2022 ciphers TCP with multiplexing is recommended.
|
over TCP with multiplexing is recommended.
|
||||||
|
|
||||||
| Ciphers | Specification | Cryptographic Security | Binary Characteristics | Active Detect Hiddenness |
|
| Ciphers | Specification | Cryptographically sound | Resists passive detection | Resists active probes |
|
||||||
|----------------|------------------------------------------------------------|------------------------|------------------------|--------------------------|
|
|----------------|------------------------------------------------------------|-------------------------|---------------------------|-----------------------|
|
||||||
| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: |
|
| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: |
|
||||||
| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: |
|
| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: |
|
||||||
| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: |
|
| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: |
|
||||||
|
|
||||||
|
(We strongly recommend using multiplexing to send UDP traffic over TCP, because
|
||||||
|
doing otherwise is vulnerable to passive detection.)
|
||||||
|
|
||||||
## :material-text-box-check: Password Generator
|
## :material-text-box-check: Password Generator
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ icon: material/horse
|
|||||||
|
|
||||||
# Trojan
|
# Trojan
|
||||||
|
|
||||||
As the most commonly used TLS proxy made in China, Trojan can be used in various combinations,
|
Torjan is the most commonly used TLS proxy made in China. It can be used in various combinations,
|
||||||
but only the combination of uTLS and multiplexing is recommended.
|
but only the combination of uTLS and multiplexing is recommended.
|
||||||
|
|
||||||
| Protocol and implementation combination | Specification | Binary Characteristics | Active Detect Hiddenness |
|
| Protocol and implementation combination | Specification | Resists passive detection | Resists active probes |
|
||||||
|-----------------------------------------|----------------------------------------------------------------------|------------------------|--------------------------|
|
|-----------------------------------------|----------------------------------------------------------------------|---------------------------|-----------------------|
|
||||||
| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: |
|
| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: |
|
||||||
| Basic Go implementation | / | :material-alert: | :material-check: |
|
| Basic Go implementation | / | :material-alert: | :material-check: |
|
||||||
| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: |
|
| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: |
|
||||||
| with uTLS enabled | No formal definition | :material-help: | :material-check: |
|
| with uTLS enabled | No formal definition | :material-help: | :material-check: |
|
||||||
|
|
||||||
## :material-text-box-check: Password Generator
|
## :material-text-box-check: Password Generator
|
||||||
|
|
||||||
@@ -211,4 +211,3 @@ but only the combination of uTLS and multiplexing is recommended.
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,208 +0,0 @@
|
|||||||
---
|
|
||||||
icon: material/alpha-t-box
|
|
||||||
---
|
|
||||||
|
|
||||||
# TUIC
|
|
||||||
|
|
||||||
A recently popular Chinese-made simple protocol based on QUIC, the selling point is the BBR congestion control algorithm.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
|
|
||||||
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies.
|
|
||||||
|
|
||||||
| Specification | Binary Characteristics | Active Detect Hiddenness |
|
|
||||||
|-----------------------------------------------------------|------------------------|--------------------------|
|
|
||||||
| [GitHub](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: |
|
|
||||||
|
|
||||||
## Password Generator
|
|
||||||
|
|
||||||
| Generated UUID | Generated Password | Action |
|
|
||||||
|------------------------|----------------------------|-----------------------------------------------------------------|
|
|
||||||
| <code id="uuid"><code> | <code id="password"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function generateUUID() {
|
|
||||||
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
||||||
let r = Math.random() * 16 | 0,
|
|
||||||
v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
||||||
return v.toString(16);
|
|
||||||
});
|
|
||||||
document.getElementById("uuid").textContent = uuid;
|
|
||||||
}
|
|
||||||
function generatePassword() {
|
|
||||||
const array = new Uint8Array(16);
|
|
||||||
window.crypto.getRandomValues(array);
|
|
||||||
document.getElementById("password").textContent = btoa(String.fromCharCode.apply(null, array));
|
|
||||||
}
|
|
||||||
function generate() {
|
|
||||||
generateUUID();
|
|
||||||
generatePassword();
|
|
||||||
}
|
|
||||||
generate();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
## :material-server: Server Example
|
|
||||||
|
|
||||||
=== ":material-harddisk: With local certificate"
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"type": "tuic",
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 8080,
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"name": "sekai",
|
|
||||||
"uuid": "<uuid>",
|
|
||||||
"password": "<password>"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"congestion_control": "bbr",
|
|
||||||
"tls": {
|
|
||||||
"enabled": true,
|
|
||||||
"server_name": "example.org",
|
|
||||||
"key_path": "/path/to/key.pem",
|
|
||||||
"certificate_path": "/path/to/certificate.pem"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
=== ":material-auto-fix: With ACME"
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"type": "tuic",
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 8080,
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"name": "sekai",
|
|
||||||
"uuid": "<uuid>",
|
|
||||||
"password": "<password>"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"congestion_control": "bbr",
|
|
||||||
"tls": {
|
|
||||||
"enabled": true,
|
|
||||||
"server_name": "example.org",
|
|
||||||
"acme": {
|
|
||||||
"domain": "example.org",
|
|
||||||
"email": "admin@example.org"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
=== ":material-cloud: With ACME and Cloudflare API"
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"type": "tuic",
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 8080,
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"name": "sekai",
|
|
||||||
"uuid": "<uuid>",
|
|
||||||
"password": "<password>"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"congestion_control": "bbr",
|
|
||||||
"tls": {
|
|
||||||
"enabled": true,
|
|
||||||
"server_name": "example.org",
|
|
||||||
"acme": {
|
|
||||||
"domain": "example.org",
|
|
||||||
"email": "admin@example.org",
|
|
||||||
"dns01_challenge": {
|
|
||||||
"provider": "cloudflare",
|
|
||||||
"api_token": "my_token"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## :material-cellphone-link: Client Example
|
|
||||||
|
|
||||||
=== ":material-web-check: With valid certificate"
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"type": "tuic",
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8080,
|
|
||||||
"uuid": "<uuid>",
|
|
||||||
"password": "<password>",
|
|
||||||
"congestion_control": "bbr",
|
|
||||||
"tls": {
|
|
||||||
"enabled": true,
|
|
||||||
"server_name": "example.org"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
=== ":material-check: With self-sign certificate"
|
|
||||||
|
|
||||||
!!! info "Tip"
|
|
||||||
|
|
||||||
Use `sing-box merge` command to merge configuration and certificate into one file.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"type": "tuic",
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8080,
|
|
||||||
"uuid": "<uuid>",
|
|
||||||
"password": "<password>",
|
|
||||||
"congestion_control": "bbr",
|
|
||||||
"tls": {
|
|
||||||
"enabled": true,
|
|
||||||
"server_name": "example.org",
|
|
||||||
"certificate_path": "/path/to/certificate.pem"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
=== ":material-alert: Ignore certificate verification"
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"type": "tuic",
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8080,
|
|
||||||
"uuid": "<uuid>",
|
|
||||||
"password": "<password>",
|
|
||||||
"congestion_control": "bbr",
|
|
||||||
"tls": {
|
|
||||||
"enabled": true,
|
|
||||||
"server_name": "example.org",
|
|
||||||
"insecure": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -290,52 +290,6 @@ flowchart TB
|
|||||||
|
|
||||||
=== ":material-dns: DNS rules"
|
=== ":material-dns: DNS rules"
|
||||||
|
|
||||||
!!! info
|
|
||||||
|
|
||||||
DNS rules are optional if FakeIP is used.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"dns": {
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"tag": "google",
|
|
||||||
"address": "tls://8.8.8.8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "local",
|
|
||||||
"address": "223.5.5.5",
|
|
||||||
"detour": "direct"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"outbound": "any",
|
|
||||||
"server": "local"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"clash_mode": "Direct",
|
|
||||||
"server": "local"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"clash_mode": "Global",
|
|
||||||
"server": "google"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"geosite": "geolocation-cn",
|
|
||||||
"server": "local"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
=== ":material-dns: DNS rules (1.8.0+)"
|
|
||||||
|
|
||||||
!!! info
|
|
||||||
|
|
||||||
DNS rules are optional if FakeIP is used.
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"dns": {
|
"dns": {
|
||||||
@@ -382,74 +336,180 @@ flowchart TB
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
=== ":material-router-network: Route rules"
|
=== ":material-dns: DNS rules (Enhanced, but slower) (1.9.0+)"
|
||||||
|
|
||||||
```json
|
=== ":material-shield-off: With DNS leaks"
|
||||||
{
|
|
||||||
"outbounds": [
|
```json
|
||||||
{
|
{
|
||||||
"type": "direct",
|
"dns": {
|
||||||
"tag": "direct"
|
"servers": [
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "block",
|
|
||||||
"tag": "block"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"route": {
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"type": "logical",
|
|
||||||
"mode": "or",
|
|
||||||
"rules": [
|
|
||||||
{
|
{
|
||||||
"protocol": "dns"
|
"tag": "google",
|
||||||
|
"address": "tls://8.8.8.8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"port": 53
|
"tag": "local",
|
||||||
|
"address": "https://223.5.5.5/dns-query",
|
||||||
|
"detour": "direct"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outbound": "dns"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"geoip": "private",
|
|
||||||
"outbound": "direct"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"clash_mode": "Direct",
|
|
||||||
"outbound": "direct"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"clash_mode": "Global",
|
|
||||||
"outbound": "default"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "logical",
|
|
||||||
"mode": "or",
|
|
||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
"port": 853
|
"outbound": "any",
|
||||||
|
"server": "local"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"network": "udp",
|
"clash_mode": "Direct",
|
||||||
"port": 443
|
"server": "local"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"protocol": "stun"
|
"clash_mode": "Global",
|
||||||
|
"server": "google"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule_set": "geosite-geolocation-cn",
|
||||||
|
"server": "local"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clash_mode": "Default",
|
||||||
|
"server": "google"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "logical",
|
||||||
|
"mode": "and",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"rule_set": "geosite-geolocation-!cn",
|
||||||
|
"invert": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule_set": "geoip-cn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"server": "local"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"outbound": "block"
|
|
||||||
},
|
},
|
||||||
{
|
"route": {
|
||||||
"geosite": "geolocation-cn",
|
"rule_set": [
|
||||||
"outbound": "direct"
|
{
|
||||||
|
"type": "remote",
|
||||||
|
"tag": "geosite-geolocation-cn",
|
||||||
|
"format": "binary",
|
||||||
|
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "remote",
|
||||||
|
"tag": "geosite-geolocation-!cn",
|
||||||
|
"format": "binary",
|
||||||
|
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "remote",
|
||||||
|
"tag": "geoip-cn",
|
||||||
|
"format": "binary",
|
||||||
|
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"experimental": {
|
||||||
|
"cache_file": {
|
||||||
|
"enabled": true,
|
||||||
|
"store_rdrc": true
|
||||||
|
},
|
||||||
|
"clash_api": {
|
||||||
|
"default_mode": "Enhanced"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
```
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
=== ":material-router-network: Route rules (1.8.0+)"
|
=== ":material-security: Without DNS leaks, but slower (1.9.0-alpha.2+)"
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dns": {
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"tag": "google",
|
||||||
|
"address": "tls://8.8.8.8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tag": "local",
|
||||||
|
"address": "https://223.5.5.5/dns-query",
|
||||||
|
"detour": "direct"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"outbound": "any",
|
||||||
|
"server": "local"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clash_mode": "Direct",
|
||||||
|
"server": "local"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clash_mode": "Global",
|
||||||
|
"server": "google"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule_set": "geosite-geolocation-cn",
|
||||||
|
"server": "local"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "logical",
|
||||||
|
"mode": "and",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"rule_set": "geosite-geolocation-!cn",
|
||||||
|
"invert": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule_set": "geoip-cn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"server": "google",
|
||||||
|
"client_subnet": "114.114.114.114/24" // Any China client IP address
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"rule_set": [
|
||||||
|
{
|
||||||
|
"type": "remote",
|
||||||
|
"tag": "geosite-geolocation-cn",
|
||||||
|
"format": "binary",
|
||||||
|
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "remote",
|
||||||
|
"tag": "geosite-geolocation-!cn",
|
||||||
|
"format": "binary",
|
||||||
|
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "remote",
|
||||||
|
"tag": "geoip-cn",
|
||||||
|
"format": "binary",
|
||||||
|
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"experimental": {
|
||||||
|
"cache_file": {
|
||||||
|
"enabled": true,
|
||||||
|
"store_rdrc": true
|
||||||
|
},
|
||||||
|
"clash_api": {
|
||||||
|
"default_mode": "Enhanced"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
=== ":material-router-network: Route rules"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,41 @@
|
|||||||
icon: material/arrange-bring-forward
|
icon: material/arrange-bring-forward
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 1.9.5
|
||||||
|
|
||||||
|
### Bundle Identifier updates in Apple platform clients
|
||||||
|
|
||||||
|
Due to problems with our old Apple developer account,
|
||||||
|
we can only change Bundle Identifiers to re-list sing-box apps,
|
||||||
|
which means the data will not be automatically inherited.
|
||||||
|
|
||||||
|
For iOS, you need to back up your old data yourself (if you still have access to it);
|
||||||
|
for tvOS, you need to re-import profiles from your iPhone or iPad or create it manually;
|
||||||
|
for macOS, you can migrate the data folder using the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Library/Group\ Containers && \
|
||||||
|
mv group.io.nekohasekai.sfa group.io.nekohasekai.sfavt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1.9.0
|
||||||
|
|
||||||
|
### `domain_suffix` behavior update
|
||||||
|
|
||||||
|
For historical reasons, sing-box's `domain_suffix` rule matches literal prefixes instead of the same as other projects.
|
||||||
|
|
||||||
|
sing-box 1.9.0 modifies the behavior of `domain_suffix`: If the rule value is prefixed with `.`,
|
||||||
|
the behavior is unchanged, otherwise it matches `(domain|.+\.domain)` instead.
|
||||||
|
|
||||||
|
### `process_path` format update on Windows
|
||||||
|
|
||||||
|
The `process_path` rule of sing-box is inherited from Clash,
|
||||||
|
the original code uses the local system's path format (e.g. `\Device\HarddiskVolume1\folder\program.exe`),
|
||||||
|
but when the device has multiple disks, the HarddiskVolume serial number is not stable.
|
||||||
|
|
||||||
|
sing-box 1.9.0 make QueryFullProcessImageNameW output a Win32 path (such as `C:\folder\program.exe`),
|
||||||
|
which will disrupt the existing `process_path` use cases in Windows.
|
||||||
|
|
||||||
## 1.8.0
|
## 1.8.0
|
||||||
|
|
||||||
### :material-close-box: Migrate cache file from Clash API to independent options
|
### :material-close-box: Migrate cache file from Clash API to independent options
|
||||||
|
|||||||
@@ -2,6 +2,39 @@
|
|||||||
icon: material/arrange-bring-forward
|
icon: material/arrange-bring-forward
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 1.9.5
|
||||||
|
|
||||||
|
### Apple 平台客户端的 Bundle Identifier 更新
|
||||||
|
|
||||||
|
由于我们旧的苹果开发者账户存在问题,我们只能通过更新 Bundle Identifiers
|
||||||
|
来重新上架 sing-box 应用, 这意味着数据不会自动继承。
|
||||||
|
|
||||||
|
对于 iOS,您需要自行备份旧的数据(如果您仍然可以访问);
|
||||||
|
对于 Apple tvOS,您需要从 iPhone 或 iPad 重新导入配置或者手动创建;
|
||||||
|
对于 macOS,您可以使用以下命令迁移数据文件夹:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Library/Group\ Containers && \
|
||||||
|
mv group.io.nekohasekai.sfa group.io.nekohasekai.sfavt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1.9.0
|
||||||
|
|
||||||
|
### `domain_suffix` 行为更新
|
||||||
|
|
||||||
|
由于历史原因,sing-box 的 `domain_suffix` 规则匹配字面前缀,而不与其他项目相同。
|
||||||
|
|
||||||
|
sing-box 1.9.0 修改了 `domain_suffix` 的行为:如果规则值以 `.` 为前缀则行为不变,否则改为匹配 `(domain|.+\.domain)`。
|
||||||
|
|
||||||
|
### 对 Windows 上 `process_path` 格式的更新
|
||||||
|
|
||||||
|
sing-box 的 `process_path` 规则继承自Clash,
|
||||||
|
原始代码使用本地系统的路径格式(例如 `\Device\HarddiskVolume1\folder\program.exe`),
|
||||||
|
但是当设备有多个硬盘时,该 HarddiskVolume 系列号并不稳定。
|
||||||
|
|
||||||
|
sing-box 1.9.0 使 QueryFullProcessImageNameW 输出 Win32 路径(如 `C:\folder\program.exe`),
|
||||||
|
这将会破坏现有的 Windows `process_path` 用例。
|
||||||
|
|
||||||
## 1.8.0
|
## 1.8.0
|
||||||
|
|
||||||
### :material-close-box: 将缓存文件从 Clash API 迁移到独立选项
|
### :material-close-box: 将缓存文件从 Clash API 迁移到独立选项
|
||||||
|
|||||||
26
docs/sponsors.md
Normal file
26
docs/sponsors.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
icon: material/hand-coin
|
||||||
|
---
|
||||||
|
|
||||||
|
# Sponsors
|
||||||
|
|
||||||
|
Do you or your friends use sing-box?
|
||||||
|
|
||||||
|
You can help keep the project bug-free and feature rich by sponsoring
|
||||||
|
the project maintainer via [GitHub Sponsors](https://github.com/sponsors/nekohasekai).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Special Sponsors
|
||||||
|
|
||||||
|
**Viral Tech, Inc.**
|
||||||
|
|
||||||
|
Helping us re-list sing-box apps on the Apple Store.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[](https://www.jetbrains.com)
|
||||||
|
|
||||||
|
Free license for the amazing IDEs.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -5,8 +5,7 @@ icon: material/forum
|
|||||||
# Support
|
# Support
|
||||||
|
|
||||||
| Channel | Link |
|
| Channel | Link |
|
||||||
|:------------------------------|:--------------------------------------------|
|
| :---------------------------- | :------------------------------------------ |
|
||||||
| Community | https://community.sagernet.org |
|
|
||||||
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
||||||
| Telegram notification channel | https://t.me/yapnc |
|
| Telegram notification channel | https://t.me/yapnc |
|
||||||
| Telegram user group | https://t.me/yapug |
|
| Telegram user group | https://t.me/yapug |
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ icon: material/forum
|
|||||||
|
|
||||||
# 支持
|
# 支持
|
||||||
|
|
||||||
| 通道 | 链接 |
|
| 通道 | 链接 |
|
||||||
|:--------------|:--------------------------------------------|
|
| :---------------- | :------------------------------------------ |
|
||||||
| 社区 | https://community.sagernet.org |
|
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
||||||
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
|
||||||
| Telegram 通知频道 | https://t.me/yapnc |
|
| Telegram 通知频道 | https://t.me/yapnc |
|
||||||
| Telegram 用户组 | https://t.me/yapug |
|
| Telegram 用户组 | https://t.me/yapug |
|
||||||
| 邮件 | contact@sagernet.org |
|
| 邮件 | contact@sagernet.org |
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ var (
|
|||||||
string(bucketExpand),
|
string(bucketExpand),
|
||||||
string(bucketMode),
|
string(bucketMode),
|
||||||
string(bucketRuleSet),
|
string(bucketRuleSet),
|
||||||
|
string(bucketRDRC),
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheIDDefault = []byte("default")
|
cacheIDDefault = []byte("default")
|
||||||
@@ -37,17 +38,26 @@ var (
|
|||||||
var _ adapter.CacheFile = (*CacheFile)(nil)
|
var _ adapter.CacheFile = (*CacheFile)(nil)
|
||||||
|
|
||||||
type CacheFile struct {
|
type CacheFile struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
path string
|
path string
|
||||||
cacheID []byte
|
cacheID []byte
|
||||||
storeFakeIP bool
|
storeFakeIP bool
|
||||||
|
storeRDRC bool
|
||||||
|
rdrcTimeout time.Duration
|
||||||
DB *bbolt.DB
|
DB *bbolt.DB
|
||||||
saveAccess sync.RWMutex
|
saveMetadataTimer *time.Timer
|
||||||
|
saveFakeIPAccess sync.RWMutex
|
||||||
saveDomain map[netip.Addr]string
|
saveDomain map[netip.Addr]string
|
||||||
saveAddress4 map[string]netip.Addr
|
saveAddress4 map[string]netip.Addr
|
||||||
saveAddress6 map[string]netip.Addr
|
saveAddress6 map[string]netip.Addr
|
||||||
saveMetadataTimer *time.Timer
|
saveRDRCAccess sync.RWMutex
|
||||||
|
saveRDRC map[saveRDRCCacheKey]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type saveRDRCCacheKey struct {
|
||||||
|
TransportName string
|
||||||
|
QuestionName string
|
||||||
|
QType uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
|
func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
|
||||||
@@ -61,14 +71,25 @@ func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
|
|||||||
if options.CacheID != "" {
|
if options.CacheID != "" {
|
||||||
cacheIDBytes = append([]byte{0}, []byte(options.CacheID)...)
|
cacheIDBytes = append([]byte{0}, []byte(options.CacheID)...)
|
||||||
}
|
}
|
||||||
|
var rdrcTimeout time.Duration
|
||||||
|
if options.StoreRDRC {
|
||||||
|
if options.RDRCTimeout > 0 {
|
||||||
|
rdrcTimeout = time.Duration(options.RDRCTimeout)
|
||||||
|
} else {
|
||||||
|
rdrcTimeout = 7 * 24 * time.Hour
|
||||||
|
}
|
||||||
|
}
|
||||||
return &CacheFile{
|
return &CacheFile{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
path: filemanager.BasePath(ctx, path),
|
path: filemanager.BasePath(ctx, path),
|
||||||
cacheID: cacheIDBytes,
|
cacheID: cacheIDBytes,
|
||||||
storeFakeIP: options.StoreFakeIP,
|
storeFakeIP: options.StoreFakeIP,
|
||||||
|
storeRDRC: options.StoreRDRC,
|
||||||
|
rdrcTimeout: rdrcTimeout,
|
||||||
saveDomain: make(map[netip.Addr]string),
|
saveDomain: make(map[netip.Addr]string),
|
||||||
saveAddress4: make(map[string]netip.Addr),
|
saveAddress4: make(map[string]netip.Addr),
|
||||||
saveAddress6: make(map[string]netip.Addr),
|
saveAddress6: make(map[string]netip.Addr),
|
||||||
|
saveRDRC: make(map[saveRDRCCacheKey]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/bbolt"
|
"github.com/sagernet/bbolt"
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@@ -58,12 +59,13 @@ func (c *CacheFile) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
|
func (c *CacheFile) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
|
||||||
if timer := c.saveMetadataTimer; timer != nil {
|
if c.saveMetadataTimer == nil {
|
||||||
timer.Stop()
|
c.saveMetadataTimer = time.AfterFunc(C.FakeIPMetadataSaveInterval, func() {
|
||||||
|
_ = c.FakeIPSaveMetadata(metadata)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
c.saveMetadataTimer.Reset(C.FakeIPMetadataSaveInterval)
|
||||||
}
|
}
|
||||||
c.saveMetadataTimer = time.AfterFunc(10*time.Second, func() {
|
|
||||||
_ = c.FakeIPSaveMetadata(metadata)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
|
func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
|
||||||
@@ -72,6 +74,7 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
oldDomain := bucket.Get(address.AsSlice())
|
||||||
err = bucket.Put(address.AsSlice(), []byte(domain))
|
err = bucket.Put(address.AsSlice(), []byte(domain))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -84,39 +87,51 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if oldDomain != nil {
|
||||||
|
if err := bucket.Delete(oldDomain); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return bucket.Put([]byte(domain), address.AsSlice())
|
return bucket.Put([]byte(domain), address.AsSlice())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
|
func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
|
||||||
c.saveAccess.Lock()
|
c.saveFakeIPAccess.Lock()
|
||||||
|
if oldDomain, loaded := c.saveDomain[address]; loaded {
|
||||||
|
if address.Is4() {
|
||||||
|
delete(c.saveAddress4, oldDomain)
|
||||||
|
} else {
|
||||||
|
delete(c.saveAddress6, oldDomain)
|
||||||
|
}
|
||||||
|
}
|
||||||
c.saveDomain[address] = domain
|
c.saveDomain[address] = domain
|
||||||
if address.Is4() {
|
if address.Is4() {
|
||||||
c.saveAddress4[domain] = address
|
c.saveAddress4[domain] = address
|
||||||
} else {
|
} else {
|
||||||
c.saveAddress6[domain] = address
|
c.saveAddress6[domain] = address
|
||||||
}
|
}
|
||||||
c.saveAccess.Unlock()
|
c.saveFakeIPAccess.Unlock()
|
||||||
go func() {
|
go func() {
|
||||||
err := c.FakeIPStore(address, domain)
|
err := c.FakeIPStore(address, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn("save FakeIP address pair: ", err)
|
logger.Warn("save FakeIP cache: ", err)
|
||||||
}
|
}
|
||||||
c.saveAccess.Lock()
|
c.saveFakeIPAccess.Lock()
|
||||||
delete(c.saveDomain, address)
|
delete(c.saveDomain, address)
|
||||||
if address.Is4() {
|
if address.Is4() {
|
||||||
delete(c.saveAddress4, domain)
|
delete(c.saveAddress4, domain)
|
||||||
} else {
|
} else {
|
||||||
delete(c.saveAddress6, domain)
|
delete(c.saveAddress6, domain)
|
||||||
}
|
}
|
||||||
c.saveAccess.Unlock()
|
c.saveFakeIPAccess.Unlock()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
|
func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
|
||||||
c.saveAccess.RLock()
|
c.saveFakeIPAccess.RLock()
|
||||||
cachedDomain, cached := c.saveDomain[address]
|
cachedDomain, cached := c.saveDomain[address]
|
||||||
c.saveAccess.RUnlock()
|
c.saveFakeIPAccess.RUnlock()
|
||||||
if cached {
|
if cached {
|
||||||
return cachedDomain, true
|
return cachedDomain, true
|
||||||
}
|
}
|
||||||
@@ -137,13 +152,13 @@ func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bo
|
|||||||
cachedAddress netip.Addr
|
cachedAddress netip.Addr
|
||||||
cached bool
|
cached bool
|
||||||
)
|
)
|
||||||
c.saveAccess.RLock()
|
c.saveFakeIPAccess.RLock()
|
||||||
if !isIPv6 {
|
if !isIPv6 {
|
||||||
cachedAddress, cached = c.saveAddress4[domain]
|
cachedAddress, cached = c.saveAddress4[domain]
|
||||||
} else {
|
} else {
|
||||||
cachedAddress, cached = c.saveAddress6[domain]
|
cachedAddress, cached = c.saveAddress6[domain]
|
||||||
}
|
}
|
||||||
c.saveAccess.RUnlock()
|
c.saveFakeIPAccess.RUnlock()
|
||||||
if cached {
|
if cached {
|
||||||
return cachedAddress, true
|
return cachedAddress, true
|
||||||
}
|
}
|
||||||
|
|||||||
109
experimental/cachefile/rdrc.go
Normal file
109
experimental/cachefile/rdrc.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package cachefile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/bbolt"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bucketRDRC = []byte("rdrc2")
|
||||||
|
|
||||||
|
func (c *CacheFile) StoreRDRC() bool {
|
||||||
|
return c.storeRDRC
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CacheFile) RDRCTimeout() time.Duration {
|
||||||
|
return c.rdrcTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CacheFile) LoadRDRC(transportName string, qName string, qType uint16) (rejected bool) {
|
||||||
|
c.saveRDRCAccess.RLock()
|
||||||
|
rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName, qType}]
|
||||||
|
c.saveRDRCAccess.RUnlock()
|
||||||
|
if cached {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key := buf.Get(2 + len(qName))
|
||||||
|
binary.BigEndian.PutUint16(key, qType)
|
||||||
|
copy(key[2:], qName)
|
||||||
|
defer buf.Put(key)
|
||||||
|
var deleteCache bool
|
||||||
|
err := c.DB.View(func(tx *bbolt.Tx) error {
|
||||||
|
bucket := c.bucket(tx, bucketRDRC)
|
||||||
|
if bucket == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
bucket = bucket.Bucket([]byte(transportName))
|
||||||
|
if bucket == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
content := bucket.Get(key)
|
||||||
|
if content == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
expiresAt := time.Unix(int64(binary.BigEndian.Uint64(content)), 0)
|
||||||
|
if time.Now().After(expiresAt) {
|
||||||
|
deleteCache = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rejected = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if deleteCache {
|
||||||
|
c.DB.Update(func(tx *bbolt.Tx) error {
|
||||||
|
bucket := c.bucket(tx, bucketRDRC)
|
||||||
|
if bucket == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
bucket = bucket.Bucket([]byte(transportName))
|
||||||
|
if bucket == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return bucket.Delete(key)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) error {
|
||||||
|
return c.DB.Batch(func(tx *bbolt.Tx) error {
|
||||||
|
bucket, err := c.createBucket(tx, bucketRDRC)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bucket, err = bucket.CreateBucketIfNotExists([]byte(transportName))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key := buf.Get(2 + len(qName))
|
||||||
|
binary.BigEndian.PutUint16(key, qType)
|
||||||
|
copy(key[2:], qName)
|
||||||
|
defer buf.Put(key)
|
||||||
|
expiresAt := buf.Get(8)
|
||||||
|
defer buf.Put(expiresAt)
|
||||||
|
binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix()))
|
||||||
|
return bucket.Put(key, expiresAt)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger) {
|
||||||
|
saveKey := saveRDRCCacheKey{transportName, qName, qType}
|
||||||
|
c.saveRDRCAccess.Lock()
|
||||||
|
c.saveRDRC[saveKey] = true
|
||||||
|
c.saveRDRCAccess.Unlock()
|
||||||
|
go func() {
|
||||||
|
err := c.SaveRDRC(transportName, qName, qType)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("save RDRC: ", err)
|
||||||
|
}
|
||||||
|
c.saveRDRCAccess.Lock()
|
||||||
|
delete(c.saveRDRC, saveKey)
|
||||||
|
c.saveRDRCAccess.Unlock()
|
||||||
|
}()
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package experimental
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
@@ -27,11 +28,26 @@ func NewClashServer(ctx context.Context, router adapter.Router, logFactory log.O
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CalculateClashModeList(options option.Options) []string {
|
func CalculateClashModeList(options option.Options) []string {
|
||||||
var clashMode []string
|
var clashModes []string
|
||||||
clashMode = append(clashMode, extraClashModeFromRule(common.PtrValueOrDefault(options.Route).Rules)...)
|
clashModes = append(clashModes, extraClashModeFromRule(common.PtrValueOrDefault(options.Route).Rules)...)
|
||||||
clashMode = append(clashMode, extraClashModeFromDNSRule(common.PtrValueOrDefault(options.DNS).Rules)...)
|
clashModes = append(clashModes, extraClashModeFromDNSRule(common.PtrValueOrDefault(options.DNS).Rules)...)
|
||||||
clashMode = common.FilterNotDefault(common.Uniq(clashMode))
|
clashModes = common.FilterNotDefault(common.Uniq(clashModes))
|
||||||
return clashMode
|
predefinedOrder := []string{
|
||||||
|
"Rule", "Global", "Direct",
|
||||||
|
}
|
||||||
|
var newClashModes []string
|
||||||
|
for _, mode := range clashModes {
|
||||||
|
if !common.Contains(predefinedOrder, mode) {
|
||||||
|
newClashModes = append(newClashModes, mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(newClashModes)
|
||||||
|
for _, mode := range predefinedOrder {
|
||||||
|
if common.Contains(clashModes, mode) {
|
||||||
|
newClashModes = append(newClashModes, mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newClashModes
|
||||||
}
|
}
|
||||||
|
|
||||||
func extraClashModeFromRule(rules []option.Rule) []string {
|
func extraClashModeFromRule(rules []option.Rule) []string {
|
||||||
|
|||||||
@@ -308,10 +308,11 @@ func authentication(serverSecret string) func(next http.Handler) http.Handler {
|
|||||||
|
|
||||||
func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) {
|
func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
if redirect {
|
contentType := r.Header.Get("Content-Type")
|
||||||
http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect)
|
if !redirect || contentType == "application/json" {
|
||||||
} else {
|
|
||||||
render.JSON(w, r, render.M{"hello": "clash"})
|
render.JSON(w, r, render.M{"hello": "clash"})
|
||||||
|
} else {
|
||||||
|
http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
@@ -75,7 +74,7 @@ func (s *platformInterfaceStub) UsePlatformInterfaceGetter() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *platformInterfaceStub) Interfaces() ([]platform.NetworkInterface, error) {
|
func (s *platformInterfaceStub) Interfaces() ([]control.Interface, error) {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +82,10 @@ func (s *platformInterfaceStub) UnderNetworkExtension() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *platformInterfaceStub) IncludeAllNetworks() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (s *platformInterfaceStub) ClearDNSCache() {
|
func (s *platformInterfaceStub) ClearDNSCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +140,6 @@ func FormatConfig(configContent string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
json.NewEncoder(&buffer)
|
|
||||||
encoder := json.NewEncoder(&buffer)
|
encoder := json.NewEncoder(&buffer)
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
err = encoder.Encode(options)
|
err = encoder.Encode(options)
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ import (
|
|||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/logger"
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
"github.com/sagernet/sing/common/task"
|
"github.com/sagernet/sing/common/task"
|
||||||
|
|
||||||
mDNS "github.com/miekg/dns"
|
mDNS "github.com/miekg/dns"
|
||||||
@@ -25,9 +23,11 @@ type LocalDNSTransport interface {
|
|||||||
|
|
||||||
func RegisterLocalDNSTransport(transport LocalDNSTransport) {
|
func RegisterLocalDNSTransport(transport LocalDNSTransport) {
|
||||||
if transport == nil {
|
if transport == nil {
|
||||||
dns.RegisterTransport([]string{"local"}, dns.CreateLocalTransport)
|
dns.RegisterTransport([]string{"local"}, func(options dns.TransportOptions) (dns.Transport, error) {
|
||||||
|
return dns.NewLocalTransport(options), nil
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
dns.RegisterTransport([]string{"local"}, func(name string, ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
dns.RegisterTransport([]string{"local"}, func(options dns.TransportOptions) (dns.Transport, error) {
|
||||||
return &platformLocalDNSTransport{
|
return &platformLocalDNSTransport{
|
||||||
iif: transport,
|
iif: transport,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -69,7 +69,8 @@ func (p *platformLocalDNSTransport) Exchange(ctx context.Context, message *mDNS.
|
|||||||
context: ctx,
|
context: ctx,
|
||||||
}
|
}
|
||||||
var responseMessage *mDNS.Msg
|
var responseMessage *mDNS.Msg
|
||||||
return responseMessage, task.Run(ctx, func() error {
|
var group task.Group
|
||||||
|
group.Append0(func(ctx context.Context) error {
|
||||||
err = p.iif.Exchange(response, messageBytes)
|
err = p.iif.Exchange(response, messageBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -80,6 +81,11 @@ func (p *platformLocalDNSTransport) Exchange(ctx context.Context, message *mDNS.
|
|||||||
responseMessage = &response.message
|
responseMessage = &response.message
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
err = group.Run(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return responseMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) {
|
func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) {
|
||||||
@@ -96,7 +102,8 @@ func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, s
|
|||||||
context: ctx,
|
context: ctx,
|
||||||
}
|
}
|
||||||
var responseAddr []netip.Addr
|
var responseAddr []netip.Addr
|
||||||
return responseAddr, task.Run(ctx, func() error {
|
var group task.Group
|
||||||
|
group.Append0(func(ctx context.Context) error {
|
||||||
err := p.iif.Lookup(response, network, domain)
|
err := p.iif.Lookup(response, network, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -121,6 +128,11 @@ func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, s
|
|||||||
}*/
|
}*/
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
err := group.Run(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return responseAddr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Func interface {
|
type Func interface {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type PlatformInterface interface {
|
|||||||
UsePlatformInterfaceGetter() bool
|
UsePlatformInterfaceGetter() bool
|
||||||
GetInterfaces() (NetworkInterfaceIterator, error)
|
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||||
UnderNetworkExtension() bool
|
UnderNetworkExtension() bool
|
||||||
|
IncludeAllNetworks() bool
|
||||||
ReadWIFIState() *WIFIState
|
ReadWIFIState() *WIFIState
|
||||||
ClearDNSCache()
|
ClearDNSCache()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package platform
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
@@ -20,16 +19,10 @@ type Interface interface {
|
|||||||
UsePlatformDefaultInterfaceMonitor() bool
|
UsePlatformDefaultInterfaceMonitor() bool
|
||||||
CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
|
CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
|
||||||
UsePlatformInterfaceGetter() bool
|
UsePlatformInterfaceGetter() bool
|
||||||
Interfaces() ([]NetworkInterface, error)
|
Interfaces() ([]control.Interface, error)
|
||||||
UnderNetworkExtension() bool
|
UnderNetworkExtension() bool
|
||||||
|
IncludeAllNetworks() bool
|
||||||
ClearDNSCache()
|
ClearDNSCache()
|
||||||
ReadWIFIState() adapter.WIFIState
|
ReadWIFIState() adapter.WIFIState
|
||||||
process.Searcher
|
process.Searcher
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetworkInterface struct {
|
|
||||||
Index int
|
|
||||||
MTU int
|
|
||||||
Name string
|
|
||||||
Addresses []netip.Prefix
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (s *BoxService) Close() error {
|
|||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
return
|
return
|
||||||
case <-time.After(C.DefaultStopFatalTimeout):
|
case <-time.After(C.FatalStopTimeout):
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -192,14 +192,14 @@ func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
|
|||||||
return w.iif.UsePlatformInterfaceGetter()
|
return w.iif.UsePlatformInterfaceGetter()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *platformInterfaceWrapper) Interfaces() ([]platform.NetworkInterface, error) {
|
func (w *platformInterfaceWrapper) Interfaces() ([]control.Interface, error) {
|
||||||
interfaceIterator, err := w.iif.GetInterfaces()
|
interfaceIterator, err := w.iif.GetInterfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var interfaces []platform.NetworkInterface
|
var interfaces []control.Interface
|
||||||
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
|
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
|
||||||
interfaces = append(interfaces, platform.NetworkInterface{
|
interfaces = append(interfaces, control.Interface{
|
||||||
Index: int(netInterface.Index),
|
Index: int(netInterface.Index),
|
||||||
MTU: int(netInterface.MTU),
|
MTU: int(netInterface.MTU),
|
||||||
Name: netInterface.Name,
|
Name: netInterface.Name,
|
||||||
@@ -213,6 +213,10 @@ func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
|
|||||||
return w.iif.UnderNetworkExtension()
|
return w.iif.UnderNetworkExtension()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) IncludeAllNetworks() bool {
|
||||||
|
return w.iif.IncludeAllNetworks()
|
||||||
|
}
|
||||||
|
|
||||||
func (w *platformInterfaceWrapper) ClearDNSCache() {
|
func (w *platformInterfaceWrapper) ClearDNSCache() {
|
||||||
w.iif.ClearDNSCache()
|
w.iif.ClearDNSCache()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,25 +16,18 @@ func (s *BoxService) Pause() {
|
|||||||
if s.pauseTimer != nil {
|
if s.pauseTimer != nil {
|
||||||
s.pauseTimer.Stop()
|
s.pauseTimer.Stop()
|
||||||
}
|
}
|
||||||
s.pauseTimer = time.AfterFunc(time.Minute, s.pause)
|
s.pauseTimer = time.AfterFunc(3*time.Second, s.ResetNetwork)
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BoxService) pause() {
|
|
||||||
s.pauseAccess.Lock()
|
|
||||||
defer s.pauseAccess.Unlock()
|
|
||||||
s.pauseManager.DevicePause()
|
|
||||||
_ = s.instance.Router().ResetNetwork()
|
|
||||||
s.pauseTimer = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BoxService) Wake() {
|
func (s *BoxService) Wake() {
|
||||||
_ = s.instance.Router().ResetNetwork()
|
|
||||||
s.pauseAccess.Lock()
|
s.pauseAccess.Lock()
|
||||||
defer s.pauseAccess.Unlock()
|
defer s.pauseAccess.Unlock()
|
||||||
if s.pauseTimer != nil {
|
if s.pauseTimer != nil {
|
||||||
s.pauseTimer.Stop()
|
s.pauseTimer.Stop()
|
||||||
s.pauseTimer = nil
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
s.pauseManager.DeviceWake()
|
s.pauseTimer = time.AfterFunc(3*time.Minute, s.ResetNetwork)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BoxService) ResetNetwork() {
|
||||||
|
_ = s.instance.Router().ResetNetwork()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/common/humanize"
|
"github.com/sagernet/sing-box/common/humanize"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
_ "github.com/sagernet/sing-box/include"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user