Compare commits

...

175 Commits

Author SHA1 Message Date
世界
e586d9e9bc Bump version 2024-09-20 23:37:06 +08:00
世界
8c7eaa4477 Fix docker build 2024-09-20 23:37:06 +08:00
世界
8464c8cb7c Fix version script 2024-09-20 21:10:15 +08:00
世界
39d7127651 Revert "Fix stream sniffer" 2024-09-20 20:40:02 +08:00
世界
e2077009c4 documentation: Update client status 2024-09-20 20:13:55 +08:00
世界
700a8eb425 Minor fixes 2024-09-20 20:13:14 +08:00
世界
3b0cba0852 Fix wireguard start 2024-09-20 20:12:52 +08:00
世界
f5554dd8b8 Bump version 2024-09-18 07:04:29 +08:00
世界
4d0362d530 Update macOS build workflow 2024-09-17 22:01:05 +08:00
世界
97ccd2ca04 documentation: Add sponsors page 2024-09-17 18:47:33 +08:00
世界
1ed6654ad4 Add mips64 build 2024-09-15 12:12:25 +08:00
世界
5385f75f53 documentation: Update build requirements 2024-09-15 12:10:00 +08:00
世界
ad97d4e11f Fix disconnected interface selected as default in windows 2024-09-15 11:59:32 +08:00
世界
09d4e91b77 Fix cached conn eats up read deadlines 2024-09-15 11:56:04 +08:00
Monica
3dbdda9555 documentation: Fix dial.zh.md
The Chinese documentation incorrectly stated that the default value for the domain_strategy field in the direct outbound module is dns.strategy. The correct value should be inbound.domain_strategy, as specified in the English documentation. This commit corrects the Chinese documentation to align with the accurate behavior described in the English version.

Signed-off-by: Monica <1379531829@qq.com>
2024-09-15 11:53:03 +08:00
世界
1f4ed6ff8f documentation: Update client status 2024-09-13 10:09:08 +08:00
世界
6ddbe19bc0 platform: Update bundle id 2024-09-12 17:55:53 +08:00
世界
d7205ecc60 Fix Makefile 2024-09-12 17:55:53 +08:00
世界
9e243e0ff9 gomobile: Fix go mod version 2024-09-10 23:05:13 +08:00
世界
02bc3e0a0a Update quic-go to v0.47.0 2024-09-09 14:45:46 +08:00
世界
87be6dc235 Update README 2024-09-09 08:48:35 +08:00
世界
c1c30976dc Improve docker workflow 2024-09-08 11:11:47 +08:00
世界
9bac18bcd1 wireguard: Fix events chan leak 2024-09-08 10:07:12 +08:00
世界
ceda5cc95d clash-api: Fix bad redirect 2024-09-08 10:07:07 +08:00
世界
27d6b63e71 Fix stream sniffer 2024-09-08 10:07:07 +08:00
世界
b57abcc73c tfo: Fix build with go1.23 2024-08-27 11:24:51 +08:00
世界
f1147965dd documentation: Fix missing zh headline 2024-08-21 18:52:38 +08:00
世界
45f3234c73 documentation: Update package status 2024-08-21 11:39:07 +08:00
Mingye Wang
aae3fded32 documentation: Two updates
* Copyedit documentation

Close #1378

* remove yum, go full on dnf

fixes #2049
2024-08-21 11:32:43 +08:00
世界
090494faf5 Do not close bug and enhancement issues 2024-08-21 08:09:15 +08:00
世界
db5719e22f Fix no error return when empty DNS cache retrieved 2024-08-20 23:23:48 +08:00
世界
064fb9b873 Fix direct dialer not resolving domain 2024-08-20 21:02:52 +08:00
世界
f6a1e123fc Make linter happy 2024-08-19 18:42:02 +08:00
世界
3066dfe3b3 Bump version 2024-08-19 10:43:09 +08:00
Liu Bingyan
1128fdd8c7 documentation: Update injectable description 2024-08-19 07:40:31 +08:00
世界
cfd9879b17 documentation: Remove unused 2024-08-19 06:39:33 +08:00
世界
9ceb660c57 documentation: Announce that our apps on Apple platforms are no longer available 2024-08-19 06:39:33 +08:00
世界
7d00d7df28 Update quic-go to v0.46.0 2024-08-19 06:25:15 +08:00
世界
21b1ac26b9 Fix UDP conn stuck on sniff
This change only avoids permanent hangs. We need to implement read deadlines for UDP conns in 1.10 for server inbounds.
2024-08-18 11:27:12 +08:00
世界
7fec8d842e Update golangci-lint configuration 2024-08-18 11:17:01 +08:00
世界
07c678fb85 Fix crash on Android when using process rules 2024-08-18 10:23:28 +08:00
世界
baecfc7778 Update quic-go to v0.45.2 2024-08-18 10:23:17 +08:00
世界
07de36ecdb Fix tests 2024-08-03 12:46:38 +08:00
世界
2c8a8303cd dns: Minor fixes 2024-07-27 11:04:57 +08:00
ruokeqx
e5991cae0b Use unix.SysctlRaw for macOS 2024-07-22 12:42:22 +08:00
世界
1349acfd5a Fix panic caused by possible generation of duplicate keys for domain_suffix 2024-07-17 16:02:17 +08:00
世界
98ff897f35 Fix reset outbounds 2024-07-13 17:46:22 +08:00
ayooh
6144c8e340 Fix default end value of the rangeItem 2024-07-13 17:45:32 +08:00
HystericalDragon
c8caac9f67 Fix v2rayquic default NextProtos (#1934) 2024-07-11 23:34:09 +08:00
printfer
81e9eda357 documentation: Fix typo 2024-07-07 16:09:41 +08:00
世界
7cba3da108 shadowsocks: Fix packet process for AEAD multi-user server 2024-07-05 17:09:09 +08:00
世界
82d06b43e7 vless: Fix missing deadline interfaces 2024-07-05 17:08:10 +08:00
世界
a7ac91f573 Move legacy vless implemetation to library 2024-07-03 20:17:32 +08:00
世界
0540a95a43 Fix v2ray-plugin 2024-07-02 14:08:17 +08:00
世界
94707dfcdd Add name to errors from v2ray HTTP transports 2024-07-02 14:08:17 +08:00
世界
8a17043502 Fix command output for rule-set match 2024-06-26 12:26:35 +08:00
世界
b0aaa86806 Minor fixes 2024-06-25 13:14:45 +08:00
世界
8a2d3fbb28 Update quic-go to v0.45.1 & Filter HTTPS ipv4/6hint 2024-06-24 11:07:32 +08:00
renovate[bot]
4652019608 [dependencies] Update docker/build-push-action action to v6 2024-06-24 10:24:13 +08:00
世界
06fa5abf63 Fix non-IP queries accepted by address filter rules 2024-06-24 10:13:16 +08:00
世界
996fbbf0c3 docs: Switch to venv 2024-06-24 10:10:49 +08:00
renovate[bot]
142ff1b455 [dependencies] Update actions/checkout digest to 692973e 2024-06-17 13:05:54 +08:00
世界
74d662f7a3 Fix always create package manager 2024-06-11 21:16:57 +08:00
世界
085f603377 Bump version 2024-06-09 13:20:56 +08:00
世界
460fae83dc Fix quic-go is caching dialErr since v0.43.0 2024-06-09 13:15:40 +08:00
世界
bb9bd9bff6 Fix package manager start order 2024-06-09 07:21:50 +08:00
世界
c2354ebf25 Bump version 2024-06-08 22:00:46 +08:00
世界
c1f4755c4e Fix parse UDP DNS server with addr:port address 2024-06-08 22:00:46 +08:00
世界
0ca5909b06 Stop passing device sleep events on Android and Apple platforms 2024-06-08 22:00:46 +08:00
世界
e77a8114c5 Fix rule-set start order 2024-06-08 22:00:46 +08:00
renovate[bot]
f1393235ff [dependencies] Update actions/checkout digest to a5ac7e5 2024-06-08 22:00:46 +08:00
renovate[bot]
bdba2365de [dependencies] Update goreleaser/goreleaser-action action to v6 2024-06-08 18:58:22 +08:00
世界
ce0da5b557 Fix typo 2024-06-08 18:58:14 +08:00
世界
3853201412 Bump version 2024-06-07 19:07:46 +08:00
世界
7003ef40a3 Fix wireguard start 2024-06-07 19:07:46 +08:00
世界
59ec92228c Fix repeatedly no route logs 2024-06-07 15:03:48 +08:00
世界
0eeb2da323 Fix reset HTTP3 DNS transport 2024-06-06 22:28:43 +08:00
世界
977b0fac02 Fix get source address from X-Forwarded-For 2024-06-06 22:21:37 +08:00
世界
51964801ff Fix enforced power listener on windows 2024-06-06 22:20:23 +08:00
世界
e08c052fc9 Fix wireguard client bind 2024-06-06 22:20:21 +08:00
世界
53927d8bbd Remove logs in router initialize 2024-06-06 22:20:19 +08:00
世界
968b9bc217 Fix crash on *bsd 2024-06-06 22:20:17 +08:00
lgjint
69dc87aa6d Fix set KDE6 system proxy 2024-06-06 22:20:14 +08:00
Fei1Yang
4193df375f build: Remove vendor in RPM packages 2024-05-27 19:28:15 +08:00
世界
5ff7006326 Bump version 2024-05-25 11:30:43 +08:00
世界
a89107ea9d documentation: Bump version 2024-05-23 14:57:45 +08:00
世界
9ffdbba2ed documentation: Add manuel for mitigating tunnelvision attacks 2024-05-23 14:57:27 +08:00
世界
65c71049ea documentation: Update DNS manual 2024-05-23 14:57:26 +08:00
世界
7d4e6a7f4e dialer: Allow nil router 2024-05-23 14:57:26 +08:00
世界
d612620c5d Add rule-set match command 2024-05-23 14:57:26 +08:00
世界
8a9a77a438 Add bypass_domain and search_domain platform HTTP proxy options 2024-05-23 14:57:26 +08:00
世界
a2098c18e1 Handle includeAllNetworks 2024-05-23 14:57:26 +08:00
世界
cf2181dd3a Update gVisor to 20240422.0 2024-05-23 14:57:15 +08:00
世界
5899e95ff1 Update quic-go to v0.43.1 2024-05-21 15:12:05 +08:00
世界
d7160c19cf Fixed order for Clash modes 2024-05-21 15:12:05 +08:00
世界
da9e22b4e6 Add custom prefix support in EDNS0 client subnet options 2024-05-21 15:12:05 +08:00
气息
0e120f8a44 Fix DNS exchange index
Signed-off-by: 气息 <qdshizh@gmail.com>
2024-05-21 15:12:05 +08:00
dyhkwong
d918863ac5 Always disable cache for fake-ip servers 2024-05-21 15:12:04 +08:00
PuerNya
2ae192305c Always disable cache for fake-ip DNS transport if independent_cache disabled 2024-05-21 15:12:03 +08:00
世界
71d1879bd6 Fix missing rule_set_ipcidr_match_source item in DNS rules 2024-05-21 15:12:03 +08:00
世界
917514e09f Improve DNS truncate behavior 2024-05-21 15:12:03 +08:00
世界
5327aeaea4 Fix DNS fallthrough incorrectly 2024-05-21 15:12:03 +08:00
世界
93ae3f7a1e Add rejected DNS response cache support 2024-05-21 15:12:03 +08:00
世界
f24a2aed7d Add support for client-subnet DNS options 2024-05-21 15:12:03 +08:00
世界
0517ceef76 Add address filter support for DNS rules 2024-05-21 15:12:02 +08:00
世界
830ea46932 Fix timezone for Android and iOS 2024-05-21 15:11:52 +08:00
世界
cd0fcd5ddc Improve loopback detector 2024-05-21 15:11:52 +08:00
世界
003176f069 Remove unused fakeip packet conn 2024-05-21 15:11:52 +08:00
世界
71d92518c1 Set the default TCP keep alive period 2024-05-21 15:11:52 +08:00
世界
b5dcd6bf59 Migrate ntp service to library 2024-05-21 15:11:52 +08:00
世界
11c7b4a866 Handle Windows power events 2024-05-21 15:11:52 +08:00
世界
ee14135298 Improve domain suffix match behavior
For historical reasons, sing-box's `domain_suffix` rule matches literal prefixes instead of the same as other projects.

This change modifies the behavior of `domain_suffix`: If the rule value is prefixed with `.`,
the behavior is unchanged, otherwise it matches `(domain|.+\.domain)` instead.
2024-05-21 15:11:41 +08:00
世界
cbcf005f37 Remove PROCESS_NAME_NATIVE dwFlag in process query output
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.

This change make QueryFullProcessImageNameW output a Win32 path (such as `C:\folder\program.exe`),
which will disrupt the existing `process_path` use cases in Windows.
2024-05-18 17:22:14 +08:00
世界
daee0b154e badtls: Support uTLS and TLS ECH for read waiter 2024-05-18 17:22:14 +08:00
世界
d530c724c0 Bump version 2024-05-18 16:53:05 +08:00
世界
7f698c1104 Fix hysteria2 panic 2024-05-18 16:20:32 +08:00
renovate[bot]
7a4a44c6d2 [dependencies] Update golangci/golangci-lint-action action to v6 2024-05-10 19:49:20 +08:00
世界
44277e5dd2 Fix urltest logic 2024-05-10 17:41:20 +08:00
世界
1f470c69c4 Update docker workflow 2024-05-03 19:33:20 +08:00
世界
742adacce7 Bump version 2024-05-03 17:38:26 +08:00
世界
32e1d5a5e2 documentation: Update package status 2024-05-03 17:38:26 +08:00
世界
cb9f4ce597 Minor fixes 2024-05-03 15:34:47 +08:00
世界
4b1a6185ba Fix DNF repo 2024-04-29 23:13:04 +08:00
世界
8d85c92356 Fix multiplex client dialer context 2024-04-29 11:58:20 +08:00
世界
c6164c9eca Fix usage of github actions 2024-04-29 11:58:20 +08:00
dyhkwong
3c85b8bc48 Fix fake-ip mapping 2024-04-29 11:58:20 +08:00
HystericalDragon
8b8fb4344c Remove unused encoder 2024-04-29 11:58:20 +08:00
renovate[bot]
e85a38e059 [dependencies] Update golangci/golangci-lint-action action to v5 2024-04-29 11:58:20 +08:00
renovate[bot]
f3ac91673a [dependencies] Update actions/checkout digest to 0ad4b8f 2024-04-29 11:58:20 +08:00
世界
0f1e58b917 documentation: Update TestFlight 2024-04-29 11:58:20 +08:00
世界
c4cfe24aef documentation: Fix strict_route description 2024-04-29 11:58:20 +08:00
世界
3d73b159ba Fix linux workflow 2024-04-29 11:58:20 +08:00
世界
0ae1afef44 Bump version 2024-04-23 14:14:40 +08:00
世界
a5e2a4073b Update dependencies 2024-04-23 14:03:55 +08:00
世界
b6cb3948a3 Fix initial packet MTU for QUIC protocols 2024-04-23 11:12:31 +08:00
世界
7b0f5061dc Fix loopback detector 2024-04-17 21:45:54 +08:00
世界
76f20482f7 Fix linux repo 2024-04-12 22:52:37 +08:00
世界
e735a5bdc8 Update dependencies 2024-04-12 22:52:37 +08:00
世界
70381e93c8 Bump version 2024-04-08 11:55:41 +08:00
世界
07a40716e8 Update dependencies 2024-04-08 11:45:00 +08:00
世界
5fea5956db Fix linux network monitor 2024-04-08 11:45:00 +08:00
世界
d20a389043 Fix timer usage 2024-04-08 11:45:00 +08:00
世界
4a4180bde5 Fixes for QUIC protocols 2024-04-08 11:44:55 +08:00
世界
7ecb6daabb Update dependencies 2024-03-29 04:52:06 +00:00
世界
712bdd9ae5 Fix fury release 2024-03-25 10:44:57 +08:00
世界
a3b74591a7 Fix syscall packet read waiter 2024-03-25 01:49:59 +08:00
世界
2f4abc6523 Fix canceler 2024-03-24 19:12:07 +08:00
dyhkwong
965ab075d9 Fix source_ip_is_private matching 2024-03-24 19:06:02 +08:00
世界
ed2f8b9637 Bump version 2024-03-23 20:50:45 +08:00
世界
0f71ce5120 tun: Fix GSO batch size 2024-03-22 14:54:57 +08:00
世界
f8085ab111 Fix Makefile 2024-03-21 23:32:02 +08:00
世界
f61b272cbf Fix WireGuard client bind 2024-03-20 10:52:24 +08:00
世界
59d437b9d2 Use local legacy compiler 2024-03-19 13:53:34 +08:00
世界
a7338fdc2b Fix DNS panic 2024-03-19 12:17:32 +08:00
Puqns67
d88860928e Fix the installation location of service files in prebuilded package 2024-03-19 12:13:59 +08:00
世界
20a2e38f47 Fix build for F-Droid 2024-03-17 21:43:22 +08:00
世界
acd438be23 Fix fury workflow 2024-03-17 21:43:22 +08:00
世界
e27fb51b54 Bump version 2024-03-16 12:05:58 +08:00
世界
adc38b26eb Fix Makefile 2024-03-15 18:06:37 +08:00
世界
7e943e743a Fix darwin interface monitor 2024-03-15 18:06:37 +08:00
世界
ceffcc0ad2 platform: Improve stop on apple platforms 2024-03-15 18:06:37 +08:00
世界
fdc451f7c6 platform: Fix missing log on apple platforms 2024-03-15 18:06:37 +08:00
世界
b48c471e6a Add repo release 2024-03-15 18:06:37 +08:00
世界
4b1fabd007 Fix lint workflow 2024-03-13 19:39:59 +08:00
世界
2b5eb1c59e Add sponsor link to issue template 2024-03-13 19:39:59 +08:00
世界
e2d3862e64 platform: reset network on invalid power events 2024-03-13 19:39:59 +08:00
世界
4f5e7b974d Fix crash in HTTP proxy server again 2024-03-10 16:53:58 +08:00
世界
21dedddd93 Update dependencies 2024-03-08 23:36:33 +08:00
世界
e02502bec0 Update go 1.20 2024-03-08 23:31:42 +08:00
世界
ba67633ee8 Fix missing source address in inbound logs in QUIC inbounds 2024-03-07 10:47:16 +08:00
世界
7fd9abe802 Bump version 2024-03-05 13:14:38 +08:00
世界
78a5f59202 documentation: Add link to F-Droid 2024-03-05 13:13:31 +08:00
世界
8d0da685d2 Update dependencies 2024-03-02 14:29:28 +08:00
世界
e6644f784e Fix crash in HTTP proxy server 2024-03-02 14:28:47 +08:00
世界
2b93b74d38 Fix SO_BINDTOIFINDEX usage 2024-02-29 13:03:05 +08:00
186 changed files with 3563 additions and 4081 deletions

View File

@@ -65,6 +65,12 @@ body:
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

View File

@@ -65,6 +65,12 @@ body:
对于 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: 完整性要求

View File

@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
with:
fetch-depth: 0
- name: Setup Go
@@ -38,7 +38,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
with:
fetch-depth: 0
- name: Setup Go
@@ -58,7 +58,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
with:
fetch-depth: 0
- name: Setup Go
@@ -78,7 +78,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
with:
fetch-depth: 0
- name: Setup Go
@@ -208,7 +208,7 @@ jobs:
TAGS: with_clash_api,with_quic
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
with:
fetch-depth: 0
- name: Setup Go

View File

@@ -1,39 +1,133 @@
name: Build Docker Images
name: Publish Docker Images
on:
release:
types:
- released
- published
workflow_dispatch:
inputs:
tag:
description: "The tag version you want to build"
env:
REGISTRY_IMAGE: ghcr.io/sagernet/sing-box
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
platform:
- linux/amd64
- linux/arm/v6
- linux/arm/v7
- linux/arm64
- linux/386
- linux/ppc64le
- linux/riscv64
- linux/s390x
steps:
- name: Get commit to build
id: ref
run: |-
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
ref="${{ github.ref_name }}"
else
ref="${{ github.event.inputs.tag }}"
fi
echo "ref=$ref"
echo "ref=$ref" >> $GITHUB_OUTPUT
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
with:
ref: ${{ steps.ref.outputs.ref }}
fetch-depth: 0
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Setup QEMU for Docker Buildx
uses: docker/setup-qemu-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: metadata
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/sagernet/sing-box
- name: Build and release Docker images
uses: docker/build-push-action@v5
images: ${{ env.REGISTRY_IMAGE }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
platforms: linux/386,linux/amd64,linux/arm64,linux/s390x
target: dist
platforms: ${{ matrix.platform }}
context: .
build-args: |
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
tags: |
ghcr.io/sagernet/sing-box:latest
ghcr.io/sagernet/sing-box:${{ github.ref_name }}
push: true
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Get commit to build
id: ref
run: |-
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
ref="${{ github.ref_name }}"
else
ref="${{ github.event.inputs.tag }}"
fi
echo "ref=$ref"
echo "ref=$ref" >> $GITHUB_OUTPUT
if [[ $ref == *"-"* ]]; then
latest=latest-beta
else
latest=latest
fi
echo "latest=$latest"
echo "latest=$latest" >> $GITHUB_OUTPUT
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create \
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}" \
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}" \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}

