Compare commits

..

31 Commits

Author SHA1 Message Date
世界
e458398bb2 documentation: Bump version 2023-12-21 10:51:57 +08:00
世界
a5d324177b documentation: Update package managers 2023-12-21 10:50:32 +08:00
世界
34d5441d56 documentation: Fix link format 2023-12-21 10:50:32 +08:00
世界
9713dfb29c Fix missing UDP timeout for QUIC protocols 2023-12-21 10:50:27 +08:00
世界
c0483a2b37 Migrate udp_timeout from seconds to duration format 2023-12-21 10:50:27 +08:00
世界
6fe582fcd7 Avoid nested direct outbound usage 2023-12-21 10:50:27 +08:00
世界
081c45b9d7 Add loopback detect for direct outbound 2023-12-21 10:50:27 +08:00
世界
4e02b9ea94 Fix missing handshake timeout for multiplex 2023-12-21 10:50:21 +08:00
世界
0b2023660b Fix DNS dial context 2023-12-21 10:50:18 +08:00
世界
dee6fffa23 Make generated files have SUDO_USER's permissions if possible. 2023-12-21 10:49:02 +08:00
世界
26d29761df Refactor inbound/outbound options struct 2023-12-21 10:49:02 +08:00
世界
4e4d220bbe Improve configuration merge 2023-12-21 10:49:02 +08:00
世界
d38336bec4 Update uTLS to 1.5.4 2023-12-21 10:49:02 +08:00
世界
de4f167402 Update tfo-go 2023-12-21 10:49:02 +08:00
世界
b9439b8fbd Update gomobile and add tag 2023-12-21 10:49:02 +08:00
世界
817be7af6e Update cloudflare-tls to go1.21.5 2023-12-21 10:49:02 +08:00
世界
f57e98dbb0 Remove unnecessary context wrappers 2023-12-21 10:49:02 +08:00
世界
47213f0616 Improve read wait interface &
Refactor Authenticator interface to struct &
Update smux &
Update gVisor to 20231204.0 &
Update wireguard-go &
Add GSO support for TUN/WireGuard &
Fix router pre-start &
Fix bind forwarder to interface for systems stack
2023-12-21 10:48:41 +08:00
世界
2f4f4e18ee Make type check strict 2023-12-18 22:26:02 +08:00
世界
bc2d73b2d6 Remove comparable limit for Listable 2023-12-18 22:26:01 +08:00
世界
abd4d8b367 Avoid opening log output before start &
Replace tracing logs with task monitor
2023-12-18 22:26:01 +08:00
世界
f998ccecde Update documentation 2023-12-18 22:26:01 +08:00
世界
fc9804b20f Add idle_timeout for URLTest outbound 2023-12-18 22:26:01 +08:00
世界
d1ad342cb0 Skip internal fake-ip queries 2023-12-18 22:26:01 +08:00
世界
80cc0cd5db Migrate contentjson and badjson to library &
Add omitempty in format
2023-12-18 22:25:54 +08:00
世界
3041f34dfa Update documentation 2023-12-18 22:25:54 +08:00
世界
3a9b787a6e Independent source_ip_is_private and ip_is_private rules 2023-12-18 22:25:53 +08:00
世界
bb70e8267e Add rule-set 2023-12-18 22:25:53 +08:00
世界
411f02ee4f Update buffer usage 2023-12-18 22:25:53 +08:00
世界
340e74eed4 Allow nested logical rules 2023-12-18 22:25:53 +08:00
世界
ad93b45021 Migrate to independent cache file 2023-12-18 22:25:53 +08:00
177 changed files with 1468 additions and 3026 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
github: nekohasekai

View File

@@ -61,28 +61,7 @@ body:
attributes:
label: Logs
description: |-
In addition, if you encounter a crash with the graphical client, please also provide crash logs.
If you encounter a crash with the graphical client, please provide crash logs.
For Apple platform clients, please check `Settings - View Service Log` for crash logs.
For the Android client, please check the `/sdcard/Android/data/io.nekohasekai.sfa/files/stderr.log` file for crash logs.
render: shell
- type: checkboxes
id: supporter
attributes:
label: Supporter
options:
- label: I am a [sponsor](https://github.com/sponsors/nekohasekai/)
- type: checkboxes
attributes:
label: Integrity requirements
description: |-
Please check all of the following options to prove that you have read and understood the requirements, otherwise this issue will be closed.
Sing-box is not a project aimed to please users who can't make any meaningful contributions and gain unethical influence. If you deceive here to deliberately waste the time of the developers, you will be permanently blocked.
options:
- label: I confirm that I have read the documentation, understand the meaning of all the configuration items I wrote, and did not pile up seemingly useful options or default values.
required: true
- label: I confirm that I have provided the server and client configuration files and process that can be reproduced locally, instead of a complicated client configuration file that has been stripped of sensitive data.
required: true
- label: I confirm that I have provided the simplest configuration that can be used to reproduce the error I reported, instead of depending on remote servers, TUN, graphical interface clients, or other closed-source software.
required: true
- label: I confirm that I have provided the complete configuration files and logs, rather than just providing parts I think are useful out of confidence in my own intelligence.
required: true
render: shell

View File

@@ -61,28 +61,21 @@ body:
attributes:
label: 日志
description: |-
此外,如果您遭遇图形界面应用程序崩溃,请附加提供崩溃日志。
如果您遭遇图形界面应用程序崩溃,请提供崩溃日志。
对于 Apple 平台图形客户端程序,请检查 `Settings - View Service Log` 以导出崩溃日志。
对于 Android 图形客户端程序,请检查 `/sdcard/Android/data/io.nekohasekai.sfa/files/stderr.log` 文件以导出崩溃日志。
render: shell
- type: checkboxes
id: supporter
attributes:
label: 支持我们
options:
- label: 我已经 [赞助](https://github.com/sponsors/nekohasekai/)
- type: checkboxes
attributes:
label: 完整性要求
description: |-
请勾选以下所有选项以证明您已经阅读并理解了以下要求,否则该 issue 将被关闭。
sing-box 不是讨好无法作出任何意义上的贡献的最终用户并获取非道德影响力的项目,如果您在此处欺骗以故意浪费开发者的时间,您将被永久封锁。
description: 我保证我提供了完整的可以在本地重现该问题的服务器、客户端配置文件与流程,而不是一个脱敏的复杂客户端配置文件,否则该 issue 将被关闭。
options:
- label: 我保证阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值。
required: true
- label: 我保证提供了可以在本地重现该问题的服务器、客户端配置文件与流程,而不是一个脱敏的复杂客户端配置文件。
required: true
- label: 我保证提供了可用于重现我报告的错误的最简配置而不是依赖远程服务器、TUN、图形界面客户端或者其他闭源软件。
required: true
- label: 我保证提供了完整的配置文件与日志,而不是出于对自身智力的自信而仅提供了部分认为有用的部分。
- label: 我保证
required: true
- type: checkboxes
attributes:
label: 负责性要求
description: 我保证我阅读了文档,了解所有我编写的配置文件项的含义,而不是大量堆砌看似有用的选项或默认值,否则该 issue 将被关闭。
options:
- label: 我保证
required: true

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
PROJECTS=$(dirname "$0")/../..
function updateClient() {
pushd clients/$1
git fetch
git reset FETCH_HEAD --hard
popd
git add clients/$1
}
updateClient "apple"
updateClient "android"

View File

@@ -25,10 +25,22 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
fetch-depth: 0
- name: Get latest go version
id: version
run: |
echo go_version=$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') >> $GITHUB_OUTPUT
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.22
go-version: ${{ steps.version.outputs.go_version }}
- name: Add cache to Go proxy
run: |
version=`git rev-parse HEAD`
mkdir build
pushd build
go mod init build
go get -v github.com/sagernet/sing-box@$version
popd
continue-on-error: true
- name: Run Test
run: |
@@ -44,9 +56,9 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.18
go-version: 1.18.10
- name: Cache go module
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
@@ -64,33 +76,13 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.20
go-version: 1.20.7
- name: Cache go module
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
key: go120-${{ hashFiles('**/go.sum') }}
- name: Run Test
run: make ci_build_go120
build_go121:
name: Debug build (Go 1.21)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.21
- name: Cache go module
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
key: go121-${{ hashFiles('**/go.sum') }}
key: go118-${{ hashFiles('**/go.sum') }}
- name: Run Test
run: make ci_build
cross:
@@ -196,7 +188,8 @@ jobs:
- name: freebsd-arm64
goos: freebsd
goarch: arm64
fail-fast: true
fail-fast: false
runs-on: ubuntu-latest
env:
GOOS: ${{ matrix.goos }}
@@ -211,10 +204,19 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
fetch-depth: 0
- name: Get latest go version
id: version
run: |
echo go_version=$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') >> $GITHUB_OUTPUT
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.21
go-version: ${{ steps.version.outputs.go_version }}
- name: Build
id: build
run: make
run: make
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: sing-box-${{ matrix.name }}
path: sing-box*

View File

@@ -1,10 +1,9 @@
name: Build Docker Images
on:
release:
types:
- released
workflow_dispatch:
inputs:
tag:
description: "The tag version you want to build"
jobs:
build:
runs-on: ubuntu-latest
@@ -26,6 +25,15 @@ jobs:
uses: docker/metadata-action@v5
with:
images: ghcr.io/sagernet/sing-box
- name: Get tag to build
id: tag
run: |
echo "latest=ghcr.io/sagernet/sing-box:latest" >> $GITHUB_OUTPUT
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
echo "versioned=ghcr.io/sagernet/sing-box:${{ github.ref_name }}" >> $GITHUB_OUTPUT
else
echo "versioned=ghcr.io/sagernet/sing-box:${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
fi
- name: Build and release Docker images
uses: docker/build-push-action@v5
with:
@@ -34,6 +42,6 @@ jobs:
build-args: |
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
tags: |
ghcr.io/sagernet/sing-box:latest
ghcr.io/sagernet/sing-box:${{ github.ref_name }}
${{ steps.tag.outputs.latest }}
${{ steps.tag.outputs.versioned }}
push: true

View File

@@ -25,12 +25,16 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
fetch-depth: 0
- name: Get latest go version
id: version
run: |
echo go_version=$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') >> $GITHUB_OUTPUT
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.22
go-version: ${{ steps.version.outputs.go_version }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --timeout=30m

View File

@@ -1,37 +0,0 @@
name: Release to Linux repository
on:
release:
types:
- published
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.22
- name: Extract signing key
run: |-
mkdir -p $HOME/.gnupg
cat > $HOME/.gnupg/sagernet.key <<EOF
${{ secrets.GPG_KEY }}
EOF
- name: Publish release
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser-pro
version: latest
args: release -f .goreleaser.fury.yaml --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
NFPM_KEY_PATH: ${{ env.Home }}/.gnupg/sagernet.key
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}

6
.gitmodules vendored
View File

@@ -1,6 +0,0 @@
[submodule "clients/apple"]
path = clients/apple
url = https://github.com/SagerNet/sing-box-for-apple.git
[submodule "clients/android"]
path = clients/android
url = https://github.com/SagerNet/sing-box-for-android.git

View File

@@ -1,87 +0,0 @@
project_name: sing-box
builds:
- id: main
main: ./cmd/sing-box
flags:
- -v
- -trimpath
ldflags:
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
tags:
- with_gvisor
- with_quic
- with_dhcp
- with_wireguard
- with_ech
- with_utls
- with_reality_server
- with_acme
- with_clash_api
env:
- CGO_ENABLED=0
targets:
- linux_386
- linux_amd64_v1
- linux_arm64
- linux_arm_7
- linux_s390x
- linux_riscv64
mod_timestamp: '{{ .CommitTimestamp }}'
snapshot:
name_template: "{{ .Version }}.{{ .ShortCommit }}"
nfpms:
- &template
id: package
package_name: sing-box
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
builds:
- main
vendor: sagernet
homepage: https://sing-box.sagernet.org/
maintainer: nekohasekai <contact-git@sekai.icu>
description: The universal proxy platform.
license: GPLv3 or later
formats:
- deb
- rpm
priority: extra
contents:
- src: release/config/config.json
dst: /etc/sing-box/config.json
type: config
- src: release/config/sing-box.service
dst: /usr/lib/systemd/system/sing-box.service
- src: release/config/sing-box@.service
dst: /usr/lib/systemd/system/sing-box@.service
- src: 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:
- sing-box-beta
- id: package_beta
<<: *template
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:
- deb
- rpm
conflicts:
- sing-box
release:
disable: true
furies:
- account: sagernet
ids:
- package
disable: "{{ not (not .Prerelease) }}"
- account: sagernet
ids:
- package_beta
disable: "{{ not .Prerelease }}"

View File

@@ -1,11 +1,14 @@
project_name: sing-box
builds:
- &template
id: main
- id: main
main: ./cmd/sing-box
flags:
- -v
- -trimpath
asmflags:
- all=-trimpath={{.Env.GOPATH}}
gcflags:
- all=-trimpath={{.Env.GOPATH}}
ldflags:
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
tags:
@@ -27,35 +30,65 @@ builds:
- linux_arm64
- linux_arm_7
- linux_s390x
- linux_riscv64
- windows_amd64_v1
- windows_amd64_v3
- windows_386
- windows_arm64
- darwin_amd64_v1
- darwin_amd64_v3
- darwin_arm64
mod_timestamp: '{{ .CommitTimestamp }}'
- id: legacy
<<: *template
main: ./cmd/sing-box
flags:
- -v
- -trimpath
asmflags:
- all=-trimpath={{.Env.GOPATH}}
gcflags:
- all=-trimpath={{.Env.GOPATH}}
ldflags:
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
tags:
- with_gvisor
- with_quic
- with_dhcp
- with_wireguard
- with_ech
- with_utls
- with_reality_server
- with_acme
- with_clash_api
env:
- CGO_ENABLED=0
- GOROOT={{ .Env.GOPATH }}/go1.20.14
gobinary: "{{ .Env.GOPATH }}/go1.20.14/bin/go"
- GOROOT=/nix/store/kg6i737jjqs923jcijnm003h68c1dghj-go-1.20.11/share/go
gobinary: /nix/store/kg6i737jjqs923jcijnm003h68c1dghj-go-1.20.11/bin/go
targets:
- windows_amd64_v1
- windows_386
- darwin_amd64_v1
mod_timestamp: '{{ .CommitTimestamp }}'
- id: android
<<: *template
main: ./cmd/sing-box
flags:
- -v
- -trimpath
asmflags:
- all=-trimpath={{.Env.GOPATH}}
gcflags:
- all=-trimpath={{.Env.GOPATH}}
ldflags:
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
tags:
- with_gvisor
- with_quic
- with_dhcp
- with_wireguard
- with_ech
- with_utls
- with_reality_server
- with_acme
- with_clash_api
env:
- CGO_ENABLED=1
overrides:
@@ -63,8 +96,8 @@ builds:
goarch: arm
goarm: 7
env:
- CC=armv7a-linux-androideabi21-clang
- CXX=armv7a-linux-androideabi21-clang++
- CC=armv7a-linux-androideabi19-clang
- CXX=armv7a-linux-androideabi19-clang++
- goos: android
goarch: arm64
env:
@@ -73,8 +106,8 @@ builds:
- goos: android
goarch: 386
env:
- CC=i686-linux-android21-clang
- CXX=i686-linux-android21-clang++
- CC=i686-linux-android19-clang
- CXX=i686-linux-android19-clang++
- goos: android
goarch: amd64
goamd64: v1
@@ -86,11 +119,11 @@ builds:
- android_arm64
- android_386
- android_amd64
mod_timestamp: '{{ .CommitTimestamp }}'
snapshot:
name_template: "{{ .Version }}.{{ .ShortCommit }}"
archives:
- &template
id: archive
- id: archive
builds:
- main
- android
@@ -103,16 +136,20 @@ archives:
- LICENSE
name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
- id: archive-legacy
<<: *template
builds:
- legacy
format: tar.gz
format_overrides:
- goos: windows
format: zip
wrap_in_directory: true
files:
- LICENSE
name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}-legacy'
nfpms:
- id: package
package_name: sing-box
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
builds:
- main
vendor: sagernet
homepage: https://sing-box.sagernet.org/
maintainer: nekohasekai <contact-git@sekai.icu>
@@ -128,27 +165,11 @@ nfpms:
dst: /etc/sing-box/config.json
type: config
- src: release/config/sing-box.service
dst: /usr/lib/systemd/system/sing-box.service
dst: /etc/systemd/system/sing-box.service
- src: release/config/sing-box@.service
dst: /usr/lib/systemd/system/sing-box@.service
dst: /etc/systemd/system/sing-box@.service
- src: 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 }}"
overrides:
deb:
conflicts:
- sing-box-beta
rpm:
conflicts:
- sing-box-beta
source:
enabled: false
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
@@ -162,10 +183,6 @@ release:
github:
owner: SagerNet
name: sing-box
name_template: '{{ if .IsSnapshot }}{{ nightly }}{{ else }}{{ .Version }}{{ end }}'
draft: true
prerelease: auto
mode: replace
ids:
- archive
- package
skip_upload: true
mode: replace

View File

@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
LABEL maintainer="nekohasekai <contact-git@sekai.icu>"
COPY . /go/src/github.com/sagernet/sing-box
WORKDIR /go/src/github.com/sagernet/sing-box

View File

@@ -1,9 +1,8 @@
NAME = sing-box
COMMIT = $(shell git rev-parse --short HEAD)
TAGS_GO118 = with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api
TAGS_GO120 = with_quic,with_utls
TAGS_GO121 = with_ech
TAGS ?= $(TAGS_GO118),$(TAGS_GO120),$(TAGS_GO121)
TAGS_GO120 = with_quic,with_ech,with_utls
TAGS ?= $(TAGS_GO118),$(TAGS_GO120)
TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server
GOHOSTOS = $(shell go env GOHOSTOS)
@@ -15,7 +14,7 @@ MAIN_PARAMS = $(PARAMS) -tags $(TAGS)
MAIN = ./cmd/sing-box
PREFIX ?= $(shell go env GOPATH)
.PHONY: test release docs build
.PHONY: test release docs
build:
go build $(MAIN_PARAMS) $(MAIN)
@@ -24,10 +23,6 @@ ci_build_go118:
go build $(PARAMS) $(MAIN)
go build $(PARAMS) -tags "$(TAGS_GO118)" $(MAIN)
ci_build_go120:
go build $(PARAMS) $(MAIN)
go build $(PARAMS) -tags "$(TAGS_GO118),$(TAGS_GO120)" $(MAIN)
ci_build:
go build $(PARAMS) $(MAIN)
go build $(MAIN_PARAMS) $(MAIN)
@@ -64,35 +59,25 @@ proto_install:
go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
release:
go run ./cmd/internal/build goreleaser release --clean --skip publish
go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1
mkdir dist/release
mv dist/*.tar.gz \
dist/*.zip \
dist/*.deb \
dist/*.rpm \
dist/*_amd64.pkg.tar.zst \
dist/*_amd64v3.pkg.tar.zst \
dist/*_arm64.pkg.tar.zst \
dist/release
mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/*.pkg.tar.zst dist/release
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
rm -r dist/release
release_repo:
go run ./cmd/internal/build goreleaser release -f .goreleaser.fury.yaml --clean
release_install:
go install -v github.com/goreleaser/goreleaser@latest
go install -v github.com/tcnksm/ghr@latest
update_android_version:
go run ./cmd/internal/update_android_version
build_android:
cd ../sing-box-for-android && ./gradlew :app:clean :app:assemblePlayRelease :app:assembleOtherRelease && ./gradlew --stop
cd ../sing-box-for-android && ./gradlew :app:assemblePlayRelease && ./gradlew --stop
upload_android:
mkdir -p dist/release_android
cp ../sing-box-for-android/app/build/outputs/apk/play/release/*.apk dist/release_android
cp ../sing-box-for-android/app/build/outputs/apk/other/release/*-universal.apk dist/release_android
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release_android
rm -rf dist/release_android
@@ -193,8 +178,8 @@ lib:
go run ./cmd/internal/build_libbox -target ios
lib_install:
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.3
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.3
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.1
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.1
docs:
mkdocs serve

View File

@@ -9,7 +9,6 @@ import (
"time"
"github.com/sagernet/sing-box/common/urltest"
"github.com/sagernet/sing-dns"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/rw"
)
@@ -31,9 +30,6 @@ type CacheFile interface {
StoreFakeIP() bool
FakeIPStorage
StoreRDRC() bool
dns.RDRCStore
LoadMode() string
StoreMode(mode string) error
LoadSelected(group string) string

View File

@@ -51,13 +51,11 @@ type InboundContext struct {
// rule cache
IPCIDRMatchSource bool
SourceAddressMatch bool
SourcePortMatch bool
DestinationAddressMatch bool
DestinationPortMatch bool
DidMatch bool
IgnoreDestinationIPCIDRMatch bool
IPCIDRMatchSource bool
SourceAddressMatch bool
SourcePortMatch bool
DestinationAddressMatch bool
DestinationPortMatch bool
}
func (c *InboundContext) ResetRuleCache() {
@@ -66,7 +64,6 @@ func (c *InboundContext) ResetRuleCache() {
c.SourcePortMatch = false
c.DestinationAddressMatch = false
c.DestinationPortMatch = false
c.DidMatch = false
}
type inboundContextKey struct{}

View File

@@ -33,8 +33,6 @@ type Router interface {
RuleSet(tag string) (RuleSet, bool)
NeedWIFIState() bool
Exchange(ctx context.Context, message *mdns.Msg) (*mdns.Msg, error)
Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error)
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
@@ -71,7 +69,6 @@ func RouterFromContext(ctx context.Context) Router {
type HeadlessRule interface {
Match(metadata *InboundContext) bool
String() string
}
type Rule interface {
@@ -80,15 +77,13 @@ type Rule interface {
Type() string
UpdateGeosite() error
Outbound() string
String() string
}
type DNSRule interface {
Rule
DisableCache() bool
RewriteTTL() *uint32
ClientSubnet() *netip.Addr
WithAddressLimit() bool
MatchAddressLimit(metadata *InboundContext) bool
}
type RuleSet interface {
@@ -102,7 +97,6 @@ type RuleSet interface {
type RuleSetMetadata struct {
ContainsProcessRule bool
ContainsWIFIRule bool
ContainsIPCIDRRule bool
}
type RuleSetStartContext interface {

4
box.go
View File

@@ -235,7 +235,7 @@ func (s *Box) Start() error {
}
func (s *Box) preStart() error {
monitor := taskmonitor.New(s.logger, C.StartTimeout)
monitor := taskmonitor.New(s.logger, C.DefaultStartTimeout)
monitor.Start("start logger")
err := s.logFactory.Start()
monitor.Finish()
@@ -331,7 +331,7 @@ func (s *Box) Close() error {
default:
close(s.done)
}
monitor := taskmonitor.New(s.logger, C.StopTimeout)
monitor := taskmonitor.New(s.logger, C.DefaultStopTimeout)
var errors error
for serviceName, service := range s.postServices {
monitor.Start("close ", serviceName)

View File

@@ -12,7 +12,7 @@ import (
)
func (s *Box) startOutbounds() error {
monitor := taskmonitor.New(s.logger, C.StartTimeout)
monitor := taskmonitor.New(s.logger, C.DefaultStartTimeout)
outboundTags := make(map[adapter.Outbound]string)
outbounds := make(map[string]adapter.Outbound)
for i, outboundToStart := range s.outbounds {

Submodule clients/android deleted from 288a6f34db

Submodule clients/apple deleted from 1c5bc23a25

View File

@@ -46,13 +46,13 @@ var (
func init() {
sharedFlags = append(sharedFlags, "-trimpath")
sharedFlags = append(sharedFlags, "-buildvcs=false")
sharedFlags = append(sharedFlags, "-ldflags")
currentTag, err := build_shared.ReadTag()
if err != nil {
currentTag = "unknown"
}
sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=")
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag)
sharedFlags = append(sharedFlags, "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -s -w -buildid=")
debugFlags = append(debugFlags, "-X github.com/sagernet/sing-box/constant.Version="+currentTag)
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_ech", "with_utls", "with_clash_api")
iosTags = append(iosTags, "with_dhcp", "with_low_memory", "with_conntrack")

View File

@@ -11,9 +11,7 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/common/shell"
)
var (
@@ -30,7 +28,7 @@ func FindSDK() {
}
for _, path := range searchPath {
path = os.ExpandEnv(path)
if rw.FileExists(filepath.Join(path, "licenses", "android-sdk-license")) {
if rw.FileExists(path + "/licenses/android-sdk-license") {
androidSDKPath = path
break
}
@@ -42,14 +40,6 @@ func FindSDK() {
log.Fatal("android NDK not found")
}
javaVersion, err := shell.Exec("java", "--version").ReadOutput()
if err != nil {
log.Fatal(E.Cause(err, "check java version"))
}
if !strings.Contains(javaVersion, "openjdk 17") {
log.Fatal("java version should be openjdk 17")
}
os.Setenv("ANDROID_HOME", androidSDKPath)
os.Setenv("ANDROID_SDK_HOME", androidSDKPath)
os.Setenv("ANDROID_NDK_HOME", androidNDKPath)
@@ -58,13 +48,11 @@ func FindSDK() {
}
func findNDK() bool {
const fixedVersion = "26.2.11394342"
const versionFile = "source.properties"
if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.FileExists(filepath.Join(fixedPath, versionFile)) {
androidNDKPath = fixedPath
if rw.FileExists(androidSDKPath + "/ndk/25.1.8937393") {
androidNDKPath = androidSDKPath + "/ndk/25.1.8937393"
return true
}
ndkVersions, err := os.ReadDir(filepath.Join(androidSDKPath, "ndk"))
ndkVersions, err := os.ReadDir(androidSDKPath + "/ndk")
if err != nil {
return false
}
@@ -85,10 +73,8 @@ func findNDK() bool {
return true
})
for _, versionName := range versionNames {
currentNDKPath := filepath.Join(androidSDKPath, "ndk", versionName)
if rw.FileExists(filepath.Join(androidSDKPath, versionFile)) {
androidNDKPath = currentNDKPath
log.Warn("reproducibility warning: using NDK version " + versionName + " instead of " + fixedVersion)
if rw.FileExists(androidSDKPath + "/ndk/" + versionName) {
androidNDKPath = androidSDKPath + "/ndk/" + versionName
return true
}
}
@@ -99,14 +85,8 @@ var GoBinPath string
func FindMobile() {
goBin := filepath.Join(build.Default.GOPATH, "bin")
if runtime.GOOS == "windows" {
if !rw.FileExists(filepath.Join(goBin, "gobind.exe")) {
log.Fatal("missing gomobile installation")
}
} else {
if !rw.FileExists(filepath.Join(goBin, "gobind")) {
log.Fatal("missing gomobile installation")
}
if !rw.FileExists(goBin + "/" + "gobind") {
log.Fatal("missing gomobile installation")
}
GoBinPath = goBin
}

View File

@@ -3,7 +3,6 @@ package main
import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
@@ -19,46 +18,34 @@ func main() {
log.Fatal(err)
}
common.Must(os.Chdir(androidPath))
localProps := common.Must1(os.ReadFile("version.properties"))
localProps := common.Must1(os.ReadFile("local.properties"))
var propsList [][]string
for _, propLine := range strings.Split(string(localProps), "\n") {
propsList = append(propsList, strings.Split(propLine, "="))
}
var (
versionUpdated bool
goVersionUpdated bool
)
for _, propPair := range propsList {
switch propPair[0] {
case "VERSION_NAME":
if propPair[1] != newVersion.String() {
versionUpdated = true
propPair[1] = newVersion.String()
log.Info("updated version to ", newVersion.String())
}
case "GO_VERSION":
if propPair[1] != runtime.Version() {
goVersionUpdated = true
propPair[1] = runtime.Version()
log.Info("updated Go version to ", runtime.Version())
if propPair[0] == "VERSION_NAME" {
if propPair[1] == newVersion.String() {
log.Info("version not changed")
return
}
propPair[1] = newVersion.String()
log.Info("updated version to ", newVersion.String())
}
}
if !(versionUpdated || goVersionUpdated) {
log.Info("version not changed")
return
}
for _, propPair := range propsList {
switch propPair[0] {
case "VERSION_CODE":
versionCode := common.Must1(strconv.ParseInt(propPair[1], 10, 64))
propPair[1] = strconv.Itoa(int(versionCode + 1))
log.Info("updated version code to ", propPair[1])
case "RELEASE_NOTES":
propPair[1] = "sing-box " + newVersion.String()
}
}
var newProps []string
for _, propPair := range propsList {
newProps = append(newProps, strings.Join(propPair, "="))
}
common.Must(os.WriteFile("version.properties", []byte(strings.Join(newProps, "\n")), 0o644))
common.Must(os.WriteFile("local.properties", []byte(strings.Join(newProps, "\n")), 0o644))
}

View File

@@ -1,6 +1,7 @@
package main
import (
"encoding/json"
"io"
"os"
@@ -8,7 +9,6 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/json"
"github.com/spf13/cobra"
)

View File

@@ -47,14 +47,10 @@ func compileRuleSet(sourcePath string) error {
return err
}
}
content, err := io.ReadAll(reader)
if err != nil {
return err
}
plainRuleSet, err := json.UnmarshalExtended[option.PlainRuleSetCompat](content)
if err != nil {
return err
}
decoder := json.NewDecoder(json.NewCommentFilter(reader))
decoder.DisallowUnknownFields()
var plainRuleSet option.PlainRuleSetCompat
err = decoder.Decode(&plainRuleSet)
if err != nil {
return err
}

View File

@@ -50,14 +50,18 @@ func formatRuleSet(sourcePath string) error {
if err != nil {
return err
}
plainRuleSet, err := json.UnmarshalExtended[option.PlainRuleSetCompat](content)
decoder := json.NewDecoder(json.NewCommentFilter(bytes.NewReader(content)))
decoder.DisallowUnknownFields()
var plainRuleSet option.PlainRuleSetCompat
err = decoder.Decode(&plainRuleSet)
if err != nil {
return err
}
ruleSet := plainRuleSet.Upgrade()
buffer := new(bytes.Buffer)
encoder := json.NewEncoder(buffer)
encoder.SetIndent("", " ")
err = encoder.Encode(plainRuleSet)
err = encoder.Encode(ruleSet)
if err != nil {
return E.Cause(err, "encode config")
}

View File

@@ -1,86 +0,0 @@
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"
"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("match rules.[", i, "]: "+currentRule.String())
}
}
return nil
}

View File

@@ -199,7 +199,7 @@ func run() error {
}
func closeMonitor(ctx context.Context) {
time.Sleep(C.FatalStopTimeout)
time.Sleep(C.DefaultStopFatalTimeout)
select {
case <-ctx.Done():
return

View File

@@ -4,8 +4,6 @@ package badtls
import (
"bytes"
"context"
"net"
"os"
"reflect"
"sync"
@@ -20,32 +18,20 @@ import (
var _ N.ReadWaiter = (*ReadWaitConn)(nil)
type ReadWaitConn struct {
tls.Conn
halfAccess *sync.Mutex
rawInput *bytes.Buffer
input *bytes.Reader
hand *bytes.Buffer
readWaitOptions N.ReadWaitOptions
tlsReadRecord func() error
tlsHandlePostHandshakeMessage func() error
*tls.STDConn
halfAccess *sync.Mutex
rawInput *bytes.Buffer
input *bytes.Reader
hand *bytes.Buffer
readWaitOptions N.ReadWaitOptions
}
func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) {
var (
loaded bool
tlsReadRecord func() error
tlsHandlePostHandshakeMessage func() error
)
for _, tlsCreator := range tlsRegistry {
loaded, tlsReadRecord, tlsHandlePostHandshakeMessage = tlsCreator(conn)
if loaded {
break
}
}
if !loaded {
stdConn, isSTDConn := conn.(*tls.STDConn)
if !isSTDConn {
return nil, os.ErrInvalid
}
rawConn := reflect.Indirect(reflect.ValueOf(conn))
rawConn := reflect.Indirect(reflect.ValueOf(stdConn))
rawHalfConn := rawConn.FieldByName("in")
if !rawHalfConn.IsValid() || rawHalfConn.Kind() != reflect.Struct {
return nil, E.New("badtls: invalid half conn")
@@ -71,13 +57,11 @@ func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) {
}
hand := (*bytes.Buffer)(unsafe.Pointer(rawHand.UnsafeAddr()))
return &ReadWaitConn{
Conn: conn,
halfAccess: halfAccess,
rawInput: rawInput,
input: input,
hand: hand,
tlsReadRecord: tlsReadRecord,
tlsHandlePostHandshakeMessage: tlsHandlePostHandshakeMessage,
STDConn: stdConn,
halfAccess: halfAccess,
rawInput: rawInput,
input: input,
hand: hand,
}, nil
}
@@ -87,19 +71,19 @@ func (c *ReadWaitConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy
}
func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
err = c.HandshakeContext(context.Background())
err = c.Handshake()
if err != nil {
return
}
c.halfAccess.Lock()
defer c.halfAccess.Unlock()
for c.input.Len() == 0 {
err = c.tlsReadRecord()
err = tlsReadRecord(c.STDConn)
if err != nil {
return
}
for c.hand.Len() > 0 {
err = c.tlsHandlePostHandshakeMessage()
err = tlsHandlePostHandshakeMessage(c.STDConn)
if err != nil {
return
}
@@ -116,7 +100,7 @@ func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
// recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
c.rawInput.Bytes()[0] == 21 {
_ = c.tlsReadRecord()
_ = tlsReadRecord(c.STDConn)
// return n, err // will be io.EOF on closeNotify
}
@@ -124,28 +108,8 @@ func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
return
}
func (c *ReadWaitConn) Upstream() any {
return c.Conn
}
//go:linkname tlsReadRecord crypto/tls.(*Conn).readRecord
func tlsReadRecord(c *tls.STDConn) error
var tlsRegistry []func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error)
func init() {
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
//go:linkname tlsHandlePostHandshakeMessage crypto/tls.(*Conn).handlePostHandshakeMessage
func tlsHandlePostHandshakeMessage(c *tls.STDConn) error

View File

@@ -1,31 +0,0 @@
//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

View File

@@ -1,31 +0,0 @@
//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

View File

@@ -63,9 +63,6 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
} else {
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
if options.UDPFragment != nil {
udpFragment = *options.UDPFragment

View File

@@ -6,21 +6,27 @@ import (
"sync"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type DetourDialer struct {
router adapter.Router
detour string
dialer N.Dialer
initOnce sync.Once
initErr error
router adapter.Router
detour string
allowNestedDirect bool
dialer N.Dialer
initOnce sync.Once
initErr error
}
func NewDetour(router adapter.Router, detour string) N.Dialer {
return &DetourDialer{router: router, detour: detour}
func NewDetour(router adapter.Router, detour string, allowNestedDirect bool) N.Dialer {
return &DetourDialer{
router: router,
detour: detour,
allowNestedDirect: allowNestedDirect,
}
}
func (d *DetourDialer) Start() error {
@@ -30,10 +36,17 @@ func (d *DetourDialer) Start() error {
func (d *DetourDialer) Dialer() (N.Dialer, error) {
d.initOnce.Do(func() {
var loaded bool
d.dialer, loaded = d.router.Outbound(d.detour)
var (
dialer adapter.Outbound
loaded bool
)
dialer, loaded = d.router.Outbound(d.detour)
if !loaded {
d.initErr = E.New("outbound detour not found: ", d.detour)
} else if !d.allowNestedDirect && dialer.Type() == C.TypeDirect {
d.initErr = E.New("using a direct outbound as a detour is illegal")
} else {
d.dialer = dialer
}
})
return d.dialer, d.initErr

View File

@@ -23,7 +23,7 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
return nil, err
}
} else {
dialer = NewDetour(router, options.Detour)
dialer = NewDetour(router, options.Detour, false)
}
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {

View File

@@ -80,7 +80,6 @@ func (c *slowOpenConn) Write(b []byte) (n int, err error) {
c.conn = nil
c.err = E.Cause(err, "dial tcp fast open")
}
n = len(b)
close(c.create)
return
}

View File

@@ -32,7 +32,3 @@ func (r *Reader) Lookup(addr netip.Addr) string {
}
return "unknown"
}
func (r *Reader) Close() error {
return r.reader.Close()
}

View File

@@ -223,7 +223,7 @@ func getExecPathFromPID(pid uint32) (string, error) {
r1, _, err := syscall.SyscallN(
procQueryFullProcessImageNameW.Addr(),
uintptr(h),
uintptr(0),
uintptr(1),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&size)),
)

View File

@@ -253,7 +253,7 @@ func writeDefaultRule(writer io.Writer, rule option.DefaultHeadlessRule) error {
if len(rule.SourceIPCIDR) > 0 {
err = writeRuleItemCIDR(writer, ruleItemSourceIPCIDR, rule.SourceIPCIDR)
if err != nil {
return E.Cause(err, "source_ip_cidr")
return E.Cause(err, "source_ipcidr")
}
}
if len(rule.IPCIDR) > 0 {

View File

@@ -105,16 +105,5 @@ func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Con
},
})
config = certmagic.New(cache, *config)
var tlsConfig *tls.Config
if acmeConfig.DisableTLSALPNChallenge || acmeConfig.DNS01Solver != nil {
tlsConfig = &tls.Config{
GetCertificate: config.GetCertificate,
}
} else {
tlsConfig = &tls.Config{
GetCertificate: config.GetCertificate,
NextProtos: []string{ACMETLS1Protocol},
}
}
return tlsConfig, &acmeWrapper{ctx: ctx, cfg: config, cache: cache, domain: options.Domain}, nil
return config.TLSConfig(), &acmeWrapper{ctx: ctx, cfg: config, cache: cache, domain: options.Domain}, nil
}

View File

@@ -1,3 +0,0 @@
package tls
const ACMETLS1Protocol = "acme-tls/1"

View File

@@ -39,19 +39,11 @@ func (c *STDServerConfig) SetServerName(serverName string) {
}
func (c *STDServerConfig) NextProtos() []string {
if c.acmeService != nil && len(c.config.NextProtos) > 1 && c.config.NextProtos[0] == ACMETLS1Protocol {
return c.config.NextProtos[1:]
} else {
return c.config.NextProtos
}
return c.config.NextProtos
}
func (c *STDServerConfig) SetNextProtos(nextProto []string) {
if c.acmeService != nil && len(c.config.NextProtos) > 1 && c.config.NextProtos[0] == ACMETLS1Protocol {
c.config.NextProtos = append(c.config.NextProtos[:1], nextProto...)
} else {
c.config.NextProtos = nextProto
}
c.config.NextProtos = nextProto
}
func (c *STDServerConfig) Config() (*STDConfig, error) {

View File

@@ -1,5 +0,0 @@
//go:build with_quic
package constant
const WithQUIC = true

View File

@@ -1,5 +0,0 @@
//go:build !with_quic
package constant
const WithQUIC = false

View File

@@ -3,18 +3,15 @@ package constant
import "time"
const (
TCPKeepAliveInitial = 10 * time.Minute
TCPKeepAliveInterval = 75 * time.Second
TCPTimeout = 5 * time.Second
ReadPayloadTimeout = 300 * time.Millisecond
DNSTimeout = 10 * time.Second
QUICTimeout = 30 * time.Second
STUNTimeout = 15 * time.Second
UDPTimeout = 5 * time.Minute
DefaultURLTestInterval = 3 * time.Minute
DefaultURLTestIdleTimeout = 30 * time.Minute
StartTimeout = 10 * time.Second
StopTimeout = 5 * time.Second
FatalStopTimeout = 10 * time.Second
FakeIPMetadataSaveInterval = 10 * time.Second
TCPTimeout = 5 * time.Second
ReadPayloadTimeout = 300 * time.Millisecond
DNSTimeout = 10 * time.Second
QUICTimeout = 30 * time.Second
STUNTimeout = 15 * time.Second
UDPTimeout = 5 * time.Minute
DefaultURLTestInterval = 3 * time.Minute
DefaultURLTestIdleTimeout = 30 * time.Minute
DefaultStartTimeout = 10 * time.Second
DefaultStopTimeout = 5 * time.Second
DefaultStopFatalTimeout = 10 * time.Second
)

View File

@@ -5,7 +5,6 @@ import (
"net/http/pprof"
"runtime"
"runtime/debug"
"strings"
"github.com/sagernet/sing-box/common/humanize"
"github.com/sagernet/sing-box/log"
@@ -48,20 +47,12 @@ func applyDebugListenOption(options option.DebugOptions) {
encoder.SetIndent("", " ")
encoder.Encode(memObject)
})
r.Route("/pprof", func(r chi.Router) {
r.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
if !strings.HasSuffix(request.URL.Path, "/") {
http.Redirect(writer, request, request.URL.Path+"/", http.StatusMovedPermanently)
} else {
pprof.Index(writer, request)
}
})
r.HandleFunc("/*", pprof.Index)
r.HandleFunc("/cmdline", pprof.Cmdline)
r.HandleFunc("/profile", pprof.Profile)
r.HandleFunc("/symbol", pprof.Symbol)
r.HandleFunc("/trace", pprof.Trace)
})
r.HandleFunc("/pprof", pprof.Index)
r.HandleFunc("/pprof/*", pprof.Index)
r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/pprof/profile", pprof.Profile)
r.HandleFunc("/pprof/symbol", pprof.Symbol)
r.HandleFunc("/pprof/trace", pprof.Trace)
})
debugHTTPServer = &http.Server{
Addr: options.Listen,

View File

@@ -1,5 +1,3 @@
//go:build linux || darwin
package box
import (

View File

@@ -1,4 +1,4 @@
//go:build !(linux || darwin)
//go:build !linux
package box

View File

@@ -2,302 +2,6 @@
icon: material/alert-decagram
---
#### 1.9.0-rc.11
* Fixes and improvements
#### 1.8.11
* Fixes and improvements
#### 1.8.10
* 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
* Fixes and improvements
#### 1.8.8
* 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
* 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
* 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
* Fixes and improvements
#### 1.8.4
* Fixes and improvements
#### 1.8.2
* Fixes and improvements
#### 1.8.1
* Fixes and improvements
#### 1.8.0
* Fixes and improvements
Important changes since 1.7:
* Migrate cache file from Clash API to independent options **1**
* Introducing [Rule Set](/configuration/rule-set/) **2**
* Add `sing-box geoip`, `sing-box geosite` and `sing-box rule-set` commands **3**
* Allow nested logical rules **4**
* Independent `source_ip_is_private` and `ip_is_private` rules **5**
* Add context to JSON decode error message **6**
* Reject internal fake-ip queries **7**
* Add GSO support for TUN and WireGuard system interface **8**
* Add `idle_timeout` for URLTest outbound **9**
* Add simple loopback detect
* Optimize memory usage of idle connections
* Update uTLS to 1.5.4 **10**
* Update dependencies **11**
**1**:
See [Cache File](/configuration/experimental/cache-file/) and
[Migration](/migration/#migrate-cache-file-from-clash-api-to-independent-options).
**2**:
Rule set is independent collections of rules that can be compiled into binaries to improve performance.
Compared to legacy GeoIP and Geosite resources,
it can include more types of rules, load faster,
use less memory, and update automatically.
See [Route#rule_set](/configuration/route/#rule_set),
[Route Rule](/configuration/route/rule/),
[DNS Rule](/configuration/dns/rule/),
[Rule Set](/configuration/rule-set/),
[Source Format](/configuration/rule-set/source-format/) and
[Headless Rule](/configuration/rule-set/headless-rule/).
For GEO resources migration, see [Migrate GeoIP to rule sets](/migration/#migrate-geoip-to-rule-sets) and
[Migrate Geosite to rule sets](/migration/#migrate-geosite-to-rule-sets).
**3**:
New commands manage GeoIP, Geosite and rule set resources, and help you migrate GEO resources to rule sets.
**4**:
Logical rules in route rules, DNS rules, and the new headless rule now allow nesting of logical rules.
**5**:
The `private` GeoIP country never existed and was actually implemented inside V2Ray.
Since GeoIP was deprecated, we made this rule independent, see [Migration](/migration/#migrate-geoip-to-rule-sets).
**6**:
JSON parse errors will now include the current key path.
Only takes effect when compiled with Go 1.21+.
**7**:
All internal DNS queries now skip DNS rules with `server` type `fakeip`,
and the default DNS server can no longer be `fakeip`.
This change is intended to break incorrect usage and essentially requires no action.
**8**:
See [TUN](/configuration/inbound/tun/) inbound and [WireGuard](/configuration/outbound/wireguard/) outbound.
**9**:
When URLTest is idle for a certain period of time, the scheduled delay test will be paused.
**10**:
Added some new [fingerprints](/configuration/shared/tls#utls).
Also, starting with this release, uTLS requires at least Go 1.20.
**11**:
Updated `cloudflare-tls`, `gomobile`, `smux`, `tfo-go` and `wireguard-go` to latest, `quic-go` to `0.40.1` and `gvisor`
to `20231204.0`
#### 1.8.0-rc.11
* Fixes and improvements
#### 1.7.8
* Fixes and improvements
#### 1.8.0-rc.10
* Fixes and improvements
#### 1.7.7
* Fix V2Ray transport `path` validation behavior **1**
* Fixes and improvements
**1**:
See [V2Ray transport](/configuration/shared/v2ray-transport/).
#### 1.8.0-rc.7
* Fixes and improvements
#### 1.8.0-rc.3
* Fix V2Ray transport `path` validation behavior **1**
* Fixes and improvements
**1**:
See [V2Ray transport](/configuration/shared/v2ray-transport/).
#### 1.7.6
* Fixes and improvements
#### 1.8.0-rc.1
* Fixes and improvements
@@ -508,7 +212,7 @@ see [TCP Brutal](/configuration/shared/tcp-brutal/) for details.
**5**:
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
#### 1.7.0-rc.3
@@ -545,7 +249,7 @@ Only supported in graphical clients on Android and Apple platforms.
**1**:
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
#### 1.7.0-beta.3

View File

@@ -16,7 +16,6 @@ platform-specific function implementation, such as TUN transparent proxy impleme
* [Play Store](https://play.google.com/store/apps/details?id=io.nekohasekai.sfa)
* [Play Store (Beta)](https://play.google.com/apps/testing/io.nekohasekai.sfa)
* [GitHub Releases](https://github.com/SagerNet/sing-box/releases)
* [F-Droid](https://f-droid.org/packages/io.nekohasekai.sfa/) (Unified signature via reproducible builds)
## :material-source-repository: Source code

View File

@@ -15,11 +15,7 @@ platform-specific function implementation, such as TUN transparent proxy impleme
## :material-download: Download
* [App Store](https://apps.apple.com/us/app/sing-box/id6451272673)
* ~~[TestFlight (Beta)](https://testflight.apple.com/join/AcqO44FH)~~
_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._
* [TestFlight (Beta)](https://testflight.apple.com/join/AcqO44FH)
## :material-file-download: Download (macOS standalone version)

View File

@@ -2,11 +2,11 @@
Maintained by Project S to provide a unified experience and platform-specific functionality.
| Platform | Client |
|---------------------------------------|------------------------------------------|
| Platform | Client |
|---------------------------------------|-----------------------------------------|
| :material-android: Android | [sing-box for Android](./android/) |
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
| :material-laptop: Desktop | Working in progress |
| :material-laptop: Desktop | Working in progress |
Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core
motivation of the maintainers of such projects is to acquire more users, and even though they provide friendly VPN

View File

@@ -6,9 +6,3 @@ icon: material/security
sing-box and official graphics clients do not collect or share personal data,
and the data generated by the software is always on your device.
## Android
If your configuration contains `wifi_ssid` or `wifi_bssid` routing rules,
sing-box uses the location permission in the background
to get information about the connected Wi-Fi network to make them work.

View File

@@ -1,11 +1,3 @@
---
icon: material/new-box
---
!!! quote "Changes in sing-box 1.9.0"
:material-plus: [client_subnet](#client_subnet)
# DNS
### Structure
@@ -21,7 +13,6 @@ icon: material/new-box
"disable_expire": false,
"independent_cache": false,
"reverse_mapping": false,
"client_subnet": "",
"fakeip": {}
}
}
@@ -30,8 +21,8 @@ icon: material/new-box
### Fields
| Key | Format |
|----------|---------------------------------|
| Key | Format |
|----------|--------------------------------|
| `server` | List of [DNS Server](./server/) |
| `rules` | List of [DNS Rule](./rule/) |
| `fakeip` | [FakeIP](./fakeip/) |
@@ -69,10 +60,6 @@ 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
problematic in environments such as macOS, where DNS is proxied and cached by the system.
#### client_subnet
#### fakeip
!!! question "Since sing-box 1.9.0"
Append a `edns0-subnet` OPT extra record with the specified IP address to every query by default.
Can be overrides by `servers.[].client_subnet` or `rules.[].client_subnet`.
[FakeIP](./fakeip/) settings.

View File

@@ -1,11 +1,3 @@
---
icon: material/new-box
---
!!! quote "sing-box 1.9.0 中的更改"
:material-plus: [client_subnet](#client_subnet)
# DNS
### 结构
@@ -21,7 +13,6 @@ icon: material/new-box
"disable_expire": false,
"independent_cache": false,
"reverse_mapping": false,
"client_subnet": "",
"fakeip": {}
}
}
@@ -30,8 +21,8 @@ icon: material/new-box
### 字段
| 键 | 格式 |
|----------|-------------------------|
| 键 | 格式 |
|----------|------------------------|
| `server` | 一组 [DNS 服务器](./server/) |
| `rules` | 一组 [DNS 规则](./rule/) |
@@ -67,14 +58,6 @@ icon: material/new-box
由于此过程依赖于应用程序在发出请求之前解析域名的行为,因此在 macOS 等 DNS 由系统代理和缓存的环境中可能会出现问题。
#### client_subnet
!!! question "自 sing-box 1.9.0 起"
默认情况下,将带有指定 IP 地址的 `edns0-subnet` OPT 附加记录附加到每个查询。
可以被 `servers.[].client_subnet``rules.[].client_subnet` 覆盖。
#### fakeip
[FakeIP](./fakeip/) 设置。

View File

@@ -1,15 +1,7 @@
---
icon: material/new-box
icon: material/alert-decagram
---
!!! 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"
:material-plus: [rule_set](#rule_set)
@@ -61,19 +53,11 @@ icon: material/new-box
"source_geoip": [
"private"
],
"geoip": [
"cn"
],
"source_ip_cidr": [
"10.0.0.0/24",
"192.168.0.1"
],
"source_ip_is_private": false,
"ip_cidr": [
"10.0.0.0/24",
"192.168.0.1"
],
"ip_is_private": false,
"source_port": [
12345
],
@@ -117,15 +101,13 @@ icon: material/new-box
"geoip-cn",
"geosite-cn"
],
"rule_set_ipcidr_match_source": false,
"invert": false,
"outbound": [
"direct"
],
"server": "local",
"disable_cache": false,
"rewrite_ttl": 100,
"client_subnet": "127.0.0.1"
"rewrite_ttl": 100
},
{
"type": "logical",
@@ -133,8 +115,7 @@ icon: material/new-box
"rules": [],
"server": "local",
"disable_cache": false,
"rewrite_ttl": 100,
"client_subnet": "127.0.0.1"
"rewrite_ttl": 100
}
]
}
@@ -285,9 +266,11 @@ Match Clash mode.
#### wifi_ssid
<!-- md:version 1.7.0-beta.4 -->
!!! quote ""
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
Match WiFi SSID.
@@ -295,7 +278,7 @@ Match WiFi SSID.
!!! quote ""
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
Match WiFi BSSID.
@@ -305,12 +288,6 @@ Match WiFi BSSID.
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 match result.
@@ -335,44 +312,6 @@ Disable cache and save cache in this query.
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 address to every query by default.
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
#### type

View File

@@ -1,15 +1,7 @@
---
icon: material/new-box
icon: material/alert-decagram
---
!!! 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 中的更改"
:material-plus: [rule_set](#rule_set)
@@ -61,19 +53,10 @@ icon: material/new-box
"source_geoip": [
"private"
],
"geoip": [
"cn"
],
"source_ip_cidr": [
"10.0.0.0/24",
"192.168.0.1"
"10.0.0.0/24"
],
"source_ip_is_private": false,
"ip_cidr": [
"10.0.0.0/24",
"192.168.0.1"
],
"ip_is_private": false,
"source_port": [
12345
],
@@ -117,22 +100,19 @@ icon: material/new-box
"geoip-cn",
"geosite-cn"
],
"rule_set_ipcidr_match_source": false,
"invert": false,
"outbound": [
"direct"
],
"server": "local",
"disable_cache": false,
"client_subnet": "127.0.0.1"
"disable_cache": false
},
{
"type": "logical",
"mode": "and",
"rules": [],
"server": "local",
"disable_cache": false,
"client_subnet": "127.0.0.1"
"disable_cache": false
}
]
}
@@ -285,7 +265,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
!!! quote ""
仅在 Android 与 Apple 平台图形客户端中支持。
仅在 Android 与 iOS 的图形客户端中支持。
匹配 WiFi SSID。
@@ -293,7 +273,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
!!! quote ""
仅在 Android 与 Apple 平台图形客户端中支持。
仅在 Android 与 iOS 的图形客户端中支持。
匹配 WiFi BSSID。
@@ -303,12 +283,6 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
匹配[规则集](/zh/configuration/route/#rule_set)。
#### rule_set_ipcidr_match_source
!!! question "自 sing-box 1.9.0 起"
使规则集中的 `ipcidr` 规则匹配源 IP。
#### invert
反选匹配结果。
@@ -333,44 +307,6 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
重写 DNS 回应中的 TTL。
#### client_subnet
!!! question "自 sing-box 1.9.0 起"
默认情况下,将带有指定 IP 地址的 `edns0-subnet` OPT 附加记录附加到每个查询。
将覆盖 `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
@@ -383,4 +319,4 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
#### rules
包括的规则。
包括的规则。

View File

@@ -1,11 +1,3 @@
---
icon: material/new-box
---
!!! quote "Changes in sing-box 1.9.0"
:material-plus: [client_subnet](#client_subnet)
### Structure
```json
@@ -13,17 +5,17 @@ icon: material/new-box
"dns": {
"servers": [
{
"tag": "",
"address": "",
"address_resolver": "",
"address_strategy": "",
"strategy": "",
"detour": "",
"client_subnet": ""
"tag": "google",
"address": "tls://dns.google",
"address_resolver": "local",
"address_strategy": "prefer_ipv4",
"strategy": "ipv4_only",
"detour": "direct"
}
]
}
}
```
### Fields
@@ -38,17 +30,17 @@ The tag of the dns server.
The address of the dns server.
| Protocol | Format |
|--------------------------------------|-------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto` or `dhcp://en0` |
| Protocol | Format |
|-------------------------------------|-------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto` or `dhcp://en0` |
| [FakeIP](/configuration/dns/fakeip/) | `fakeip` |
!!! warning ""
@@ -88,20 +80,10 @@ Default domain strategy for resolving the domain names.
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
Take no effect if overridden by other settings.
Take no effect if override by other settings.
#### detour
Tag of an outbound for connecting to the dns server.
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 address to every query by default.
Can be overrides by `rules.[].client_subnet`.
Will overrides `dns.client_subnet`.

View File

@@ -1,11 +1,3 @@
---
icon: material/new-box
---
!!! quote "sing-box 1.9.0 中的更改"
:material-plus: [client_subnet](#client_subnet)
### 结构
```json
@@ -13,17 +5,17 @@ icon: material/new-box
"dns": {
"servers": [
{
"tag": "",
"address": "",
"address_resolver": "",
"address_strategy": "",
"strategy": "",
"detour": "",
"client_subnet": ""
"tag": "google",
"address": "tls://dns.google",
"address_resolver": "local",
"address_strategy": "prefer_ipv4",
"strategy": "ipv4_only",
"detour": "direct"
}
]
}
}
```
### 字段
@@ -38,17 +30,17 @@ DNS 服务器的标签。
DNS 服务器的地址。
| 协议 | 格式 |
|--------------------------------------|------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto``dhcp://en0` |
| 协议 | 格式 |
|-------------------------------------|------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto``dhcp://en0` |
| [FakeIP](/configuration/dns/fakeip/) | `fakeip` |
!!! warning ""
@@ -95,13 +87,3 @@ DNS 服务器的地址。
用于连接到 DNS 服务器的出站的标签。
如果为空,将使用默认出站。
#### client_subnet
!!! question "自 sing-box 1.9.0 起"
默认情况下,将带有指定 IP 地址的 `edns0-subnet` OPT 附加记录附加到每个查询。
可以被 `rules.[].client_subnet` 覆盖。
将覆盖 `dns.client_subnet`

View File

@@ -4,11 +4,6 @@ icon: material/new-box
!!! 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
```json
@@ -16,9 +11,7 @@ icon: material/new-box
"enabled": true,
"path": "",
"cache_id": "",
"store_fakeip": false,
"store_rdrc": false,
"rdrc_timeout": ""
"store_fakeip": false
}
```
@@ -36,23 +29,6 @@ Path to the cache file.
#### cache_id
Identifier in the cache file
Identifier in cache file.
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.

View File

@@ -4,11 +4,6 @@ icon: material/new-box
!!! 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
@@ -16,9 +11,7 @@ icon: material/new-box
"enabled": true,
"path": "",
"cache_id": "",
"store_fakeip": false,
"store_rdrc": false,
"rdrc_timeout": ""
"store_fakeip": false
}
```
@@ -37,19 +30,3 @@ icon: material/new-box
缓存文件中的标识符。
如果不为空,配置特定的数据将使用由其键控的单独存储。
#### store_fakeip
将 fakeip 存储在缓存文件中。
#### store_rdrc
将拒绝的 DNS 响应缓存存储在缓存文件中。
[地址筛选 DNS 规则项](/zh/configuration/dns/rule/#_3) 的检查结果将被缓存至过期。
#### rdrc_timeout
拒绝的 DNS 响应缓存超时。
默认使用 `7d`

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
!!! quote "Changes in sing-box 1.8.0"
:material-delete-alert: [store_mode](#store_mode)

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
!!! quote "sing-box 1.8.0 中的更改"
:material-delete-alert: [store_mode](#store_mode)

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
# Experimental
!!! quote "Changes in sing-box 1.8.0"

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
# 实验性
!!! quote "sing-box 1.8.0 中的更改"

View File

@@ -42,6 +42,6 @@ No authentication required if empty.
!!! warning ""
To work on Android and Apple platforms without privileges, use tun.platform.http_proxy instead.
To work on Android and iOS without privileges, use tun.platform.http_proxy instead.
Automatically set system proxy configuration when start and clean up when stop.

View File

@@ -15,8 +15,8 @@
### Fields
| Type | Format | Injectable |
|---------------|-------------------------------|------------|
| Type | Format | Injectable |
|---------------|------------------------------|------------|
| `direct` | [Direct](./direct/) | X |
| `mixed` | [Mixed](./mixed/) | TCP |
| `socks` | [SOCKS](./socks/) | TCP |

View File

@@ -39,6 +39,6 @@ No authentication required if empty.
!!! warning ""
To work on Android and Apple platforms without privileges, use tun.platform.http_proxy instead.
To work on Android and iOS without privileges, use tun.platform.http_proxy instead.
Automatically set system proxy configuration when start and clean up when stop.

View File

@@ -1,12 +1,7 @@
---
icon: material/new-box
icon: material/alert-decagram
---
!!! 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"
:material-plus: [gso](#gso)
@@ -78,9 +73,7 @@ icon: material/new-box
"http_proxy": {
"enabled": false,
"server": "127.0.0.1",
"server_port": 8080,
"bypass_domain": [],
"match_domain": []
"server_port": 8080
}
},
@@ -267,38 +260,6 @@ Platform-specific settings, provided by client applications.
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
See [Listen Fields](/configuration/shared/listen/) for details.

View File

@@ -1,12 +1,7 @@
---
icon: material/new-box
icon: material/alert-decagram
---
!!! 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 中的更改"
:material-plus: [gso](#gso)
@@ -78,9 +73,7 @@ icon: material/new-box
"http_proxy": {
"enabled": false,
"server": "127.0.0.1",
"server_port": 8080,
"bypass_domain": [],
"match_domain": []
"server_port": 8080
}
},
@@ -264,38 +257,6 @@ TCP/IP 栈。
系统 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/)。

View File

@@ -18,8 +18,8 @@ sing-box uses JSON for configuration files.
### Fields
| Key | Format |
|----------------|---------------------------------|
| Key | Format |
|----------------|--------------------------------|
| `log` | [Log](./log/) |
| `dns` | [DNS](./dns/) |
| `ntp` | [NTP](./ntp/) |

View File

@@ -17,8 +17,8 @@ sing-box 使用 JSON 作为配置文件格式。
### 字段
| Key | Format |
|----------------|------------------------|
| Key | Format |
|----------------|-----------------------|
| `log` | [日志](./log/) |
| `dns` | [DNS](./dns/) |
| `inbounds` | [入站](./inbound/) |

View File

@@ -1,3 +1,7 @@
---
icon: material/new-box
---
!!! quote "Changes in sing-box 1.8.0"
:material-plus: [gso](#gso)

View File

@@ -1,3 +1,7 @@
---
icon: material/new-box
---
!!! quote "sing-box 1.8.0 中的更改"
:material-plus: [gso](#gso)

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
# Route
!!! quote "Changes in sing-box 1.8.0"

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
# 路由
!!! quote "sing-box 1.8.0 中的更改"
@@ -26,14 +30,15 @@
### 字段
| 键 | 格式 |
|-----------|-----------------------|
| `geoip` | [GeoIP](./geoip/) |
| `geosite` | [Geosite](./geosite/) |
| 键 | 格式 |
|------------|-----------------------------------|
| `geoip` | [GeoIP](./geoip/) |
| `geosite` | [Geosite](./geosite/) |
#### rule
一组 [路由规则](./rule/)
一组 [路由规则](./rule/)。
#### rule_set

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
!!! quote "Changes in sing-box 1.8.0"
:material-plus: [rule_set](#rule_set)
@@ -105,7 +109,6 @@
"geoip-cn",
"geosite-cn"
],
"rule_set_ipcidr_match_source": false,
"invert": false,
"outbound": "direct"
},
@@ -281,7 +284,7 @@ Match Clash mode.
!!! quote ""
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
Match WiFi SSID.
@@ -289,7 +292,7 @@ Match WiFi SSID.
!!! quote ""
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
Match WiFi BSSID.

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
!!! quote "sing-box 1.8.0 中的更改"
:material-plus: [rule_set](#rule_set)
@@ -103,7 +107,6 @@
"geoip-cn",
"geosite-cn"
],
"rule_set_ipcidr_match_source": false,
"invert": false,
"outbound": "direct"
},
@@ -279,7 +282,7 @@
!!! quote ""
仅在 Android 与 Apple 平台图形客户端中支持。
仅在 Android 与 iOS 的图形客户端中支持。
匹配 WiFi SSID。
@@ -287,7 +290,7 @@
!!! quote ""
仅在 Android 与 Apple 平台图形客户端中支持。
仅在 Android 与 iOS 的图形客户端中支持。
匹配 WiFi BSSID。

View File

@@ -1,3 +1,7 @@
---
icon: material/new-box
---
### Structure
!!! question "Since sing-box 1.8.0"
@@ -124,7 +128,7 @@ Match source IP CIDR.
!!! info ""
`ip_cidr` is an alias for `source_ip_cidr` when `rule_set_ipcidr_match_source` enabled in route/DNS rules.
`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.
Match IP CIDR.
@@ -168,7 +172,7 @@ Match android package name.
!!! quote ""
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
Match WiFi SSID.
@@ -176,7 +180,7 @@ Match WiFi SSID.
!!! quote ""
Only supported in graphical clients on Android and Apple platforms.
Only supported in graphical clients on Android and iOS.
Match WiFi BSSID.

View File

@@ -1,3 +1,7 @@
---
icon: material/new-box
---
# Rule Set
!!! question "Since sing-box 1.8.0"

View File

@@ -1,3 +1,7 @@
---
icon: material/new-box
---
# Source Format
!!! question "Since sing-box 1.8.0"
@@ -27,4 +31,4 @@ Version of Rule Set, must be `1`.
==Required==
List of [Headless Rule](./headless-rule.md/).
List of [Headless Rule](./headless-rule/).

View File

@@ -1,3 +1,8 @@
---
icon: material/alert-decagram
---
!!! quote "Changes in sing-box 1.8.0"
:material-alert-decagram: [utls](#utls)
@@ -168,9 +173,10 @@ By default, the maximum version is currently TLS 1.3.
#### cipher_suites
A list of enabled TLS 1.01.2 cipher suites. The order of the list is ignored. Note that TLS 1.3 cipher suites are not configurable.
The elliptic curves that will be used in an ECDHE handshake, in preference order.
If empty, a safe default list is used. The default cipher suites might change over time.
If empty, the default will be used. The client will use the first preference as the type for its key share in TLS 1.3.
This may change in the future.
#### certificate

View File

@@ -1,3 +1,7 @@
---
icon: material/alert-decagram
---
!!! quote "sing-box 1.8.0 中的更改"
:material-alert-decagram: [utls](#utls)
@@ -166,9 +170,12 @@ TLS 版本值:
#### cipher_suites
启用的 TLS 1.0-1.2密码套件的列表。列表的顺序被忽略。请注意TLS 1.3 的密码套件是不可配置的
将在 ECDHE 握手中使用的椭圆曲线,按优先顺序排列
如果为空,使用安全的默认列表。默认密码套件可能会随着时间的推移而改变
如果为空,使用默认值
客户端将使用第一个首选项作为其在 TLS 1.3 中的密钥共享类型。
这在未来可能会改变。
#### certificate

View File

@@ -53,15 +53,9 @@ The client will choose randomly and the server will verify if not empty.
#### path
!!! warning
V2Ray's documentation says that the path between the server and the client must be consistent,
but the actual code allows the client to add any suffix to the path.
sing-box uses the same behavior as V2Ray, but note that the behavior does not exist in `WebSocket` and `HTTPUpgrade` transport.
Path of HTTP request.
The server will verify.
The server will verify if not empty.
#### method
@@ -83,10 +77,7 @@ Specifies the time until idle clients should be closed with a GOAWAY frame. PING
In HTTP2 client:
Specifies the period of time after which a health check will be performed using a ping frame if no frames have been
received on the connection.Please note that a ping response is considered a received frame, so if there is no other
traffic on the connection, the health check will be executed every interval. If the value is zero, no health check will
be performed.
Specifies the period of time after which a health check will be performed using a ping frame if no frames have been received on the connection. Please note that a ping response is considered a received frame, so if there is no other traffic on the connection, the health check will be executed every interval. If the value is zero, no health check will be performed.
Zero is used by default.
@@ -94,9 +85,7 @@ Zero is used by default.
In HTTP2 client:
Specifies the timeout duration after sending a PING frame, within which a response must be received.
If a response to the PING frame is not received within the specified timeout duration, the connection will be closed.
The default timeout duration is 15 seconds.
Specifies the timeout duration after sending a PING frame, within which a response must be received. If a response to the PING frame is not received within the specified timeout duration, the connection will be closed. The default timeout duration is 15 seconds.
### WebSocket
@@ -114,14 +103,12 @@ The default timeout duration is 15 seconds.
Path of HTTP request.
The server will verify.
The server will verify if not empty.
#### headers
Extra headers of HTTP request.
The server will write in response if not empty.
#### max_early_data
Allowed payload size is in the request. Enabled if not zero.
@@ -171,8 +158,7 @@ Service name of gRPC.
In standard gRPC server/client:
If the transport doesn't see any activity after a duration of this time,
it pings the client to check if the connection is still active.
If the transport doesn't see any activity after a duration of this time, it pings the client to check if the connection is still active.
In default gRPC server/client:
@@ -182,8 +168,7 @@ It has the same behavior as the corresponding setting in HTTP transport.
In standard gRPC server/client:
The timeout that after performing a keepalive check, the client will wait for activity.
If no activity is detected, the connection will be closed.
The timeout that after performing a keepalive check, the client will wait for activity. If no activity is detected, the connection will be closed.
In default gRPC server/client:
@@ -193,9 +178,7 @@ It has the same behavior as the corresponding setting in HTTP transport.
In standard gRPC client:
If enabled, the client transport sends keepalive pings even with no active connections.
If disabled, when there are no active connections, `idle_timeout` and `ping_timeout` will be ignored and no keepalive
pings will be sent.
If enabled, the client transport sends keepalive pings even with no active connections. If disabled, when there are no active connections, `idle_timeout` and `ping_timeout` will be ignored and no keepalive pings will be sent.
Disabled by default.
@@ -220,7 +203,7 @@ The server will verify if not empty.
Path of HTTP request.
The server will verify.
The server will verify if not empty.
#### headers

View File

@@ -48,30 +48,25 @@ V2Ray Transport 是 v2ray 发明的一组私有协议,并污染了其他协议
主机域名列表。
如果设置,客户端将随机选择,服务器将验证。
客户端将随机选择,默认服务器将验证。
#### path
!!! warning
V2Ray 文档称服务端和客户端的路径必须一致,但实际代码允许客户端向路径添加任何后缀。
sing-box 使用与 V2Ray 相同的行为,但请注意,该行为在 `WebSocket``HTTPUpgrade` 传输层中不存在。
HTTP 请求路径
服务器将验证。
默认服务器将验证。
#### method
HTTP 请求方法
如果设置,服务器将验证。
默认服务器将验证。
#### headers
HTTP 请求的额外标头
如果设置,服务器将写入响应。
默认服务器将写入响应。
#### idle_timeout
@@ -107,13 +102,11 @@ HTTP 请求的额外标头
HTTP 请求路径
服务器将验证。
默认服务器将验证。
#### headers
HTTP 请求的额外标头
如果设置,服务器将写入响应。
HTTP 请求的额外标头
#### max_early_data
@@ -203,16 +196,16 @@ gRPC 服务名称。
主机域名。
服务器将验证。
默认服务器将验证。
#### path
HTTP 请求路径
服务器将验证。
默认服务器将验证。
#### headers
HTTP 请求的额外标头。
如果设置,服务器将写入响应。
默认服务器将写入响应。

View File

@@ -19,7 +19,7 @@ The maxmind GeoIP National Database, as an IP classification database,
is not entirely suitable for traffic bypassing,
and all existing implementations suffer from high memory usage and difficult management.
sing-box 1.8.0 introduces [Rule Set](/configuration/rule-set/), which can completely replace GeoIP,
sing-box 1.8.0 introduces [Rule Set](/configuration/rule_set/), which can completely replace GeoIP,
check [Migration](/migration/#migrate-geoip-to-rule-sets).
#### Geosite
@@ -29,9 +29,11 @@ Geosite is deprecated and may be removed in the future.
Geosite, the `domain-list-community` project maintained by V2Ray as an early traffic bypassing solution,
suffers from a number of problems, including lack of maintenance, inaccurate rules, and difficult management.
sing-box 1.8.0 introduces [Rule Set](/configuration/rule-set/), which can completely replace Geosite,
sing-box 1.8.0 introduces [Rule Set](/configuration/rule_set/), which can completely replace Geosite,
check [Migration](/migration/#migrate-geosite-to-rule-sets).
Geosite即由 V2Ray 维护的 domain-list-community 项目,作为早期流量绕过解决方案,存在着大量问题,包括缺少维护、规则不准确、管理困难。
## 1.6.0
The following features will be marked deprecated in 1.5.0 and removed entirely in 1.6.0.

View File

@@ -18,7 +18,7 @@ GeoIP 已废弃且可能在不久的将来移除。
maxmind GeoIP 国家数据库作为 IP 分类数据库,不完全适合流量绕过,
且现有的实现均存在内存使用大与管理困难的问题。
sing-box 1.8.0 引入了[规则集](/configuration/rule-set/)
sing-box 1.8.0 引入了[规则集](/configuration/rule_set/)
可以完全替代 GeoIP 参阅 [迁移指南](/zh/migration/#geoip)。
#### Geosite
@@ -28,7 +28,7 @@ Geosite 已废弃且可能在不久的将来移除。
Geosite即由 V2Ray 维护的 domain-list-community 项目,作为早期流量绕过解决方案,
存在着包括缺少维护、规则不准确和管理困难内的大量问题。
sing-box 1.8.0 引入了[规则集](/configuration/rule-set/)
sing-box 1.8.0 引入了[规则集](/configuration/rule_set/)
可以完全替代 Geosite参阅 [迁移指南](/zh/migration/#geosite)。
## 1.6.0

View File

@@ -23,8 +23,7 @@ Since sing-box 1.5.0:
Since sing-box 1.8.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
* Go 1.21.0 - ~ with tag `with_ech` enabled
* Go 1.20.0 - ~ with tag `with_quic`, `with_ech`, or `with_utls` enabled
You can download and install Go from: https://go.dev/doc/install, latest version is recommended.
@@ -54,19 +53,19 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
## :material-folder-settings: Build Tags
| 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_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_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_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_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_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_embedded_tor` (CGO required) | :material-close: | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
| `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_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_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_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_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_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.

View File

@@ -23,8 +23,7 @@ sing-box 1.4.0 前:
从 sing-box 1.8.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic``with_utls`
* Go 1.20.1 - ~ 如果启用构建标记 `with_ech`
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic``with_ech``with_utls`
您可以从 https://go.dev/doc/install 下载并安装 Go推荐使用最新版本。

View File

@@ -4,35 +4,6 @@ icon: material/package
# Package Manager
## :material-tram: Repository Installation
=== ":material-debian: Debian / APT"
```bash
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc
sudo chmod a+r /etc/apt/keyrings/sagernet.asc
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/sagernet.asc] https://deb.sagernet.org/ * *" | \
sudo tee /etc/apt/sources.list.d/sagernet.list > /dev/null
sudo apt-get update
sudo apt-get install sing-box # or sing-box-beta
```
=== ":material-redhat: Redhat / DNF"
```bash
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
sudo dnf install sing-box # or sing-box-beta
```
=== ":material-redhat: CentOS / YUM"
```bash
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://sing-box.app/sing-box.repo
sudo yum install sing-box # or sing-box-beta
```
## :material-download-box: Manual Installation
=== ":material-debian: Debian / DEB"

View File

@@ -4,35 +4,6 @@ icon: material/package
# 包管理器
## :material-tram: 仓库安装
=== ":material-debian: Debian / APT"
```bash
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc
sudo chmod a+r /etc/apt/keyrings/sagernet.asc
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/sagernet.asc] https://deb.sagernet.org/ * *" | \
sudo tee /etc/apt/sources.list.d/sagernet.list > /dev/null
sudo apt-get update
sudo apt-get install sing-box # or sing-box-beta
```
=== ":material-redhat: Redhat / DNF"
```bash
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
sudo dnf install sing-box # or sing-box-beta
```
=== ":material-redhat: CentOS / YUM"
```bash
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://sing-box.app/sing-box.repo
sudo yum install sing-box # or sing-box-beta
```
## :material-download-box: 手动安装
=== ":material-debian: Debian / DEB"

View File

@@ -1,8 +0,0 @@
[sing-box]
name=sing-box
baseurl=https://rpm.sagernet.org/
metalink=https://sing-box.app/sing-box.repo
enabled=1
repo_gpgcheck=1
gpgcheck=1
gpgkey=https://sing-box.app/gpg.key

View File

@@ -290,6 +290,10 @@ flowchart TB
=== ":material-dns: DNS rules"
!!! info
DNS rules are optional if FakeIP is used.
```json
{
"dns": {
@@ -318,7 +322,75 @@ flowchart TB
"server": "google"
},
{
"rule_set": "geosite-geolocation-cn",
"type": "logical",
"mode": "and",
"rules": [
{
"geosite": "geolocation-!cn",
"invert": true
},
{
"geosite": [
"cn",
"category-companies@cn"
],
}
],
"server": "local"
}
]
}
}
```
=== ":material-dns: DNS rules (1.8.0+)"
!!! 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"
},
{
"type": "logical",
"mode": "and",
"rules": [
{
"rule_set": "geosite-geolocation-!cn",
"invert": true
},
{
"rule_set": [
"geosite-cn",
"geosite-category-companies@cn"
]
}
],
"server": "local"
}
]
@@ -327,190 +399,110 @@ flowchart TB
"rule_set": [
{
"type": "remote",
"tag": "geosite-geolocation-cn",
"tag": "geosite-cn",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-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": "geosite-category-companies@cn",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-category-companies@cn.srs"
}
]
}
}
```
=== ":material-dns: DNS rules (Enhanced, but slower) (1.9.0+)"
=== ":material-shield-off: With DNS leaks"
```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"
},
{
"clash_mode": "Default",
"server": "google"
},
{
"type": "logical",
"mode": "and",
"rules": [
{
"rule_set": "geosite-geolocation-!cn",
"invert": true
},
{
"rule_set": "geoip-cn"
}
],
"server": "local"
}
]
},
"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-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" // 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
{
"outbounds": [
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
}
],
"route": {
"rules": [
{
"type": "logical",
"mode": "or",
"rules": [
{
"protocol": "dns"
},
{
"port": 53
}
],
"outbound": "dns"
},
{
"geoip": "private",
"outbound": "direct"
},
{
"clash_mode": "Direct",
"outbound": "direct"
},
{
"clash_mode": "Global",
"outbound": "default"
},
{
"type": "logical",
"mode": "or",
"rules": [
{
"port": 853
},
{
"network": "udp",
"port": 443
},
{
"protocol": "stun"
}
],
"outbound": "block"
},
{
"type": "logical",
"mode": "and",
"rules": [
{
"geosite": "geolocation-!cn",
"invert": true
},
{
"geosite": [
"cn",
"category-companies@cn"
],
"geoip": "cn"
}
],
"outbound": "direct"
}
]
}
}
```
=== ":material-router-network: Route rules (1.8.0+)"
```json
{
"outbounds": [
@@ -568,9 +560,20 @@ flowchart TB
"outbound": "block"
},
{
"rule_set": [
"geoip-cn",
"geosite-geolocation-cn"
"type": "logical",
"mode": "and",
"rules": [
{
"rule_set": "geosite-geolocation-!cn",
"invert": true
},
{
"rule_set": [
"geoip-cn",
"geosite-cn",
"geosite-category-companies@cn"
]
}
],
"outbound": "direct"
}
@@ -584,9 +587,21 @@ flowchart TB
},
{
"type": "remote",
"tag": "geosite-geolocation-cn",
"tag": "geosite-cn",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-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": "geosite-category-companies@cn",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-category-companies@cn.srs"
}
]
}

View File

@@ -2,30 +2,12 @@
icon: material/arrange-bring-forward
---
## 1.9.0
## 1.8.0
!!! warning "Unstable"
This version is still under development, and the following migration guide may be changed in the future.
### `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
### :material-close-box: Migrate cache file from Clash API to independent options
!!! info "References"

View File

@@ -2,29 +2,12 @@
icon: material/arrange-bring-forward
---
## 1.9.0
## 1.8.0
!!! warning "不稳定的"
该版本仍在开发中,迁移指南可能将在未来更改。
### `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
### :material-close-box: 将缓存文件从 Clash API 迁移到独立选项
!!! info "参考"

View File

@@ -29,7 +29,6 @@ var (
string(bucketExpand),
string(bucketMode),
string(bucketRuleSet),
string(bucketRDRC),
}
cacheIDDefault = []byte("default")
@@ -38,25 +37,17 @@ var (
var _ adapter.CacheFile = (*CacheFile)(nil)
type CacheFile struct {
ctx context.Context
path string
cacheID []byte
storeFakeIP bool
storeRDRC bool
rdrcTimeout time.Duration
ctx context.Context
path string
cacheID []byte
storeFakeIP bool
DB *bbolt.DB
saveMetadataTimer *time.Timer
saveFakeIPAccess sync.RWMutex
saveAccess sync.RWMutex
saveDomain map[netip.Addr]string
saveAddress4 map[string]netip.Addr
saveAddress6 map[string]netip.Addr
saveRDRCAccess sync.RWMutex
saveRDRC map[saveRDRCCacheKey]bool
}
type saveRDRCCacheKey struct {
TransportName string
QuestionName string
saveMetadataTimer *time.Timer
}
func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
@@ -70,25 +61,14 @@ func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
if 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{
ctx: ctx,
path: filemanager.BasePath(ctx, path),
cacheID: cacheIDBytes,
storeFakeIP: options.StoreFakeIP,
storeRDRC: options.StoreRDRC,
rdrcTimeout: rdrcTimeout,
saveDomain: make(map[netip.Addr]string),
saveAddress4: make(map[string]netip.Addr),
saveAddress6: make(map[string]netip.Addr),
saveRDRC: make(map[saveRDRCCacheKey]bool),
}
}

View File

@@ -7,7 +7,6 @@ import (
"github.com/sagernet/bbolt"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
)
@@ -59,13 +58,12 @@ func (c *CacheFile) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
}
func (c *CacheFile) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
if c.saveMetadataTimer == nil {
c.saveMetadataTimer = time.AfterFunc(C.FakeIPMetadataSaveInterval, func() {
_ = c.FakeIPSaveMetadata(metadata)
})
} else {
c.saveMetadataTimer.Reset(C.FakeIPMetadataSaveInterval)
if timer := c.saveMetadataTimer; timer != nil {
timer.Stop()
}
c.saveMetadataTimer = time.AfterFunc(10*time.Second, func() {
_ = c.FakeIPSaveMetadata(metadata)
})
}
func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
@@ -91,34 +89,34 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
}
func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
c.saveFakeIPAccess.Lock()
c.saveAccess.Lock()
c.saveDomain[address] = domain
if address.Is4() {
c.saveAddress4[domain] = address
} else {
c.saveAddress6[domain] = address
}
c.saveFakeIPAccess.Unlock()
c.saveAccess.Unlock()
go func() {
err := c.FakeIPStore(address, domain)
if err != nil {
logger.Warn("save FakeIP cache: ", err)
logger.Warn("save FakeIP address pair: ", err)
}
c.saveFakeIPAccess.Lock()
c.saveAccess.Lock()
delete(c.saveDomain, address)
if address.Is4() {
delete(c.saveAddress4, domain)
} else {
delete(c.saveAddress6, domain)
}
c.saveFakeIPAccess.Unlock()
c.saveAccess.Unlock()
}()
}
func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
c.saveFakeIPAccess.RLock()
c.saveAccess.RLock()
cachedDomain, cached := c.saveDomain[address]
c.saveFakeIPAccess.RUnlock()
c.saveAccess.RUnlock()
if cached {
return cachedDomain, true
}
@@ -139,13 +137,13 @@ func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bo
cachedAddress netip.Addr
cached bool
)
c.saveFakeIPAccess.RLock()
c.saveAccess.RLock()
if !isIPv6 {
cachedAddress, cached = c.saveAddress4[domain]
} else {
cachedAddress, cached = c.saveAddress6[domain]
}
c.saveFakeIPAccess.RUnlock()
c.saveAccess.RUnlock()
if cached {
return cachedAddress, true
}

View File

@@ -1,101 +0,0 @@
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("rdrc")
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) (rejected bool) {
c.saveRDRCAccess.RLock()
rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName}]
c.saveRDRCAccess.RUnlock()
if cached {
return
}
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([]byte(qName))
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([]byte(qName))
})
}
return
}
func (c *CacheFile) SaveRDRC(transportName string, qName string) 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
}
expiresAt := buf.Get(8)
defer buf.Put(expiresAt)
binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix()))
return bucket.Put([]byte(qName), expiresAt)
})
}
func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, logger logger.Logger) {
saveKey := saveRDRCCacheKey{transportName, qName}
c.saveRDRCAccess.Lock()
c.saveRDRC[saveKey] = true
c.saveRDRCAccess.Unlock()
go func() {
err := c.SaveRDRC(transportName, qName)
if err != nil {
logger.Warn("save RDRC: ", err)
}
c.saveRDRCAccess.Lock()
delete(c.saveRDRC, saveKey)
c.saveRDRCAccess.Unlock()
}()
}

Some files were not shown because too many files have changed in this diff Show More