View File

@@ -22,19 +22,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.22
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ steps.version.outputs.go_version }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: --timeout=30m

39
.github/workflows/linux.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Release to Linux repository
on:
release:
types:
- published
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # 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 }}
echo "HOME=$HOME" >> "$GITHUB_ENV"
EOF
echo "HOME=$HOME" >> "$GITHUB_ENV"
- name: Publish release
uses: goreleaser/goreleaser-action@v6
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 }}

View File

@@ -12,4 +12,5 @@ jobs:
with:
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
days-before-stale: 60
days-before-close: 5
days-before-close: 5
exempt-issue-labels: 'bug,enhancement'

2
.gitignore vendored
View File

@@ -14,3 +14,5 @@
/*.xcframework/
.DS_Store
/config.d/
/venv/

View File

@@ -6,14 +6,7 @@ linters:
- gci
- staticcheck
- paralleltest
run:
skip-dirs:
- transport/simple-obfs
- transport/clashssr
- transport/cloudflaretls
- transport/shadowtls/tls
- transport/shadowtls/tls_go119
- ineffassign
linters-settings:
gci:
@@ -23,4 +16,13 @@ linters-settings:
- prefix(github.com/sagernet/)
- default
staticcheck:
go: '1.20'
checks:
- all
- -SA1003
run:
go: "1.23"
issues:
exclude-dirs:
- transport/simple-obfs

87
.goreleaser.fury.yaml Normal file
View File

@@ -0,0 +1,87 @@
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
- linux_mips64le
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
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,12 +1,15 @@
project_name: sing-box
builds:
- id: main
- &template
id: main
main: ./cmd/sing-box
flags:
- -v
- -trimpath
ldflags:
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }}
- -s
- -buildid=
tags:
- with_gvisor
- with_quic
@@ -24,24 +27,20 @@ builds:
- linux_amd64_v1
- linux_amd64_v3
- linux_arm64
- linux_arm_6
- linux_arm_7
- linux_s390x
- linux_riscv64
- linux_mips64le
- windows_amd64_v1
- windows_amd64_v3
- windows_386
- windows_arm64
- darwin_amd64_v1
- darwin_amd64_v3
- darwin_arm64
mod_timestamp: '{{ .CommitTimestamp }}'
- id: legacy
main: ./cmd/sing-box
flags:
- -v
- -trimpath
ldflags:
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
<<: *template
tags:
- with_gvisor
- with_quic
@@ -53,30 +52,14 @@ builds:
- with_clash_api
env:
- CGO_ENABLED=0
- GOROOT=/nix/store/kg6i737jjqs923jcijnm003h68c1dghj-go-1.20.11/share/go
gobinary: /nix/store/kg6i737jjqs923jcijnm003h68c1dghj-go-1.20.11/bin/go
- GOROOT={{ .Env.GOPATH }}/go1.20.14
gobinary: "{{ .Env.GOPATH }}/go1.20.14/bin/go"
targets:
- windows_amd64_v1
- windows_386
- darwin_amd64_v1
mod_timestamp: '{{ .CommitTimestamp }}'
- id: android
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
<<: *template
env:
- CGO_ENABLED=1
overrides:
@@ -107,11 +90,11 @@ builds:
- android_arm64
- android_386
- android_amd64
mod_timestamp: '{{ .CommitTimestamp }}'
snapshot:
name_template: "{{ .Version }}.{{ .ShortCommit }}"
archives:
- id: archive
- &template
id: archive
builds:
- main
- android
@@ -124,21 +107,16 @@ 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 }}'
vendor: sagernet
builds:
- main
homepage: https://sing-box.sagernet.org/
maintainer: nekohasekai <contact-git@sekai.icu>
description: The universal proxy platform.
@@ -153,11 +131,27 @@ nfpms:
dst: /etc/sing-box/config.json
type: config
- src: release/config/sing-box.service
dst: /etc/systemd/system/sing-box.service
dst: /usr/lib/systemd/system/sing-box.service
- src: release/config/sing-box@.service
dst: /etc/systemd/system/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 }}"
overrides:
deb:
conflicts:
- sing-box-beta
rpm:
conflicts:
- sing-box-beta
source:
enabled: false
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
@@ -171,6 +165,10 @@ release:
github:
owner: SagerNet
name: sing-box
name_template: '{{ if .IsSnapshot }}{{ nightly }}{{ else }}{{ .Version }}{{ end }}'
draft: true
mode: replace
prerelease: auto
mode: replace
ids:
- archive
- package
skip_upload: true

View File

@@ -15,7 +15,7 @@ MAIN_PARAMS = $(PARAMS) -tags $(TAGS)
MAIN = ./cmd/sing-box
PREFIX ?= $(shell go env GOPATH)
.PHONY: test release docs
.PHONY: test release docs build
build:
go build $(MAIN_PARAMS) $(MAIN)
@@ -64,7 +64,7 @@ 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 || exit 1
go run ./cmd/internal/build goreleaser release --clean --skip publish
mkdir dist/release
mv dist/*.tar.gz \
dist/*.zip \
@@ -77,15 +77,17 @@ 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:assemblePlayRelease && ./gradlew :app:assembleOtherRelease && ./gradlew --stop
cd ../sing-box-for-android && ./gradlew :app:clean :app:assemblePlayRelease :app:assembleOtherRelease && ./gradlew --stop
upload_android:
mkdir -p dist/release_android
@@ -102,10 +104,12 @@ publish_android:
publish_android_appcenter:
cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadPlayRelease
# TODO: find why and remove `-destination 'generic/platform=iOS'`
build_ios:
cd ../sing-box-for-apple && \
rm -rf build/SFI.xcarchive && \
xcodebuild archive -scheme SFI -configuration Release -archivePath build/SFI.xcarchive
xcodebuild archive -scheme SFI -configuration Release -destination 'generic/platform=iOS' -archivePath build/SFI.xcarchive -allowProvisioningUpdates
upload_ios_app_store:
cd ../sing-box-for-apple && \
@@ -116,55 +120,61 @@ release_ios: build_ios upload_ios_app_store
build_macos:
cd ../sing-box-for-apple && \
rm -rf build/SFM.xcarchive && \
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive -allowProvisioningUpdates
upload_macos_app_store:
cd ../sing-box-for-apple && \
xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
release_macos: build_macos upload_macos_app_store
build_macos_independent:
build_macos_standalone:
cd ../sing-box-for-apple && \
rm -rf build/SFT.System.xcarchive && \
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive
rm -rf build/SFM.System.xcarchive && \
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive -allowProvisioningUpdates
notarize_macos_independent:
cd ../sing-box-for-apple && \
xcodebuild -exportArchive -archivePath "build/SFM.System.xcarchive" -exportOptionsPlist SFM.System/Upload.plist -allowProvisioningUpdates
wait_notarize_macos_independent:
sleep 60
export_macos_independent:
build_macos_dmg:
rm -rf dist/SFM
mkdir -p dist/SFM
cd ../sing-box-for-apple && \
xcodebuild -exportNotarizedApp -archivePath build/SFM.System.xcarchive -exportPath "../sing-box/dist/SFM"
rm -rf build/SFM.System && \
rm -rf build/SFM.dmg && \
xcodebuild -exportArchive \
-archivePath "build/SFM.System.xcarchive" \
-exportOptionsPlist SFM.System/Export.plist -allowProvisioningUpdates \
-exportPath "build/SFM.System" && \
create-dmg \
--volname "sing-box" \
--volicon "build/SFM.System/SFM.app/Contents/Resources/AppIcon.icns" \
--icon "SFM.app" 0 0 \
--hide-extension "SFM.app" \
--app-drop-link 0 0 \
--skip-jenkins \
--notarize "notarytool-password" \
"../sing-box/dist/SFM/SFM.dmg" "build/SFM.System/SFM.app"
upload_macos_independent:
upload_macos_dmg:
cd dist/SFM && \
rm -f *.zip && \
zip -ry "SFM-${VERSION}-universal.zip" SFM.app && \
ghr --replace --draft --prerelease "v${VERSION}" *.zip
cp SFM.dmg "SFM-${VERSION}-universal.dmg" && \
ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dmg"
release_macos_independent: build_macos_independent notarize_macos_independent wait_notarize_macos_independent export_macos_independent upload_macos_independent
release_macos_standalone: build_macos_standalone build_macos_dmg upload_macos_dmg
build_tvos:
cd ../sing-box-for-apple && \
rm -rf build/SFT.xcarchive && \
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive -allowProvisioningUpdates
upload_tvos_app_store:
cd ../sing-box-for-apple && \
xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
release_tvos: build_tvos upload_tvos_app_store
update_apple_version:
go run ./cmd/internal/update_apple_version
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_independent
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos
release_apple_beta: update_apple_version release_ios release_macos release_tvos
@@ -191,17 +201,19 @@ 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.4
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.4
docs:
mkdocs serve
venv/bin/mkdocs serve
publish_docs:
mkdocs gh-deploy -m "Update" --force --ignore-version --no-history
venv/bin/mkdocs gh-deploy -m "Update" --force --ignore-version --no-history
docs_install:
pip install --force-reinstall mkdocs-material=="9.*" mkdocs-static-i18n=="1.2.*"
python -m venv venv
source ./venv/bin/activate && pip install --force-reinstall mkdocs-material=="9.*" mkdocs-static-i18n=="1.2.*"
clean:
rm -rf bin dist sing-box
rm -f $(shell go env GOPATH)/sing-box

View File

@@ -8,10 +8,6 @@ The universal proxy platform.
https://sing-box.sagernet.org
## Support
https://community.sagernet.org/c/sing-box/
## License
```

View File

@@ -9,6 +9,7 @@ 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"
)
@@ -30,6 +31,9 @@ type CacheFile interface {
StoreFakeIP() bool
FakeIPStorage
StoreRDRC() bool
dns.RDRCStore
LoadMode() string
StoreMode(mode string) error
LoadSelected(group string) string

View File

@@ -51,11 +51,13 @@ type InboundContext struct {
// rule cache
IPCIDRMatchSource bool
SourceAddressMatch bool
SourcePortMatch bool
DestinationAddressMatch bool
DestinationPortMatch bool
IPCIDRMatchSource bool
SourceAddressMatch bool
SourcePortMatch bool
DestinationAddressMatch bool
DestinationPortMatch bool
DidMatch bool
IgnoreDestinationIPCIDRMatch bool
}
func (c *InboundContext) ResetRuleCache() {
@@ -64,6 +66,7 @@ func (c *InboundContext) ResetRuleCache() {
c.SourcePortMatch = false
c.DestinationAddressMatch = false
c.DestinationPortMatch = false
c.DidMatch = false
}
type inboundContextKey struct{}
@@ -96,3 +99,12 @@ func ExtendContext(ctx context.Context) (context.Context, *InboundContext) {
}
return WithContext(ctx, &newMetadata), &newMetadata
}
func OverrideContext(ctx context.Context) context.Context {
if metadata := ContextFrom(ctx); metadata != nil {
var newMetadata InboundContext
newMetadata = *metadata
return WithContext(ctx, &newMetadata)
}
return ctx
}

View File

@@ -71,6 +71,7 @@ func RouterFromContext(ctx context.Context) Router {
type HeadlessRule interface {
Match(metadata *InboundContext) bool
String() string
}
type Rule interface {
@@ -79,18 +80,19 @@ type Rule interface {
Type() string
UpdateGeosite() error
Outbound() string
String() string
}
type DNSRule interface {
Rule
DisableCache() bool
RewriteTTL() *uint32
ClientSubnet() *netip.Prefix
WithAddressLimit() bool
MatchAddressLimit(metadata *InboundContext) bool
}
type RuleSet interface {
StartContext(ctx context.Context, startContext RuleSetStartContext) error
PostStart() error
Metadata() RuleSetMetadata
Close() error
HeadlessRule
@@ -99,6 +101,7 @@ type RuleSet interface {
type RuleSetMetadata struct {
ContainsProcessRule bool
ContainsWIFIRule bool
ContainsIPCIDRRule bool
}
type RuleSetStartContext interface {

View File

@@ -22,4 +22,5 @@ type V2RayServerTransportHandler interface {
type V2RayClientTransport interface {
DialContext(ctx context.Context) (net.Conn, error)
Close() error
}

10
box.go
View File

@@ -203,7 +203,7 @@ func (s *Box) PreStart() error {
defer func() {
v := recover()
if v != nil {
log.Error(E.Cause(err, "origin error"))
println(err.Error())
debug.PrintStack()
panic("panic on early close: " + fmt.Sprint(v))
}
@@ -222,9 +222,9 @@ func (s *Box) Start() error {
defer func() {
v := recover()
if v != nil {
log.Error(E.Cause(err, "origin error"))
println(err.Error())
debug.PrintStack()
panic("panic on early close: " + fmt.Sprint(v))
println("panic on early start: " + fmt.Sprint(v))
}
}()
s.Close()
@@ -235,7 +235,7 @@ func (s *Box) Start() error {
}
func (s *Box) preStart() error {
monitor := taskmonitor.New(s.logger, C.DefaultStartTimeout)
monitor := taskmonitor.New(s.logger, C.StartTimeout)
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.DefaultStopTimeout)
monitor := taskmonitor.New(s.logger, C.StopTimeout)
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.DefaultStartTimeout)
monitor := taskmonitor.New(s.logger, C.StartTimeout)
outboundTags := make(map[adapter.Outbound]string)
outbounds := make(map[string]adapter.Outbound)
for i, outboundToStart := range s.outbounds {

View File

@@ -26,8 +26,8 @@ func main() {
common.Must(decoder.Decode(&project))
objectsMap := project["objects"].(map[string]any)
projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfa"}, newVersion.VersionString())
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfa.independent", "io.nekohasekai.sfa.system"}, newVersion.String())
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfavt"}, newVersion.VersionString())
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfavt.standalone", "io.nekohasekai.sfavt.system"}, newVersion.String())
if updated0 || updated1 {
log.Info("updated version to ", newVersion.VersionString(), " (", newVersion.String(), ")")
}

View File

@@ -0,0 +1,87 @@
package main
import (
"bytes"
"io"
"os"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/srs"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/route"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json"
"github.com/spf13/cobra"
)
var flagRuleSetMatchFormat string
var commandRuleSetMatch = &cobra.Command{
Use: "match <rule-set path> <domain>",
Short: "Check if a domain matches the rule set",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
err := ruleSetMatch(args[0], args[1])
if err != nil {
log.Fatal(err)
}
},
}
func init() {
commandRuleSetMatch.Flags().StringVarP(&flagRuleSetMatchFormat, "format", "f", "source", "rule-set format")
commandRuleSet.AddCommand(commandRuleSetMatch)
}
func ruleSetMatch(sourcePath string, domain string) error {
var (
reader io.Reader
err error
)
if sourcePath == "stdin" {
reader = os.Stdin
} else {
reader, err = os.Open(sourcePath)
if err != nil {
return E.Cause(err, "read rule-set")
}
}
content, err := io.ReadAll(reader)
if err != nil {
return E.Cause(err, "read rule-set")
}
var plainRuleSet option.PlainRuleSet
switch flagRuleSetMatchFormat {
case C.RuleSetFormatSource:
var compat option.PlainRuleSetCompat
compat, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
if err != nil {
return err
}
plainRuleSet = compat.Upgrade()
case C.RuleSetFormatBinary:
plainRuleSet, err = srs.Read(bytes.NewReader(content), false)
if err != nil {
return err
}
default:
return E.New("unknown rule set format: ", flagRuleSetMatchFormat)
}
for i, ruleOptions := range plainRuleSet.Rules {
var currentRule adapter.HeadlessRule
currentRule, err = route.NewHeadlessRule(nil, ruleOptions)
if err != nil {
return E.Cause(err, "parse rule_set.rules.[", i, "]")
}
if currentRule.Match(&adapter.InboundContext{
Domain: domain,
}) {
println(F.ToString("match rules.[", i, "]: ", currentRule))
}
}
return nil
}

View File

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

View File

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

View File

@@ -0,0 +1,31 @@
//go:build go1.21 && !without_badtls && with_ech
package badtls
import (
"net"
_ "unsafe"
"github.com/sagernet/cloudflare-tls"
"github.com/sagernet/sing/common"
)
func init() {
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
tlsConn, loaded := common.Cast[*tls.Conn](conn)
if !loaded {
return
}
return true, func() error {
return echReadRecord(tlsConn)
}, func() error {
return echHandlePostHandshakeMessage(tlsConn)
}
})
}
//go:linkname echReadRecord github.com/sagernet/cloudflare-tls.(*Conn).readRecord
func echReadRecord(c *tls.Conn) error
//go:linkname echHandlePostHandshakeMessage github.com/sagernet/cloudflare-tls.(*Conn).handlePostHandshakeMessage
func echHandlePostHandshakeMessage(c *tls.Conn) error

View File

@@ -0,0 +1,31 @@
//go:build go1.21 && !without_badtls && with_utls
package badtls
import (
"net"
_ "unsafe"
"github.com/sagernet/sing/common"
"github.com/sagernet/utls"
)
func init() {
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
tlsConn, loaded := common.Cast[*tls.UConn](conn)
if !loaded {
return
}
return true, func() error {
return utlsReadRecord(tlsConn.Conn)
}, func() error {
return utlsHandlePostHandshakeMessage(tlsConn.Conn)
}
})
}
//go:linkname utlsReadRecord github.com/sagernet/utls.(*Conn).readRecord
func utlsReadRecord(c *tls.Conn) error
//go:linkname utlsHandlePostHandshakeMessage github.com/sagernet/utls.(*Conn).handlePostHandshakeMessage
func utlsHandlePostHandshakeMessage(c *tls.Conn) error

View File

@@ -32,14 +32,20 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
var dialer net.Dialer
var listener net.ListenConfig
if options.BindInterface != "" {
bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
var interfaceFinder control.InterfaceFinder
if router != nil {
interfaceFinder = router.InterfaceFinder()
} else {
interfaceFinder = control.NewDefaultInterfaceFinder()
}
bindFunc := control.BindToInterface(interfaceFinder, options.BindInterface, -1)
dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc)
} else if router.AutoDetectInterface() {
} else if router != nil && router.AutoDetectInterface() {
bindFunc := router.AutoDetectInterfaceFunc()
dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc)
} else if router.DefaultInterface() != "" {
} else if router != nil && router.DefaultInterface() != "" {
bindFunc := control.BindToInterface(router.InterfaceFinder(), router.DefaultInterface(), -1)
dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc)
@@ -47,7 +53,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
if options.RoutingMark != 0 {
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
} else if router.DefaultMark() != 0 {
} else if router != nil && router.DefaultMark() != 0 {
dialer.Control = control.Append(dialer.Control, control.RoutingMark(router.DefaultMark()))
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
}
@@ -63,6 +69,9 @@ 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

@@ -5,7 +5,7 @@ package dialer
import (
"net"
"github.com/sagernet/tfo-go"
"github.com/metacubex/tfo-go"
)
type tcpDialer = tfo.Dialer

View File

@@ -13,6 +13,9 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
if options.IsWireGuardListener {
return NewDefault(router, options)
}
if router == nil {
return NewDefault(nil, options)
}
var (
dialer N.Dialer
err error
@@ -25,13 +28,12 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
} else {
dialer = NewDetour(router, options.Detour)
}
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {
if options.Detour == "" {
dialer = NewResolveDialer(
router,
dialer,
options.Detour == "" && !options.TCPFastOpen,
domainStrategy,
dns.DomainStrategy(options.DomainStrategy),
time.Duration(options.FallbackDelay))
}
return dialer, nil

View File

@@ -15,7 +15,8 @@ import (
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/tfo-go"
"github.com/metacubex/tfo-go"
)
type slowOpenConn struct {

View File

@@ -1,11 +1,16 @@
package mux
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-mux"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
@@ -30,7 +35,7 @@ func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.
}
}
return mux.NewClient(mux.Options{
Dialer: dialer,
Dialer: &clientDialer{dialer},
Logger: logger,
Protocol: options.Protocol,
MaxConnections: options.MaxConnections,
@@ -40,3 +45,15 @@ func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.
Brutal: brutalOptions,
})
}
type clientDialer struct {
N.Dialer
}
func (d *clientDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
return d.Dialer.DialContext(adapter.OverrideContext(ctx), network, destination)
}
func (d *clientDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return d.Dialer.ListenPacket(adapter.OverrideContext(ctx), destination)
}

View File

@@ -60,12 +60,12 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
isIPv4 := ip.Is4()
value, err := syscall.Sysctl(spath)
value, err := unix.SysctlRaw(spath)
if err != nil {
return "", err
}
buf := []byte(value)
buf := value
// from darwin-xnu/bsd/netinet/in_pcblist.c:get_pcblist_n
// size/offset are round up (aligned) to 8 bytes in darwin

View File

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

View File

@@ -16,30 +16,40 @@ import (
)
type LinuxSystemProxy struct {
hasGSettings bool
hasKWriteConfig5 bool
sudoUser string
serverAddr M.Socksaddr
supportSOCKS bool
isEnabled bool
hasGSettings bool
kWriteConfigCmd string
sudoUser string
serverAddr M.Socksaddr
supportSOCKS bool
isEnabled bool
}
func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*LinuxSystemProxy, error) {
hasGSettings := common.Error(exec.LookPath("gsettings")) == nil
hasKWriteConfig5 := common.Error(exec.LookPath("kwriteconfig5")) == nil
kWriteConfigCmds := []string{
"kwriteconfig5",
"kwriteconfig6",
}
var kWriteConfigCmd string
for _, cmd := range kWriteConfigCmds {
if common.Error(exec.LookPath(cmd)) == nil {
kWriteConfigCmd = cmd
break
}
}
var sudoUser string
if os.Getuid() == 0 {
sudoUser = os.Getenv("SUDO_USER")
}
if !hasGSettings && !hasKWriteConfig5 {
if !hasGSettings && kWriteConfigCmd == "" {
return nil, E.New("unsupported desktop environment")
}
return &LinuxSystemProxy{
hasGSettings: hasGSettings,
hasKWriteConfig5: hasKWriteConfig5,
sudoUser: sudoUser,
serverAddr: serverAddr,
supportSOCKS: supportSOCKS,
hasGSettings: hasGSettings,
kWriteConfigCmd: kWriteConfigCmd,
sudoUser: sudoUser,
serverAddr: serverAddr,
supportSOCKS: supportSOCKS,
}, nil
}
@@ -70,8 +80,8 @@ func (p *LinuxSystemProxy) Enable() error {
return err
}
}
if p.hasKWriteConfig5 {
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
if p.kWriteConfigCmd != "" {
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
if err != nil {
return err
}
@@ -83,7 +93,7 @@ func (p *LinuxSystemProxy) Enable() error {
if err != nil {
return err
}
err = p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
err = p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
if err != nil {
return err
}
@@ -103,8 +113,8 @@ func (p *LinuxSystemProxy) Disable() error {
return err
}
}
if p.hasKWriteConfig5 {
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
if p.kWriteConfigCmd != "" {
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
if err != nil {
return err
}
@@ -150,7 +160,7 @@ func (p *LinuxSystemProxy) setKDEProxy(proxyTypes ...string) error {
proxyUrl = "http://" + p.serverAddr.String()
}
err := p.runAsUser(
"kwriteconfig5",
p.kWriteConfigCmd,
"--file",
"kioslaverc",
"--group",

View File

@@ -18,28 +18,45 @@ type (
PacketSniffer = func(ctx context.Context, packet []byte) (*adapter.InboundContext, error)
)
func Skip(metadata adapter.InboundContext) bool {
// skip server first protocols
switch metadata.Destination.Port {
case 25, 465, 587:
// SMTP
return true
case 143, 993:
// IMAP
return true
case 110, 995:
// POP3
return true
}
return false
}
func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) (*adapter.InboundContext, error) {
if timeout == 0 {
timeout = C.ReadPayloadTimeout
}
deadline := time.Now().Add(timeout)
var errors []error
for i := 0; i < 3; i++ {
for i := 0; ; i++ {
err := conn.SetReadDeadline(deadline)
if err != nil {
return nil, E.Cause(err, "set read deadline")
}
_, err = buffer.ReadOnceFrom(conn)
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
_ = conn.SetReadDeadline(time.Time{})
if err != nil {
if i > 0 {
break
}
return nil, E.Cause(err, "read payload")
}
errors = nil
var metadata *adapter.InboundContext
for _, sniffer := range sniffers {
metadata, err := sniffer(ctx, bytes.NewReader(buffer.Bytes()))
metadata, err = sniffer(ctx, bytes.NewReader(buffer.Bytes()))
if metadata != nil {
return metadata, nil
}

View File

@@ -27,11 +27,10 @@ func (c *echClientConfig) DialEarly(ctx context.Context, conn net.PacketConn, ad
return quic.DialEarly(ctx, conn, addr, c.config, config)
}
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config, enableDatagrams bool) http.RoundTripper {
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config) http.RoundTripper {
return &http3.RoundTripper{
TLSClientConfig: c.config,
QuicConfig: quicConfig,
EnableDatagrams: enableDatagrams,
QUICConfig: quicConfig,
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
quicConn, err := quic.DialEarly(ctx, conn, serverAddr.UDPAddr(), tlsCfg, cfg)
if err != nil {

5
constant/quic.go Normal file
View File

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

5
constant/quic_stub.go Normal file
View File

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

View File

@@ -3,15 +3,18 @@ package constant
import "time"
const (
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
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
)

View File

@@ -2,14 +2,344 @@
icon: material/alert-decagram
---
### 1.9.6
* Fixes and improvements
### 1.9.5
* Update quic-go to v0.47.0
* Fix direct dialer not resolving domain
* Fix no error return when empty DNS cache retrieved
* Fix build with go1.23
* Fix stream sniffer
* Fix bad redirect in clash-api
* Fix wireguard events chan leak
* Fix cached conn eats up read deadlines
* Fix disconnected interface selected as default in windows
* Update Bundle Identifiers for Apple platform clients **1**
**1**:
See [Migration](/migration/#bundle-identifier-updates-in-apple-platform-clients).
We are still working on getting all sing-box apps back on the App Store.
This work is expected to be completed within a week
(SFI on the App Store and others on TestFlight are already available).
### 1.9.4
* Update quic-go to v0.46.0
* Update Hysteria2 BBR congestion control
* Filter HTTPS ipv4hint/ipv6hint with domain strategy
* Fix crash on Android when using process rules
* Fix non-IP queries accepted by address filter rules
* Fix UDP server for shadowsocks AEAD multi-user inbounds
* Fix default next protos for v2ray QUIC transport
* Fix default end value of port range configuration options
* Fix reset v2ray transports
* Fix panic caused by rule-set generation of duplicate keys for `domain_suffix`
* Fix UDP connnection leak when sniffing
* Fixes and improvements
_Due to problems with our Apple developer account,
sing-box apps on Apple platforms are temporarily unavailable for download or update.
If your company or organization is willing to help us return to the App Store,
please [contact us](mailto:contact@sagernet.org)._
### 1.9.3
* Fixes and improvements
### 1.9.2
* Fixes and improvements
### 1.9.1
* Fixes and improvements
### 1.9.0
* Fixes and improvements
Important changes since 1.8:
* `domain_suffix` behavior update **1**
* `process_path` format update on Windows **2**
* Add address filter DNS rule items **3**
* Add support for `client-subnet` DNS options **4**
* Add rejected DNS response cache support **5**
* Add `bypass_domain` and `search_domain` platform HTTP proxy options **6**
* Fix missing `rule_set_ipcidr_match_source` item in DNS rules **7**
* Handle Windows power events
* Always disable cache for fake-ip DNS transport if `dns.independent_cache` disabled
* Improve DNS truncate behavior
* Update Hysteria protocol
* Update quic-go to v0.43.1
* Update gVisor to 20240422.0
* Mitigating TunnelVision attacks **8**
**1**:
See [Migration](/migration/#domain_suffix-behavior-update).
**2**:
See [Migration](/migration/#process_path-format-update-on-windows).
**3**:
The new DNS feature allows you to more precisely bypass Chinese websites via **DNS leaks**. Do not use plain local DNS
if using this method.
See [Address Filter Fields](/configuration/dns/rule#address-filter-fields).
[Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) updated.
**4**:
See [DNS](/configuration/dns), [DNS Server](/configuration/dns/server) and [DNS Rules](/configuration/dns/rule).
Since this feature makes the scenario mentioned in `alpha.1` no longer leak DNS requests,
the [Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) has been updated.
**5**:
The new feature allows you to cache the check results of
[Address filter DNS rule items](/configuration/dns/rule/#address-filter-fields) until expiration.
**6**:
See [TUN](/configuration/inbound/tun) inbound.
**7**:
See [DNS Rule](/configuration/dns/rule/).
**8**:
See [TunnelVision](/manual/misc/tunnelvision).
#### 1.9.0-rc.22
* Fixes and improvements
#### 1.9.0-rc.20
* Prioritize `*_route_address` in linux auto-route
* Fix `*_route_address` in darwin auto-route
#### 1.8.14
* Fix hysteria2 panic
* Fixes and improvements
#### 1.9.0-rc.18
* Add custom prefix support in EDNS0 client subnet options
* Fix hysteria2 crash
* Fix `store_rdrc` corrupted
* Update quic-go to v0.43.1
* Fixes and improvements
#### 1.9.0-rc.16
* Mitigating TunnelVision attacks **1**
* Fixes and improvements
**1**:
See [TunnelVision](/manual/misc/tunnelvision).
#### 1.9.0-rc.15
* Fixes and improvements
#### 1.8.13
* Fix fake-ip mapping
* Fixes and improvements
#### 1.9.0-rc.14
* Fixes and improvements
#### 1.9.0-rc.13
* Update Hysteria protocol
* Update quic-go to v0.43.0
* Update gVisor to 20240422.0
* Fixes and improvements
#### 1.8.12
* Now we have official APT and DNF repositories **1**
* Fix packet MTU for QUIC protocols
* Fixes and improvements
**1**:
Including stable and beta versions, see https://sing-box.sagernet.org/installation/package-manager/
#### 1.9.0-rc.11
* Fixes and improvements
#### 1.8.11
* Fixes and improvements
#### 1.8.10
* 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
@@ -26,7 +356,7 @@ icon: material/alert-decagram
* Fixes and improvements
#### 1.8.0
### 1.8.0
* Fixes and improvements
@@ -108,8 +438,8 @@ 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`
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
@@ -317,7 +647,7 @@ New commands manage GeoIP, Geosite and rule set resources, and help you migrate
Logical rules in route rules, DNS rules, and the new headless rule now allow nesting of logical rules.
#### 1.7.0
### 1.7.0
* Fixes and improvements
@@ -359,7 +689,7 @@ see [TCP Brutal](/configuration/shared/tcp-brutal/) for details.
**5**:
Only supported in graphical clients on Android and iOS.
Only supported in graphical clients on Android and Apple platforms.
#### 1.7.0-rc.3
@@ -396,7 +726,7 @@ Only supported in graphical clients on Android and iOS.
**1**:
Only supported in graphical clients on Android and iOS.
Only supported in graphical clients on Android and Apple platforms.
#### 1.7.0-beta.3
@@ -477,7 +807,7 @@ Introduced in V2Ray 5.10.0.
The new HTTPUpgrade transport has better performance than WebSocket and is better suited for CDN abuse.
#### 1.6.0
### 1.6.0
* Fixes and improvements
@@ -656,7 +986,7 @@ introduce new issues.
None of the existing Golang BBR congestion control implementations have been reviewed or unit tested.
This update is intended to address the multi-send defects of the old implementation and may introduce new issues.
#### 1.5.0
### 1.5.0
* Fixes and improvements
@@ -850,7 +1180,7 @@ All inbounds and outbounds are supported, including `Naiveproxy`, `Hysteria`, `T
* Fixes and improvements
#### 1.4.0
### 1.4.0
* Fix bugs and update dependencies
@@ -992,7 +1322,7 @@ The old testflight link and app are no longer valid.
* Fixes and improvements
#### 1.3.0
### 1.3.0
* Fix bugs and update dependencies
@@ -1184,7 +1514,7 @@ to `domain` rule.
* Flush DNS cache for macOS when tun start/close
* Fix tun's DNS hijacking compatibility with systemd-resolved
#### 1.2.0
### 1.2.0
* Fix bugs and update dependencies

View File

@@ -16,6 +16,7 @@ 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

@@ -14,8 +14,13 @@ 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)
* [App Store](https://apps.apple.com/app/sing-box-vt/id6673731168)
* TestFlight (Beta)
TestFlight quota is only available to [sponsors](https://github.com/sponsors/nekohasekai)
(one-time sponsorships are accepted).
Once you donate, you can get an invitation by join our Telegram group for sponsors from [@yet_another_sponsor_bot](https://t.me/yet_another_sponsor_bot)
or sending us your Apple ID [via email](mailto:contact@sagernet.org).
## :material-file-download: Download (macOS standalone version)

View File

@@ -2,11 +2,11 @@
由 Project S 维护,提供统一的体验与平台特定的功能。
| 平台 | 客户端 |
|---------------------------------------|-----------------------------------------|
| 平台 | 客户端 |
|---------------------------------------|------------------------------------------|
| :material-android: Android | [sing-box for Android](./android/) |
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
| :material-laptop: Desktop | 施工中 |
| :material-laptop: Desktop | 施工中 |
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
VPN 客户端功能, 但代码质量很差且包含广告。

View File

@@ -1,3 +1,11 @@
---
icon: material/new-box
---
!!! quote "Changes in sing-box 1.9.0"
:material-plus: [client_subnet](#client_subnet)
# DNS
### Structure
@@ -13,6 +21,7 @@
"disable_expire": false,
"independent_cache": false,
"reverse_mapping": false,
"client_subnet": "",
"fakeip": {}
}
}
@@ -21,8 +30,8 @@
### Fields
| Key | Format |
|----------|--------------------------------|
| Key | Format |
|----------|---------------------------------|
| `server` | List of [DNS Server](./server/) |
| `rules` | List of [DNS Rule](./rule/) |
| `fakeip` | [FakeIP](./fakeip/) |
@@ -60,6 +69,12 @@ Stores a reverse mapping of IP addresses after responding to a DNS query in orde
Since this process relies on the act of resolving domain names by an application before making a request, it can be
problematic in environments such as macOS, where DNS is proxied and cached by the system.
#### fakeip
#### client_subnet
[FakeIP](./fakeip/) settings.
!!! question "Since sing-box 1.9.0"
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
Can be overrides by `servers.[].client_subnet` or `rules.[].client_subnet`.

View File

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

View File

@@ -1,7 +1,15 @@
---
icon: material/alert-decagram
icon: material/new-box
---
!!! quote "Changes in sing-box 1.9.0"
:material-plus: [geoip](#geoip)
:material-plus: [ip_cidr](#ip_cidr)
:material-plus: [ip_is_private](#ip_is_private)
:material-plus: [client_subnet](#client_subnet)
:material-plus: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
!!! quote "Changes in sing-box 1.8.0"
:material-plus: [rule_set](#rule_set)
@@ -53,11 +61,19 @@ icon: material/alert-decagram
"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
],
@@ -101,13 +117,15 @@ icon: material/alert-decagram
"geoip-cn",
"geosite-cn"
],
"rule_set_ipcidr_match_source": false,
"invert": false,
"outbound": [
"direct"
],
"server": "local",
"disable_cache": false,
"rewrite_ttl": 100
"rewrite_ttl": 100,
"client_subnet": "127.0.0.1/24"
},
{
"type": "logical",
@@ -115,7 +133,8 @@ icon: material/alert-decagram
"rules": [],
"server": "local",
"disable_cache": false,
"rewrite_ttl": 100
"rewrite_ttl": 100,
"client_subnet": "127.0.0.1/24"
}
]
}
@@ -266,11 +285,9 @@ Match Clash mode.
#### wifi_ssid
<!-- md:version 1.7.0-beta.4 -->
!!! quote ""
Only supported in graphical clients on Android and iOS.
Only supported in graphical clients on Android and Apple platforms.
Match WiFi SSID.
@@ -278,7 +295,7 @@ Match WiFi SSID.
!!! quote ""
Only supported in graphical clients on Android and iOS.
Only supported in graphical clients on Android and Apple platforms.
Match WiFi BSSID.
@@ -288,6 +305,12 @@ 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.
@@ -312,6 +335,46 @@ 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 prefix to every query by default.
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
Will overrides `dns.client_subnet` and `servers.[].client_subnet`.
### Address Filter Fields
Only takes effect for IP address requests. When the query results do not match the address filtering rule items, the current rule will be skipped.
!!! info ""
`ip_cidr` items in included rule sets also takes effect as an address filtering field.
!!! note ""
Enable `experimental.cache_file.store_rdrc` to cache results.
#### geoip
!!! question "Since sing-box 1.9.0"
Match GeoIP with query response.
#### ip_cidr
!!! question "Since sing-box 1.9.0"
Match IP CIDR with query response.
#### ip_is_private
!!! question "Since sing-box 1.9.0"
Match private IP with query response.
### Logical Fields
#### type

View File

@@ -1,7 +1,15 @@
---
icon: material/alert-decagram
icon: material/new-box
---
!!! quote "sing-box 1.9.0 中的更改"
:material-plus: [geoip](#geoip)
:material-plus: [ip_cidr](#ip_cidr)
:material-plus: [ip_is_private](#ip_is_private)
:material-plus: [client_subnet](#client_subnet)
:material-plus: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
!!! quote "sing-box 1.8.0 中的更改"
:material-plus: [rule_set](#rule_set)
@@ -53,10 +61,19 @@ icon: material/alert-decagram
"source_geoip": [
"private"
],
"geoip": [
"cn"
],
"source_ip_cidr": [
"10.0.0.0/24"
"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
],
@@ -100,19 +117,22 @@ icon: material/alert-decagram
"geoip-cn",
"geosite-cn"
],
"rule_set_ipcidr_match_source": false,
"invert": false,
"outbound": [
"direct"
],
"server": "local",
"disable_cache": false
"disable_cache": false,
"client_subnet": "127.0.0.1/24"
},
{
"type": "logical",
"mode": "and",
"rules": [],
"server": "local",
"disable_cache": false
"disable_cache": false,
"client_subnet": "127.0.0.1/24"
}
]
}
@@ -265,7 +285,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
!!! quote ""
仅在 Android 与 iOS 的图形客户端中支持。
仅在 Android 与 Apple 平台图形客户端中支持。
匹配 WiFi SSID。
@@ -273,7 +293,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
!!! quote ""
仅在 Android 与 iOS 的图形客户端中支持。
仅在 Android 与 Apple 平台图形客户端中支持。
匹配 WiFi BSSID。
@@ -283,6 +303,12 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
匹配[规则集](/zh/configuration/route/#rule_set)。
#### rule_set_ipcidr_match_source
!!! question "自 sing-box 1.9.0 起"
使规则集中的 `ipcidr` 规则匹配源 IP。
#### invert
反选匹配结果。
@@ -307,6 +333,46 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
重写 DNS 回应中的 TTL。
#### client_subnet
!!! question "自 sing-box 1.9.0 起"
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
如果值是 IP 地址而不是前缀,则会自动附加 `/32``/128`
将覆盖 `dns.client_subnet``servers.[].client_subnet`
### 地址筛选字段
仅对IP地址请求生效。 当查询结果与地址筛选规则项不匹配时,将跳过当前规则。
!!! info ""
引用的规则集中的 `ip_cidr` 项也作为地址筛选字段生效。
!!! note ""
启用 `experimental.cache_file.store_rdrc` 以缓存结果。
#### geoip
!!! question "自 sing-box 1.9.0 起"
与查询响应匹配 GeoIP。
#### ip_cidr
!!! question "自 sing-box 1.9.0 起"
与查询相应匹配 IP CIDR。
#### ip_is_private
!!! question "自 sing-box 1.9.0 起"
与查询响应匹配非公开 IP。
### 逻辑字段
#### type
@@ -319,4 +385,4 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
#### rules
包括的规则。
包括的规则。

View File

@@ -1,3 +1,11 @@
---
icon: material/new-box
---
!!! quote "Changes in sing-box 1.9.0"
:material-plus: [client_subnet](#client_subnet)
### Structure
```json
@@ -5,17 +13,17 @@
"dns": {
"servers": [
{
"tag": "google",
"address": "tls://dns.google",
"address_resolver": "local",
"address_strategy": "prefer_ipv4",
"strategy": "ipv4_only",
"detour": "direct"
"tag": "",
"address": "",
"address_resolver": "",
"address_strategy": "",
"strategy": "",
"detour": "",
"client_subnet": ""
}
]
}
}
```
### Fields
@@ -80,10 +88,22 @@ Default domain strategy for resolving the domain names.
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
Take no effect if override by other settings.
Take no effect if overridden by other settings.
#### detour
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 prefix to every query by default.
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
Can be overrides by `rules.[].client_subnet`.
Will overrides `dns.client_subnet`.

View File

@@ -1,3 +1,11 @@
---
icon: material/new-box
---
!!! quote "sing-box 1.9.0 中的更改"
:material-plus: [client_subnet](#client_subnet)
### 结构
```json
@@ -5,17 +13,17 @@
"dns": {
"servers": [
{
"tag": "google",
"address": "tls://dns.google",
"address_resolver": "local",
"address_strategy": "prefer_ipv4",
"strategy": "ipv4_only",
"detour": "direct"
"tag": "",
"address": "",
"address_resolver": "",
"address_strategy": "",
"strategy": "",
"detour": "",
"client_subnet": ""
}
]
}
}
```
### 字段
@@ -87,3 +95,15 @@ DNS 服务器的地址。
用于连接到 DNS 服务器的出站的标签。
如果为空,将使用默认出站。
#### client_subnet
!!! question "自 sing-box 1.9.0 起"
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
如果值是 IP 地址而不是前缀,则会自动附加 `/32``/128`
可以被 `rules.[].client_subnet` 覆盖。
将覆盖 `dns.client_subnet`

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,3 @@
---
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 iOS without privileges, use tun.platform.http_proxy instead.
To work on Android and Apple platforms without privileges, use tun.platform.http_proxy instead.
Automatically set system proxy configuration when start and clean up when stop.

View File

@@ -15,24 +15,24 @@
### Fields
| Type | Format | Injectable |
|---------------|-------------------------------|------------|
| `direct` | [Direct](./direct/) | X |
| `mixed` | [Mixed](./mixed/) | TCP |
| `socks` | [SOCKS](./socks/) | TCP |
| `http` | [HTTP](./http/) | TCP |
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
| `vmess` | [VMess](./vmess/) | TCP |
| `trojan` | [Trojan](./trojan/) | TCP |
| `naive` | [Naive](./naive/) | X |
| `hysteria` | [Hysteria](./hysteria/) | X |
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
| `tuic` | [TUIC](./tuic/) | X |
| `hysteria2` | [Hysteria2](./hysteria2/) | X |
| `vless` | [VLESS](./vless/) | TCP |
| `tun` | [Tun](./tun/) | X |
| `redirect` | [Redirect](./redirect/) | X |
| `tproxy` | [TProxy](./tproxy/) | X |
| Type | Format | Injectable |
|---------------|-------------------------------|------------------|
| `direct` | [Direct](./direct/) | :material-close: |
| `mixed` | [Mixed](./mixed/) | TCP |
| `socks` | [SOCKS](./socks/) | TCP |
| `http` | [HTTP](./http/) | TCP |
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
| `vmess` | [VMess](./vmess/) | TCP |
| `trojan` | [Trojan](./trojan/) | TCP |
| `naive` | [Naive](./naive/) | :material-close: |
| `hysteria` | [Hysteria](./hysteria/) | :material-close: |
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
| `tuic` | [TUIC](./tuic/) | :material-close: |
| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: |
| `vless` | [VLESS](./vless/) | TCP |
| `tun` | [Tun](./tun/) | :material-close: |
| `redirect` | [Redirect](./redirect/) | :material-close: |
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
#### tag

View File

@@ -15,24 +15,24 @@
### 字段
| 类型 | 格式 | 注入支持 |
|---------------|------------------------------|------|
| `direct` | [Direct](./direct/) | X |
| `mixed` | [Mixed](./mixed/) | TCP |
| `socks` | [SOCKS](./socks/) | TCP |
| `http` | [HTTP](./http/) | TCP |
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
| `vmess` | [VMess](./vmess/) | TCP |
| `trojan` | [Trojan](./trojan/) | TCP |
| `naive` | [Naive](./naive/) | X |
| `hysteria` | [Hysteria](./hysteria/) | X |
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
| `tuic` | [TUIC](./tuic/) | X |
| `hysteria2` | [Hysteria2](./hysteria2/) | X |
| `vless` | [VLESS](./vless/) | TCP |
| `tun` | [Tun](./tun/) | X |
| `redirect` | [Redirect](./redirect/) | X |
| `tproxy` | [TProxy](./tproxy/) | X |
| 类型 | 格式 | 注入支持 |
|---------------|-------------------------------|------------------|
| `direct` | [Direct](./direct/) | :material-close: |
| `mixed` | [Mixed](./mixed/) | TCP |
| `socks` | [SOCKS](./socks/) | TCP |
| `http` | [HTTP](./http/) | TCP |
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
| `vmess` | [VMess](./vmess/) | TCP |
| `trojan` | [Trojan](./trojan/) | TCP |
| `naive` | [Naive](./naive/) | :material-close: |
| `hysteria` | [Hysteria](./hysteria/) | :material-close: |
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
| `tuic` | [TUIC](./tuic/) | :material-close: |
| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: |
| `vless` | [VLESS](./vless/) | TCP |
| `tun` | [Tun](./tun/) | :material-close: |
| `redirect` | [Redirect](./redirect/) | :material-close: |
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
#### tag

View File

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

View File

@@ -1,7 +1,12 @@
---
icon: material/alert-decagram
icon: material/new-box
---
!!! quote "Changes in sing-box 1.9.0"
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
:material-plus: [platform.http_proxy.match_domain](#platformhttp_proxymatch_domain)
!!! quote "Changes in sing-box 1.8.0"
:material-plus: [gso](#gso)
@@ -73,7 +78,9 @@ icon: material/alert-decagram
"http_proxy": {
"enabled": false,
"server": "127.0.0.1",
"server_port": 8080
"server_port": 8080,
"bypass_domain": [],
"match_domain": []
}
},
@@ -140,7 +147,7 @@ Enforce strict routing rules when `auto_route` is enabled:
* Let unsupported network unreachable
* Route all connections to tun
It prevents address leaks and makes DNS hijacking work on Android, but your device will not be accessible by others.
It prevents address leaks and makes DNS hijacking work on Android.
*In Windows*:
@@ -260,6 +267,38 @@ 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,7 +1,12 @@
---
icon: material/alert-decagram
icon: material/new-box
---
!!! quote "sing-box 1.9.0 中的更改"
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
:material-plus: [platform.http_proxy.match_domain](#platformhttp_proxymatch_domain)
!!! quote "sing-box 1.8.0 中的更改"
:material-plus: [gso](#gso)
@@ -73,7 +78,9 @@ icon: material/alert-decagram
"http_proxy": {
"enabled": false,
"server": "127.0.0.1",
"server_port": 8080
"server_port": 8080,
"bypass_domain": [],
"match_domain": []
}
},
@@ -140,7 +147,7 @@ tun 接口的 IPv6 前缀。
* 让不支持的网络无法到达
* 将所有连接路由到 tun
它可以防止地址泄漏,并使 DNS 劫持在 Android 上工作,但你的设备将无法其他设备被访问
它可以防止地址泄漏,并使 DNS 劫持在 Android 上工作。
*在 Windows 中*:
@@ -257,6 +264,38 @@ 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

@@ -9,6 +9,6 @@
}
```
### 字段
### Fields
No fields.
No fields.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -83,7 +83,10 @@
如果设置,域名将在请求发出之前解析为 IP。
默认使用 `dns.strategy`
| 出站 | 受影响的域名 | 默认回退值 |
|----------|--------------------------|-------------------------------------------|
| `direct` | 请求中的域名 | `inbound.domain_strategy` |
| others | 服务器地址中的域名 | / |
#### fallback_delay

View File

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

View File

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

View File

@@ -6,26 +6,18 @@ icon: material/file-code
## :material-graph: Requirements
Before sing-box 1.4.0:
### sing-box 1.10
* Go 1.18.5 - 1.20.x
Since sing-box 1.4.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ with tag `with_quic` enabled
Since sing-box 1.5.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ with tag `with_quic` or `with_ech` enabled
Since sing-box 1.8.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
* Go 1.21.0 - ~ with tag `with_ech` enabled
### sing-box 1.9
* Go 1.18.5 - 1.22.x
* Go 1.20.0 - 1.22.x with tag `with_quic`, or `with_utls` enabled
* Go 1.21.0 - 1.22.x with tag `with_ech` enabled
You can download and install Go from: https://go.dev/doc/install, latest version is recommended.
## :material-fast-forward: Simple Build
@@ -57,16 +49,16 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
| Build Tag | Enabled by default | Description |
|------------------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). |
| `with_grpc` | :material-close: | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
| `with_grpc` | :material-close: | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). |
| `with_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_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_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

@@ -6,25 +6,17 @@ icon: material/file-code
## :material-graph: 要求
sing-box 1.4.0 前:
### sing-box 1.10
* Go 1.18.5 - 1.20.x
* Go 1.20.0 - ~
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
* Go 1.21.0 - ~ with tag `with_ech` enabled
sing-box 1.4.0:
### sing-box 1.9
* Go 1.18.5 - ~
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic`
从 sing-box 1.5.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic``with_ech`
从 sing-box 1.8.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic``with_utls`
* Go 1.20.1 - ~ 如果启用构建标记 `with_ech`
* Go 1.18.5 - 1.22.x
* Go 1.20.0 - 1.22.x with tag `with_quic`, or `with_utls` enabled
* Go 1.21.0 - 1.22.x with tag `with_ech` enabled
您可以从 https://go.dev/doc/install 下载并安装 Go推荐使用最新版本。
@@ -54,19 +46,19 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
## :material-folder-settings: 构建标记
| 构建标记 | 默认启动 | 说明 |
|------------------------------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 构建标记 | 默认启动 | 说明 |
|------------------------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). |
| `with_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/). |
除非您确实知道您正在启用什么,否则不建议更改默认构建标签列表。

View File

@@ -4,6 +4,28 @@ 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
```
(This applies to any distribution that uses `dnf` as the package manager: Fedora, CentOS, even OpenSUSE with DNF installed.)
## :material-download-box: Manual Installation
=== ":material-debian: Debian / DEB"
@@ -17,6 +39,7 @@ icon: material/package
```bash
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
```
(This applies to any distribution that uses `rpm` and `systemd`. Because of how `rpm` defines dependencies, if it installs, it probably works.)
=== ":simple-archlinux: Archlinux / PKG"
@@ -28,38 +51,55 @@ icon: material/package
=== ":material-linux: Linux"
| Type | Platform | Link | Command | Actively maintained |
|----------|---------------|-------------------------|------------------------------|---------------------|
| APK | Alpine | [sing-box][alpine] | `apk add sing-box` | :material-check: |
| AUR | Arch Linux | [sing-box][aur] ᴬᵁᴿ | `? -S sing-box` | :material-check: |
| nixpkgs | NixOS | [sing-box][nixpkgs] | `nix-env -iA nixos.sing-box` | :material-check: |
| Homebrew | macOS / Linux | [sing-box][brew] | `brew install sing-box` | :material-check: |
| Type | Platform | Command | Link |
|----------|---------------|------------------------------|---------------------------------------------------------------------------------------------------------------|
| AUR | Arch Linux | `? -S sing-box` | [![AUR package](https://repology.org/badge/version-for-repo/aur/sing-box.svg)][aur] |
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [![nixpkgs unstable package](https://repology.org/badge/version-for-repo/nix_unstable/sing-box.svg)][nixpkgs] |
| Homebrew | macOS / Linux | `brew install sing-box` | [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/sing-box.svg)][brew] |
| APK | Alpine | `apk add sing-box` | [![Alpine Linux Edge package](https://repology.org/badge/version-for-repo/alpine_edge/sing-box.svg)][alpine] |
| DEB | AOSC | `apt install sing-box` | [![AOSC package](https://repology.org/badge/version-for-repo/aosc/sing-box.svg)][aosc] |
=== ":material-apple: macOS"
| Type | Platform | Link | Command | Actively maintained |
|----------|----------|------------------|-------------------------|---------------------|
| Homebrew | macOS | [sing-box][brew] | `brew install sing-box` | :material-check: |
| Type | Platform | Command | Link |
|----------|----------|-------------------------|------------------------------------------------------------------------------------------------|
| Homebrew | macOS | `brew install sing-box` | [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/sing-box.svg)][brew] |
=== ":material-microsoft-windows: Windows"
| Type | Platform | Link | Command | Actively maintained |
|------------|--------------------|---------------------|------------------------------|---------------------|
| Scoop | Windows | [sing-box][scoop] | `scoop install sing-box` | :material-check: |
| Chocolatey | Windows | [sing-box][choco] | `choco install sing-box` | :material-check: |
| winget | Windows | [sing-box][winget] | `winget install sing-box` | :material-alert: |
| Type | Platform | Command | Link |
|------------|----------|---------------------------|-----------------------------------------------------------------------------------------------------|
| Scoop | Windows | `scoop install sing-box` | [![Scoop package](https://repology.org/badge/version-for-repo/scoop/sing-box.svg)][scoop] |
| Chocolatey | Windows | `choco install sing-box` | [![Chocolatey package](https://repology.org/badge/version-for-repo/chocolatey/sing-box.svg)][choco] |
| winget | Windows | `winget install sing-box` | [![winget package](https://repology.org/badge/version-for-repo/winget/sing-box.svg)][winget] |
=== ":material-android: Android"
| Type | Platform | Link | Command | Actively maintained |
|------------|--------------------|---------------------|------------------------------|---------------------|
| Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: |
| Type | Platform | Command | Link |
|--------|----------|--------------------|----------------------------------------------------------------------------------------------|
| Termux | Android | `pkg add sing-box` | [![Termux package](https://repology.org/badge/version-for-repo/termux/sing-box.svg)][termux] |
=== ":material-freebsd: FreeBSD"
| Type | Platform | Link | Command | Actively maintained |
|------------|----------|-------------------|------------------------|---------------------|
| FreshPorts | FreeBSD | [sing-box][ports] | `pkg install sing-box` | :material-alert: |
| Type | Platform | Command | Link |
|------------|----------|------------------------|--------------------------------------------------------------------------------------------|
| FreshPorts | FreeBSD | `pkg install sing-box` | [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/sing-box.svg)][ports] |
## :material-alert: Problematic Sources
| Type | Platform | Link | Promblem(s) |
|------------|----------|-------------------------------------------------------------------------------------------|------------------------------------------------------------------|
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | Problematic build tag list modification; Not actively maintained |
| Homebrew | / | [homebrew-core][brew] | Problematic build tag list modification |
| Termux | Android | [termux-packages][termux] | Problematic build tag list modification |
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | Old Go (go1.20) |
If you are a user of them, please report issues to them:
1. Please do not modify release build tags without full understanding of the related functionality: enabling non-default
labels may result in decreased performance; the lack of default labels may cause user confusion.
2. sing-box supports compiling with some older Go versions, but it is not recommended (especially versions that are no
longer supported by Go).
## :material-book-multiple: Service Management
@@ -99,4 +139,6 @@ you can manage the service using the following command:
[ports]: https://www.freshports.org/net/sing-box
[aosc]: https://packages.aosc.io/packages/sing-box
[systemd]: https://systemd.io/

View File

@@ -4,6 +4,28 @@ 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
```
(这适用于任何使用 `dnf` 作为包管理器的发行版Fedora、CentOS甚至安装了 DNF 的 OpenSUSE。
## :material-download-box: 手动安装
=== ":material-debian: Debian / DEB"
@@ -17,6 +39,7 @@ icon: material/package
```bash
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
```
(这适用于任何使用 `rpm` 和 `systemd` 的发行版。由于 `rpm` 定义依赖关系的方式,如果安装成功,就多半能用。)
=== ":simple-archlinux: Archlinux / PKG"
@@ -28,38 +51,54 @@ icon: material/package
=== ":material-linux: Linux"
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|----------|------------|---------------------|------------------------------|------------------|
| Alpine | Alpine | [sing-box][alpine] | `apk add sing-box` | :material-check: |
| AUR | Arch Linux | [sing-box][aur] ᴬᵁᴿ | `? -S sing-box` | :material-check: |
| nixpkgs | NixOS | [sing-box][nixpkgs] | `nix-env -iA nixos.sing-box` | :material-check: |
| Homebrew | Linux | [sing-box][brew] | `brew install sing-box` | :material-check: |
| 类型 | 平台 | 链接 | 命令 |
|----------|---------------|------------------------------|---------------------------------------------------------------------------------------------------------------|
| AUR | Arch Linux | `? -S sing-box` | [![AUR package](https://repology.org/badge/version-for-repo/aur/sing-box.svg)][aur] |
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [![nixpkgs unstable package](https://repology.org/badge/version-for-repo/nix_unstable/sing-box.svg)][nixpkgs] |
| Homebrew | macOS / Linux | `brew install sing-box` | [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/sing-box.svg)][brew] |
| APK | Alpine | `apk add sing-box` | [![Alpine Linux Edge package](https://repology.org/badge/version-for-repo/alpine_edge/sing-box.svg)][alpine] |
| DEB | AOSC | `apt install sing-box` | [![AOSC package](https://repology.org/badge/version-for-repo/aosc/sing-box.svg)][aosc] |
=== ":material-apple: macOS"
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|----------|-------|------------------|-------------------------|------------------|
| Homebrew | macOS | [sing-box][brew] | `brew install sing-box` | :material-check: |
| 类型 | 平台 | 链接 | 命令 |
|----------|-------|-------------------------|------------------------------------------------------------------------------------------------|
| Homebrew | macOS | `brew install sing-box` | [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/sing-box.svg)][brew] |
=== ":material-microsoft-windows: Windows"
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|------------|---------|--------------------|---------------------------|------------------|
| Scoop | Windows | [sing-box][scoop] | `scoop install sing-box` | :material-check: |
| Chocolatey | Windows | [sing-box][choco] | `choco install sing-box` | :material-check: |
| winget | Windows | [sing-box][winget] | `winget install sing-box` | :material-alert: |
| 类型 | 平台 | 链接 | 命令 |
|------------|---------|---------------------------|-----------------------------------------------------------------------------------------------------|
| Scoop | Windows | `scoop install sing-box` | [![Scoop package](https://repology.org/badge/version-for-repo/scoop/sing-box.svg)][scoop] |
| Chocolatey | Windows | `choco install sing-box` | [![Chocolatey package](https://repology.org/badge/version-for-repo/chocolatey/sing-box.svg)][choco] |
| winget | Windows | `winget install sing-box` | [![winget package](https://repology.org/badge/version-for-repo/winget/sing-box.svg)][winget] |
=== ":material-android: Android"
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|--------|---------|--------------------|--------------------|------------------|
| Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: |
| 类型 | 平台 | 链接 | 命令 |
|--------|---------|--------------------|----------------------------------------------------------------------------------------------|
| Termux | Android | `pkg add sing-box` | [![Termux package](https://repology.org/badge/version-for-repo/termux/sing-box.svg)][termux] |
=== ":material-freebsd: FreeBSD"
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|------------|---------|-------------------|------------------------|------------------|
| FreshPorts | FreeBSD | [sing-box][ports] | `pkg install sing-box` | :material-alert: |
| 类型 | 平台 | 链接 | 命令 |
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
| FreshPorts | FreeBSD | `pkg install sing-box` | [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/sing-box.svg)][ports] |
## :material-alert: 存在问题的源
| 类型 | 平台 | 链接 | 原因 |
|------------|---------|-------------------------------------------------------------------------------------------|-----------------------|
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改; 没有活跃维护 |
| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 |
| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 |
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) |
如果您是其用户,请向他们报告问题:
1. 在未完全了解相关功能的情况下,请勿修改发布版本标签:启用非默认标签可能会导致性能下降;缺少默认标签可能会引起用户混淆。
2. sing-box 支持使用一些较旧的 Go 版本进行编译,但不推荐使用(特别是已不再受 Go 支持的版本)。
## :material-book-multiple: 服务管理
@@ -95,4 +134,6 @@ icon: material/package
[ports]: https://www.freshports.org/net/sing-box
[aosc]: https://packages.aosc.io/packages/sing-box
[systemd]: https://systemd.io/

View File

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

View File

@@ -0,0 +1,38 @@
---
icon: material/book-lock-open
---
# TunnelVision
TunnelVision is an attack that uses DHCP option 121 to set higher priority routes
so that traffic does not go through the VPN.
Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-3661
## Status
### Android
Android does not handle DHCP option 121 and is not affected.
### Apple platforms
Update [sing-box graphical client](/clients/apple/#download) to `1.9.0-rc.16` or newer,
then enable `includeAllNetworks` in `Settings``Packet Tunnel` and you will be unaffected.
Note: when `includeAllNetworks` is enabled, the default TUN stack is changed to `gvisor`,
and the `system` and `mixed` stacks are not available.
### Linux
Update sing-box to `1.9.0-rc.16` or newer, rules generated by `auto-route` are unaffected.
### Windows
No solution yet.
## Workarounds
* Don't connect to untrusted networks
* Relay untrusted network through another device
* Just ignore it

View File

@@ -4,16 +4,17 @@ icon: material/lightning-bolt
# Hysteria 2
The most popular Chinese-made simple protocol based on QUIC, the selling point is Brutal,
a congestion control algorithm that can resist packet loss by manually specifying the required rate by the user.
Hysteria 2 is a simple, Chinese-made protocol based on QUIC.
The selling point is Brutal, a congestion control algorithm that
tries to achieve a user-defined bandwidth despite packet loss.
!!! warning
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies.
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more obvious characteristics than TCP based proxies.
| Specification | Binary Characteristics | Active Detect Hiddenness |
|---------------------------------------------------------------------------|------------------------|--------------------------|
| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: |
| Specification | Resists passive detection | Resists active probes |
|---------------------------------------------------------------------------|---------------------------|-----------------------|
| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: |
## :material-text-box-check: Password Generator
@@ -44,7 +45,7 @@ To use sing-box with the official program, you need to fill in that combination
Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your server.
=== ":material-harddisk: With local certificate"
```json
{
"inbounds": [

View File

@@ -4,15 +4,18 @@ icon: material/send
# Shadowsocks
As the most well-known Chinese-made proxy protocol,
Shadowsocks exists in multiple versions,
but only AEAD 2022 ciphers TCP with multiplexing is recommended.
Shadowsocks is the most well-known Chinese-made proxy protocol.
It exists in multiple versions, but only AEAD 2022 ciphers
over TCP with multiplexing is recommended.
| Ciphers | Specification | Cryptographic Security | Binary Characteristics | Active Detect Hiddenness |
|----------------|------------------------------------------------------------|------------------------|------------------------|--------------------------|
| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: |
| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: |
| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: |
| Ciphers | Specification | Cryptographically sound | Resists passive detection | Resists active probes |
|----------------|------------------------------------------------------------|-------------------------|---------------------------|-----------------------|
| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: |
| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: |
| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: |
(We strongly recommend using multiplexing to send UDP traffic over TCP, because
doing otherwise is vulnerable to passive detection.)
## :material-text-box-check: Password Generator

View File

@@ -4,15 +4,15 @@ icon: material/horse
# Trojan
As the most commonly used TLS proxy made in China, Trojan can be used in various combinations,
Torjan is the most commonly used TLS proxy made in China. It can be used in various combinations,
but only the combination of uTLS and multiplexing is recommended.
| Protocol and implementation combination | Specification | Binary Characteristics | Active Detect Hiddenness |
|-----------------------------------------|----------------------------------------------------------------------|------------------------|--------------------------|
| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: |
| Basic Go implementation | / | :material-alert: | :material-check: |
| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: |
| with uTLS enabled | No formal definition | :material-help: | :material-check: |
| Protocol and implementation combination | Specification | Resists passive detection | Resists active probes |
|-----------------------------------------|----------------------------------------------------------------------|---------------------------|-----------------------|
| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: |
| Basic Go implementation | / | :material-alert: | :material-check: |
| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: |
| with uTLS enabled | No formal definition | :material-help: | :material-check: |
## :material-text-box-check: Password Generator
@@ -211,4 +211,3 @@ but only the combination of uTLS and multiplexing is recommended.
]
}
```

View File

@@ -1,208 +0,0 @@
---
icon: material/alpha-t-box
---
# TUIC
A recently popular Chinese-made simple protocol based on QUIC, the selling point is the BBR congestion control algorithm.
!!! warning
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies.
| Specification | Binary Characteristics | Active Detect Hiddenness |
|-----------------------------------------------------------|------------------------|--------------------------|
| [GitHub](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: |
## Password Generator
| Generated UUID | Generated Password | Action |
|------------------------|----------------------------|-----------------------------------------------------------------|
| <code id="uuid"><code> | <code id="password"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
<script>
function generateUUID() {
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
let r = Math.random() * 16 | 0,
v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
document.getElementById("uuid").textContent = uuid;
}
function generatePassword() {
const array = new Uint8Array(16);
window.crypto.getRandomValues(array);
document.getElementById("password").textContent = btoa(String.fromCharCode.apply(null, array));
}
function generate() {
generateUUID();
generatePassword();
}
generate();
</script>
## :material-server: Server Example
=== ":material-harddisk: With local certificate"
```json
{
"inbounds": [
{
"type": "tuic",
"listen": "::",
"listen_port": 8080,
"users": [
{
"name": "sekai",
"uuid": "<uuid>",
"password": "<password>"
}
],
"congestion_control": "bbr",
"tls": {
"enabled": true,
"server_name": "example.org",
"key_path": "/path/to/key.pem",
"certificate_path": "/path/to/certificate.pem"
}
}
]
}
```
=== ":material-auto-fix: With ACME"
```json
{
"inbounds": [
{
"type": "tuic",
"listen": "::",
"listen_port": 8080,
"users": [
{
"name": "sekai",
"uuid": "<uuid>",
"password": "<password>"
}
],
"congestion_control": "bbr",
"tls": {
"enabled": true,
"server_name": "example.org",
"acme": {
"domain": "example.org",
"email": "admin@example.org"
}
}
}
]
}
```
=== ":material-cloud: With ACME and Cloudflare API"
```json
{
"inbounds": [
{
"type": "tuic",
"listen": "::",
"listen_port": 8080,
"users": [
{
"name": "sekai",
"uuid": "<uuid>",
"password": "<password>"
}
],
"congestion_control": "bbr",
"tls": {
"enabled": true,
"server_name": "example.org",
"acme": {
"domain": "example.org",
"email": "admin@example.org",
"dns01_challenge": {
"provider": "cloudflare",
"api_token": "my_token"
}
}
}
}
]
}
```
## :material-cellphone-link: Client Example
=== ":material-web-check: With valid certificate"
```json
{
"outbounds": [
{
"type": "tuic",
"server": "127.0.0.1",
"server_port": 8080,
"uuid": "<uuid>",
"password": "<password>",
"congestion_control": "bbr",
"tls": {
"enabled": true,
"server_name": "example.org"
}
}
]
}
```
=== ":material-check: With self-sign certificate"
!!! info "Tip"
Use `sing-box merge` command to merge configuration and certificate into one file.
```json
{
"outbounds": [
{
"type": "tuic",
"server": "127.0.0.1",
"server_port": 8080,
"uuid": "<uuid>",
"password": "<password>",
"congestion_control": "bbr",
"tls": {
"enabled": true,
"server_name": "example.org",
"certificate_path": "/path/to/certificate.pem"
}
}
]
}
```
=== ":material-alert: Ignore certificate verification"
```json
{
"outbounds": [
{
"type": "tuic",
"server": "127.0.0.1",
"server_port": 8080,
"uuid": "<uuid>",
"password": "<password>",
"congestion_control": "bbr",
"tls": {
"enabled": true,
"server_name": "example.org",
"insecure": true
}
}
]
}
```

View File

@@ -290,52 +290,6 @@ flowchart TB
=== ":material-dns: DNS rules"
!!! info
DNS rules are optional if FakeIP is used.
```json
{
"dns": {
"servers": [
{
"tag": "google",
"address": "tls://8.8.8.8"
},
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
}
],
"rules": [
{
"outbound": "any",
"server": "local"
},
{
"clash_mode": "Direct",
"server": "local"
},
{
"clash_mode": "Global",
"server": "google"
},
{
"geosite": "geolocation-cn",
"server": "local"
}
]
}
}
```
=== ":material-dns: DNS rules (1.8.0+)"
!!! info
DNS rules are optional if FakeIP is used.
```json
{
"dns": {
@@ -382,74 +336,180 @@ flowchart TB
}
```
=== ":material-router-network: Route rules"
=== ":material-dns: DNS rules (Enhanced, but slower) (1.9.0+)"
```json
{
"outbounds": [
=== ":material-shield-off: With DNS leaks"
```json
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
}
],
"route": {
"rules": [
{
"type": "logical",
"mode": "or",
"rules": [
"dns": {
"servers": [
{
"protocol": "dns"
"tag": "google",
"address": "tls://8.8.8.8"
},
{
"port": 53
"tag": "local",
"address": "https://223.5.5.5/dns-query",
"detour": "direct"
}
],
"outbound": "dns"
},
{
"geoip": "private",
"outbound": "direct"
},
{
"clash_mode": "Direct",
"outbound": "direct"
},
{
"clash_mode": "Global",
"outbound": "default"
},
{
"type": "logical",
"mode": "or",
"rules": [
{
"port": 853
"outbound": "any",
"server": "local"
},
{
"network": "udp",
"port": 443
"clash_mode": "Direct",
"server": "local"
},
{
"protocol": "stun"
"clash_mode": "Global",
"server": "google"
},
{
"rule_set": "geosite-geolocation-cn",
"server": "local"
},
{
"clash_mode": "Default",
"server": "google"
},
{
"type": "logical",
"mode": "and",
"rules": [
{
"rule_set": "geosite-geolocation-!cn",
"invert": true
},
{
"rule_set": "geoip-cn"
}
],
"server": "local"
}
],
"outbound": "block"
]
},
{
"geosite": "geolocation-cn",
"outbound": "direct"
"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 (1.8.0+)"
=== ":material-security: Without DNS leaks, but slower (1.9.0-alpha.2+)"
```json
{
"dns": {
"servers": [
{
"tag": "google",
"address": "tls://8.8.8.8"
},
{
"tag": "local",
"address": "https://223.5.5.5/dns-query",
"detour": "direct"
}
],
"rules": [
{
"outbound": "any",
"server": "local"
},
{
"clash_mode": "Direct",
"server": "local"
},
{
"clash_mode": "Global",
"server": "google"
},
{
"rule_set": "geosite-geolocation-cn",
"server": "local"
},
{
"type": "logical",
"mode": "and",
"rules": [
{
"rule_set": "geosite-geolocation-!cn",
"invert": true
},
{
"rule_set": "geoip-cn"
}
],
"server": "google",
"client_subnet": "114.114.114.114/24" // Any China client IP address
}
]
},
"route": {
"rule_set": [
{
"type": "remote",
"tag": "geosite-geolocation-cn",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
},
{
"type": "remote",
"tag": "geosite-geolocation-!cn",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
},
{
"type": "remote",
"tag": "geoip-cn",
"format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
}
]
},
"experimental": {
"cache_file": {
"enabled": true,
"store_rdrc": true
},
"clash_api": {
"default_mode": "Enhanced"
}
}
}
```
=== ":material-router-network: Route rules"
```json
{

View File

@@ -2,6 +2,41 @@
icon: material/arrange-bring-forward
---
## 1.9.5
### Bundle Identifier updates in Apple platform clients
Due to problems with our old Apple developer account,
we can only change Bundle Identifiers to re-list sing-box apps,
which means the data will not be automatically inherited.
For iOS, you need to back up your old data yourself (if you still have access to it);
for tvOS, you need to re-import profiles from your iPhone or iPad or create it manually;
for macOS, you can migrate the data folder using the following command:
```bash
cd ~/Library/Group\ Containers && \
mv group.io.nekohasekai.sfa group.io.nekohasekai.sfavt
```
## 1.9.0
### `domain_suffix` behavior update
For historical reasons, sing-box's `domain_suffix` rule matches literal prefixes instead of the same as other projects.
sing-box 1.9.0 modifies the behavior of `domain_suffix`: If the rule value is prefixed with `.`,
the behavior is unchanged, otherwise it matches `(domain|.+\.domain)` instead.
### `process_path` format update on Windows
The `process_path` rule of sing-box is inherited from Clash,
the original code uses the local system's path format (e.g. `\Device\HarddiskVolume1\folder\program.exe`),
but when the device has multiple disks, the HarddiskVolume serial number is not stable.
sing-box 1.9.0 make QueryFullProcessImageNameW output a Win32 path (such as `C:\folder\program.exe`),
which will disrupt the existing `process_path` use cases in Windows.
## 1.8.0
### :material-close-box: Migrate cache file from Clash API to independent options

View File

@@ -2,6 +2,39 @@
icon: material/arrange-bring-forward
---
## 1.9.5
### Apple 平台客户端的 Bundle Identifier 更新
由于我们旧的苹果开发者账户存在问题,我们只能通过更新 Bundle Identifiers
来重新上架 sing-box 应用, 这意味着数据不会自动继承。
对于 iOS您需要自行备份旧的数据如果您仍然可以访问
对于 Apple tvOS您需要从 iPhone 或 iPad 重新导入配置或者手动创建;
对于 macOS您可以使用以下命令迁移数据文件夹
```bash
cd ~/Library/Group\ Containers && \
mv group.io.nekohasekai.sfa group.io.nekohasekai.sfavt
```
## 1.9.0
### `domain_suffix` 行为更新
由于历史原因sing-box 的 `domain_suffix` 规则匹配字面前缀,而不与其他项目相同。
sing-box 1.9.0 修改了 `domain_suffix` 的行为:如果规则值以 `.` 为前缀则行为不变,否则改为匹配 `(domain|.+\.domain)`
### 对 Windows 上 `process_path` 格式的更新
sing-box 的 `process_path` 规则继承自Clash
原始代码使用本地系统的路径格式(例如 `\Device\HarddiskVolume1\folder\program.exe`
但是当设备有多个硬盘时,该 HarddiskVolume 系列号并不稳定。
sing-box 1.9.0 使 QueryFullProcessImageNameW 输出 Win32 路径(如 `C:\folder\program.exe`
这将会破坏现有的 Windows `process_path` 用例。
## 1.8.0
### :material-close-box: 将缓存文件从 Clash API 迁移到独立选项

26
docs/sponsors.md Normal file
View File

@@ -0,0 +1,26 @@
---
icon: material/hand-coin
---
# Sponsors
Do you or your friends use sing-box?
You can help keep the project bug-free and feature rich by sponsoring
the project maintainer via [GitHub Sponsors](https://github.com/sponsors/nekohasekai).
![](https://nekohasekai.github.io/sponsor-images/sponsors.svg)
### Special Sponsors
**Viral Tech, Inc.**
Helping us re-list sing-box apps on the Apple Store.
---
[![JetBrains logo](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://www.jetbrains.com)
Free license for the amazing IDEs.
---

View File

@@ -5,8 +5,7 @@ icon: material/forum
# Support
| Channel | Link |
|:------------------------------|:--------------------------------------------|
| Community | https://community.sagernet.org |
| :---------------------------- | :------------------------------------------ |
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
| Telegram notification channel | https://t.me/yapnc |
| Telegram user group | https://t.me/yapug |

View File

@@ -4,11 +4,10 @@ icon: material/forum
# 支持
| 通道 | 链接 |
|:--------------|:--------------------------------------------|
| 社区 | https://community.sagernet.org |
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
| 通道 | 链接 |
| :---------------- | :------------------------------------------ |
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
| Telegram 通知频道 | https://t.me/yapnc |
| Telegram 用户组 | https://t.me/yapug |
| 邮件 | contact@sagernet.org |
| Telegram 用户组 | https://t.me/yapug |
| 邮件 | contact@sagernet.org |

View File

@@ -29,6 +29,7 @@ var (
string(bucketExpand),
string(bucketMode),
string(bucketRuleSet),
string(bucketRDRC),
}
cacheIDDefault = []byte("default")
@@ -37,17 +38,26 @@ var (
var _ adapter.CacheFile = (*CacheFile)(nil)
type CacheFile struct {
ctx context.Context
path string
cacheID []byte
storeFakeIP bool
ctx context.Context
path string
cacheID []byte
storeFakeIP bool
storeRDRC bool
rdrcTimeout time.Duration
DB *bbolt.DB
saveAccess sync.RWMutex
saveMetadataTimer *time.Timer
saveFakeIPAccess sync.RWMutex
saveDomain map[netip.Addr]string
saveAddress4 map[string]netip.Addr
saveAddress6 map[string]netip.Addr
saveMetadataTimer *time.Timer
saveRDRCAccess sync.RWMutex
saveRDRC map[saveRDRCCacheKey]bool
}
type saveRDRCCacheKey struct {
TransportName string
QuestionName string
QType uint16
}
func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
@@ -61,14 +71,25 @@ 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,6 +7,7 @@ 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"
)
@@ -58,12 +59,13 @@ func (c *CacheFile) FakeIPSaveMetadata(metadata *adapter.FakeIPMetadata) error {
}
func (c *CacheFile) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata) {
if timer := c.saveMetadataTimer; timer != nil {
timer.Stop()
if c.saveMetadataTimer == nil {
c.saveMetadataTimer = time.AfterFunc(C.FakeIPMetadataSaveInterval, func() {
_ = c.FakeIPSaveMetadata(metadata)
})
} else {
c.saveMetadataTimer.Reset(C.FakeIPMetadataSaveInterval)
}
c.saveMetadataTimer = time.AfterFunc(10*time.Second, func() {
_ = c.FakeIPSaveMetadata(metadata)
})
}
func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
@@ -72,6 +74,7 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
if err != nil {
return err
}
oldDomain := bucket.Get(address.AsSlice())
err = bucket.Put(address.AsSlice(), []byte(domain))
if err != nil {
return err
@@ -84,39 +87,51 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
if err != nil {
return err
}
if oldDomain != nil {
if err := bucket.Delete(oldDomain); err != nil {
return err
}
}
return bucket.Put([]byte(domain), address.AsSlice())
})
}
func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
c.saveAccess.Lock()
c.saveFakeIPAccess.Lock()
if oldDomain, loaded := c.saveDomain[address]; loaded {
if address.Is4() {
delete(c.saveAddress4, oldDomain)
} else {
delete(c.saveAddress6, oldDomain)
}
}
c.saveDomain[address] = domain
if address.Is4() {
c.saveAddress4[domain] = address
} else {
c.saveAddress6[domain] = address
}
c.saveAccess.Unlock()
c.saveFakeIPAccess.Unlock()
go func() {
err := c.FakeIPStore(address, domain)
if err != nil {
logger.Warn("save FakeIP address pair: ", err)
logger.Warn("save FakeIP cache: ", err)
}
c.saveAccess.Lock()
c.saveFakeIPAccess.Lock()
delete(c.saveDomain, address)
if address.Is4() {
delete(c.saveAddress4, domain)
} else {
delete(c.saveAddress6, domain)
}
c.saveAccess.Unlock()
c.saveFakeIPAccess.Unlock()
}()
}
func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
c.saveAccess.RLock()
c.saveFakeIPAccess.RLock()
cachedDomain, cached := c.saveDomain[address]
c.saveAccess.RUnlock()
c.saveFakeIPAccess.RUnlock()
if cached {
return cachedDomain, true
}
@@ -137,13 +152,13 @@ func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bo
cachedAddress netip.Addr
cached bool
)
c.saveAccess.RLock()
c.saveFakeIPAccess.RLock()
if !isIPv6 {
cachedAddress, cached = c.saveAddress4[domain]
} else {
cachedAddress, cached = c.saveAddress6[domain]
}
c.saveAccess.RUnlock()
c.saveFakeIPAccess.RUnlock()
if cached {
return cachedAddress, true
}

View File

@@ -0,0 +1,109 @@
package cachefile
import (
"encoding/binary"
"time"
"github.com/sagernet/bbolt"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/logger"
)
var bucketRDRC = []byte("rdrc2")
func (c *CacheFile) StoreRDRC() bool {
return c.storeRDRC
}
func (c *CacheFile) RDRCTimeout() time.Duration {
return c.rdrcTimeout
}
func (c *CacheFile) LoadRDRC(transportName string, qName string, qType uint16) (rejected bool) {
c.saveRDRCAccess.RLock()
rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName, qType}]
c.saveRDRCAccess.RUnlock()
if cached {
return
}
key := buf.Get(2 + len(qName))
binary.BigEndian.PutUint16(key, qType)
copy(key[2:], qName)
defer buf.Put(key)
var deleteCache bool
err := c.DB.View(func(tx *bbolt.Tx) error {
bucket := c.bucket(tx, bucketRDRC)
if bucket == nil {
return nil
}
bucket = bucket.Bucket([]byte(transportName))
if bucket == nil {
return nil
}
content := bucket.Get(key)
if content == nil {
return nil
}
expiresAt := time.Unix(int64(binary.BigEndian.Uint64(content)), 0)
if time.Now().After(expiresAt) {
deleteCache = true
return nil
}
rejected = true
return nil
})
if err != nil {
return
}
if deleteCache {
c.DB.Update(func(tx *bbolt.Tx) error {
bucket := c.bucket(tx, bucketRDRC)
if bucket == nil {
return nil
}
bucket = bucket.Bucket([]byte(transportName))
if bucket == nil {
return nil
}
return bucket.Delete(key)
})
}
return
}
func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) error {
return c.DB.Batch(func(tx *bbolt.Tx) error {
bucket, err := c.createBucket(tx, bucketRDRC)
if err != nil {
return err
}
bucket, err = bucket.CreateBucketIfNotExists([]byte(transportName))
if err != nil {
return err
}
key := buf.Get(2 + len(qName))
binary.BigEndian.PutUint16(key, qType)
copy(key[2:], qName)
defer buf.Put(key)
expiresAt := buf.Get(8)
defer buf.Put(expiresAt)
binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix()))
return bucket.Put(key, expiresAt)
})
}
func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger) {
saveKey := saveRDRCCacheKey{transportName, qName, qType}
c.saveRDRCAccess.Lock()
c.saveRDRC[saveKey] = true
c.saveRDRCAccess.Unlock()
go func() {
err := c.SaveRDRC(transportName, qName, qType)
if err != nil {
logger.Warn("save RDRC: ", err)
}
c.saveRDRCAccess.Lock()
delete(c.saveRDRC, saveKey)
c.saveRDRCAccess.Unlock()
}()
}

View File

@@ -3,6 +3,7 @@ package experimental
import (
"context"
"os"
"sort"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
@@ -27,11 +28,26 @@ func NewClashServer(ctx context.Context, router adapter.Router, logFactory log.O
}
func CalculateClashModeList(options option.Options) []string {
var clashMode []string
clashMode = append(clashMode, extraClashModeFromRule(common.PtrValueOrDefault(options.Route).Rules)...)
clashMode = append(clashMode, extraClashModeFromDNSRule(common.PtrValueOrDefault(options.DNS).Rules)...)
clashMode = common.FilterNotDefault(common.Uniq(clashMode))
return clashMode
var clashModes []string
clashModes = append(clashModes, extraClashModeFromRule(common.PtrValueOrDefault(options.Route).Rules)...)
clashModes = append(clashModes, extraClashModeFromDNSRule(common.PtrValueOrDefault(options.DNS).Rules)...)
clashModes = common.FilterNotDefault(common.Uniq(clashModes))
predefinedOrder := []string{
"Rule", "Global", "Direct",
}
var newClashModes []string
for _, mode := range clashModes {
if !common.Contains(predefinedOrder, mode) {
newClashModes = append(newClashModes, mode)
}
}
sort.Strings(newClashModes)
for _, mode := range predefinedOrder {
if common.Contains(clashModes, mode) {
newClashModes = append(newClashModes, mode)
}
}
return newClashModes
}
func extraClashModeFromRule(rules []option.Rule) []string {

View File

@@ -308,10 +308,11 @@ func authentication(serverSecret string) func(next http.Handler) http.Handler {
func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
if redirect {
http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect)
} else {
contentType := r.Header.Get("Content-Type")
if !redirect || contentType == "application/json" {
render.JSON(w, r, render.M{"hello": "clash"})
} else {
http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect)
}
}
}

View File

@@ -4,6 +4,7 @@ const (
CommandLog int32 = iota
CommandStatus
CommandServiceReload
CommandServiceClose
CommandCloseConnections
CommandGroup
CommandSelectOutbound

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