mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-16 21:30:27 +00:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cfc3117a9 | ||
|
|
099052dd3d | ||
|
|
b9530ec4eb | ||
|
|
fbe9440e72 | ||
|
|
03c432a8c4 | ||
|
|
957f2e0087 | ||
|
|
bb2519601a | ||
|
|
6b0f4105f7 | ||
|
|
d5b79fe817 | ||
|
|
775987d290 | ||
|
|
27f7dd2116 | ||
|
|
201c239393 | ||
|
|
eb23752ae7 | ||
|
|
da0fc7dd94 | ||
|
|
7877b4b7b6 | ||
|
|
9f74a89a06 | ||
|
|
5d174685dc | ||
|
|
6e03213452 | ||
|
|
72a01bf6b1 | ||
|
|
c3cd01a956 | ||
|
|
ebb077d1fb | ||
|
|
1dd47ad6b1 | ||
|
|
d5c1de2978 | ||
|
|
a6b0c25ac9 | ||
|
|
627d980d8d | ||
|
|
c7070e2b4a | ||
|
|
38cfe5d503 |
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -207,7 +207,7 @@ jobs:
|
||||
TAGS: with_clash_api,with_quic
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
@@ -3,11 +3,8 @@ name: Publish Docker Images
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "The tag version you want to build"
|
||||
- released
|
||||
- prereleased
|
||||
|
||||
env:
|
||||
REGISTRY_IMAGE: ghcr.io/sagernet/sing-box
|
||||
@@ -28,21 +25,10 @@ jobs:
|
||||
- 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@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
ref: ${{ steps.ref.outputs.ref }}
|
||||
fetch-depth: 0
|
||||
- name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
@@ -57,11 +43,6 @@ jobs:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY_IMAGE }}
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
@@ -70,7 +51,6 @@ jobs:
|
||||
context: .
|
||||
build-args: |
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||
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: |
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
@@ -26,7 +26,6 @@ builds:
|
||||
- linux_arm_7
|
||||
- linux_s390x
|
||||
- linux_riscv64
|
||||
- linux_mips64le
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
snapshot:
|
||||
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
||||
@@ -49,19 +48,10 @@ nfpms:
|
||||
- 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: release/completions/sing-box.bash
|
||||
dst: /usr/share/bash-completion/completions/sing-box.bash
|
||||
- src: release/completions/sing-box.fish
|
||||
dst: /usr/share/fish/vendor_completions.d/sing-box.fish
|
||||
- src: release/completions/sing-box.zsh
|
||||
dst: /usr/share/zsh/site-functions/_sing-box
|
||||
|
||||
- src: LICENSE
|
||||
dst: /usr/share/licenses/sing-box/LICENSE
|
||||
deb:
|
||||
|
||||
+12
-43
@@ -1,4 +1,3 @@
|
||||
version: 2
|
||||
project_name: sing-box
|
||||
builds:
|
||||
- &template
|
||||
@@ -26,13 +25,13 @@ builds:
|
||||
targets:
|
||||
- linux_386
|
||||
- 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
|
||||
@@ -89,6 +88,8 @@ builds:
|
||||
- android_arm64
|
||||
- android_386
|
||||
- android_amd64
|
||||
snapshot:
|
||||
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
||||
archives:
|
||||
- &template
|
||||
id: archive
|
||||
@@ -102,7 +103,7 @@ archives:
|
||||
wrap_in_directory: true
|
||||
files:
|
||||
- LICENSE
|
||||
name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ if and .Mips (not (eq .Mips "hardfloat")) }}_{{ .Mips }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
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:
|
||||
@@ -111,7 +112,7 @@ archives:
|
||||
nfpms:
|
||||
- id: package
|
||||
package_name: sing-box
|
||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ if and .Mips (not (eq .Mips "hardfloat")) }}_{{ .Mips }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
builds:
|
||||
- main
|
||||
homepage: https://sing-box.sagernet.org/
|
||||
@@ -122,26 +123,15 @@ nfpms:
|
||||
- deb
|
||||
- rpm
|
||||
- archlinux
|
||||
# - apk
|
||||
# - ipk
|
||||
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: release/completions/sing-box.bash
|
||||
dst: /usr/share/bash-completion/completions/sing-box.bash
|
||||
- src: release/completions/sing-box.fish
|
||||
dst: /usr/share/fish/vendor_completions.d/sing-box.fish
|
||||
- src: release/completions/sing-box.zsh
|
||||
dst: /usr/share/zsh/site-functions/_sing-box
|
||||
|
||||
- src: LICENSE
|
||||
dst: /usr/share/licenses/sing-box/LICENSE
|
||||
deb:
|
||||
@@ -153,34 +143,13 @@ nfpms:
|
||||
signature:
|
||||
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
||||
overrides:
|
||||
apk:
|
||||
contents:
|
||||
- src: release/config/config.json
|
||||
dst: /etc/sing-box/config.json
|
||||
type: config
|
||||
deb:
|
||||
conflicts:
|
||||
- sing-box-beta
|
||||
rpm:
|
||||
conflicts:
|
||||
- sing-box-beta
|
||||
|
||||
- src: release/config/sing-box.initd
|
||||
dst: /etc/init.d/sing-box
|
||||
|
||||
- src: release/completions/sing-box.bash
|
||||
dst: /usr/share/bash-completion/completions/sing-box.bash
|
||||
- src: release/completions/sing-box.fish
|
||||
dst: /usr/share/fish/vendor_completions.d/sing-box.fish
|
||||
- src: release/completions/sing-box.zsh
|
||||
dst: /usr/share/zsh/site-functions/_sing-box
|
||||
|
||||
- src: LICENSE
|
||||
dst: /usr/share/licenses/sing-box/LICENSE
|
||||
ipk:
|
||||
contents:
|
||||
- src: release/config/config.json
|
||||
dst: /etc/sing-box/config.json
|
||||
type: config
|
||||
|
||||
- src: release/config/openwrt.init
|
||||
dst: /etc/init.d/sing-box
|
||||
- src: release/config/openwrt.conf
|
||||
dst: /etc/config/sing-box
|
||||
source:
|
||||
enabled: false
|
||||
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
|
||||
|
||||
@@ -27,9 +27,6 @@ ci_build:
|
||||
go build $(PARAMS) $(MAIN)
|
||||
go build $(MAIN_PARAMS) $(MAIN)
|
||||
|
||||
generate_completions:
|
||||
go run -v --tags generate,generate_completions $(MAIN)
|
||||
|
||||
install:
|
||||
go build -o $(PREFIX)/bin/$(NAME) $(MAIN_PARAMS) $(MAIN)
|
||||
|
||||
@@ -69,6 +66,7 @@ release:
|
||||
dist/*.deb \
|
||||
dist/*.rpm \
|
||||
dist/*_amd64.pkg.tar.zst \
|
||||
dist/*_amd64v3.pkg.tar.zst \
|
||||
dist/*_arm64.pkg.tar.zst \
|
||||
dist/release
|
||||
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
|
||||
@@ -101,12 +99,10 @@ 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 -destination 'generic/platform=iOS' -archivePath build/SFI.xcarchive -allowProvisioningUpdates
|
||||
xcodebuild archive -scheme SFI -configuration Release -archivePath build/SFI.xcarchive
|
||||
|
||||
upload_ios_app_store:
|
||||
cd ../sing-box-for-apple && \
|
||||
@@ -117,70 +113,55 @@ 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 -allowProvisioningUpdates
|
||||
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive
|
||||
|
||||
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_standalone:
|
||||
build_macos_independent:
|
||||
cd ../sing-box-for-apple && \
|
||||
rm -rf build/SFM.System.xcarchive && \
|
||||
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive -allowProvisioningUpdates
|
||||
rm -rf build/SFT.System.xcarchive && \
|
||||
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive
|
||||
|
||||
build_macos_dmg:
|
||||
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:
|
||||
rm -rf dist/SFM
|
||||
mkdir -p dist/SFM
|
||||
cd ../sing-box-for-apple && \
|
||||
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"
|
||||
xcodebuild -exportNotarizedApp -archivePath build/SFM.System.xcarchive -exportPath "../sing-box/dist/SFM"
|
||||
|
||||
upload_macos_dmg:
|
||||
upload_macos_independent:
|
||||
cd dist/SFM && \
|
||||
cp SFM.dmg "SFM-${VERSION}-universal.dmg" && \
|
||||
ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dmg"
|
||||
rm -f *.zip && \
|
||||
zip -ry "SFM-${VERSION}-universal.zip" SFM.app && \
|
||||
ghr --replace --draft --prerelease "v${VERSION}" *.zip
|
||||
|
||||
upload_macos_dsyms:
|
||||
pushd ../sing-box-for-apple/build/SFM.System.xcarchive && \
|
||||
zip -r SFM.dSYMs.zip dSYMs && \
|
||||
mv SFM.dSYMs.zip ../../../sing-box/dist/SFM && \
|
||||
popd && \
|
||||
cd dist/SFM && \
|
||||
cp SFM.dSYMs.zip "SFM-${VERSION}-universal.dSYMs.zip" && \
|
||||
ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dSYMs.zip"
|
||||
|
||||
release_macos_standalone: build_macos_standalone build_macos_dmg upload_macos_dmg upload_macos_dsyms
|
||||
release_macos_independent: build_macos_independent notarize_macos_independent wait_notarize_macos_independent export_macos_independent upload_macos_independent
|
||||
|
||||
build_tvos:
|
||||
cd ../sing-box-for-apple && \
|
||||
rm -rf build/SFT.xcarchive && \
|
||||
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive -allowProvisioningUpdates
|
||||
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive
|
||||
|
||||
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_standalone
|
||||
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_independent
|
||||
|
||||
release_apple_beta: update_apple_version release_ios release_macos release_tvos
|
||||
|
||||
@@ -207,8 +188,8 @@ lib:
|
||||
go run ./cmd/internal/build_libbox -target ios
|
||||
|
||||
lib_install:
|
||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.4
|
||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.4
|
||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.3
|
||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.3
|
||||
|
||||
docs:
|
||||
venv/bin/mkdocs serve
|
||||
|
||||
@@ -4,9 +4,9 @@ The universal proxy platform.
|
||||
|
||||
[](https://repology.org/project/sing-box/versions)
|
||||
|
||||
## Documentation
|
||||
## Support
|
||||
|
||||
https://sing-box.sagernet.org
|
||||
https://community.sagernet.org/c/sing-box/
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -91,6 +91,15 @@ func ContextFrom(ctx context.Context) *InboundContext {
|
||||
return metadata.(*InboundContext)
|
||||
}
|
||||
|
||||
func AppendContext(ctx context.Context) (context.Context, *InboundContext) {
|
||||
metadata := ContextFrom(ctx)
|
||||
if metadata != nil {
|
||||
return ctx, metadata
|
||||
}
|
||||
metadata = new(InboundContext)
|
||||
return WithContext(ctx, metadata), metadata
|
||||
}
|
||||
|
||||
func ExtendContext(ctx context.Context) (context.Context, *InboundContext) {
|
||||
var newMetadata InboundContext
|
||||
if metadata := ContextFrom(ctx); metadata != nil {
|
||||
|
||||
+4
-40
@@ -2,17 +2,13 @@ package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/common/geoip"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-dns"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service"
|
||||
@@ -102,7 +98,7 @@ type DNSRule interface {
|
||||
|
||||
type RuleSet interface {
|
||||
Name() string
|
||||
StartContext(ctx context.Context, startContext *HTTPStartContext) error
|
||||
StartContext(ctx context.Context, startContext RuleSetStartContext) error
|
||||
PostStart() error
|
||||
Metadata() RuleSetMetadata
|
||||
ExtractIPSet() []*netipx.IPSet
|
||||
@@ -122,42 +118,10 @@ type RuleSetMetadata struct {
|
||||
ContainsWIFIRule bool
|
||||
ContainsIPCIDRRule bool
|
||||
}
|
||||
type HTTPStartContext struct {
|
||||
access sync.Mutex
|
||||
httpClientCache map[string]*http.Client
|
||||
}
|
||||
|
||||
func NewHTTPStartContext() *HTTPStartContext {
|
||||
return &HTTPStartContext{
|
||||
httpClientCache: make(map[string]*http.Client),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *HTTPStartContext) HTTPClient(detour string, dialer N.Dialer) *http.Client {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
if httpClient, loaded := c.httpClientCache[detour]; loaded {
|
||||
return httpClient
|
||||
}
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
ForceAttemptHTTP2: true,
|
||||
TLSHandshakeTimeout: C.TCPTimeout,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||||
},
|
||||
},
|
||||
}
|
||||
c.httpClientCache[detour] = httpClient
|
||||
return httpClient
|
||||
}
|
||||
|
||||
func (c *HTTPStartContext) Close() {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
for _, client := range c.httpClientCache {
|
||||
client.CloseIdleConnections()
|
||||
}
|
||||
type RuleSetStartContext interface {
|
||||
HTTPClient(detour string, dialer N.Dialer) *http.Client
|
||||
Close()
|
||||
}
|
||||
|
||||
type InterfaceUpdateListener interface {
|
||||
|
||||
+1
-1
Submodule clients/android updated: 45a1f5f0aa...440aaa9a1a
+1
-1
Submodule clients/apple updated: c7d9b49de7...aa4ce98421
@@ -58,7 +58,7 @@ func FindSDK() {
|
||||
}
|
||||
|
||||
func findNDK() bool {
|
||||
const fixedVersion = "27.2.12479018"
|
||||
const fixedVersion = "26.2.11394342"
|
||||
const versionFile = "source.properties"
|
||||
if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.IsFile(filepath.Join(fixedPath, versionFile)) {
|
||||
androidNDKPath = fixedPath
|
||||
@@ -86,7 +86,7 @@ func findNDK() bool {
|
||||
})
|
||||
for _, versionName := range versionNames {
|
||||
currentNDKPath := filepath.Join(androidSDKPath, "ndk", versionName)
|
||||
if rw.IsFile(filepath.Join(currentNDKPath, versionFile)) {
|
||||
if rw.IsFile(filepath.Join(androidSDKPath, versionFile)) {
|
||||
androidNDKPath = currentNDKPath
|
||||
log.Warn("reproducibility warning: using NDK version " + versionName + " instead of " + fixedVersion)
|
||||
return true
|
||||
|
||||
@@ -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.sfavt"}, newVersion.VersionString())
|
||||
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfavt.standalone", "io.nekohasekai.sfavt.system"}, newVersion.String())
|
||||
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())
|
||||
if updated0 || updated1 {
|
||||
log.Info("updated version to ", newVersion.VersionString(), " (", newVersion.String(), ")")
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
_ "github.com/sagernet/sing-box/include"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/service"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
globalCtx context.Context
|
||||
configPaths []string
|
||||
configDirectories []string
|
||||
workingDir string
|
||||
disableColor bool
|
||||
)
|
||||
|
||||
var mainCommand = &cobra.Command{
|
||||
Use: "sing-box",
|
||||
PersistentPreRun: preRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
mainCommand.PersistentFlags().StringArrayVarP(&configPaths, "config", "c", nil, "set configuration file path")
|
||||
mainCommand.PersistentFlags().StringArrayVarP(&configDirectories, "config-directory", "C", nil, "set configuration directory path")
|
||||
mainCommand.PersistentFlags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
|
||||
mainCommand.PersistentFlags().BoolVarP(&disableColor, "disable-color", "", false, "disable color output")
|
||||
}
|
||||
|
||||
func preRun(cmd *cobra.Command, args []string) {
|
||||
globalCtx = context.Background()
|
||||
sudoUser := os.Getenv("SUDO_USER")
|
||||
sudoUID, _ := strconv.Atoi(os.Getenv("SUDO_UID"))
|
||||
sudoGID, _ := strconv.Atoi(os.Getenv("SUDO_GID"))
|
||||
if sudoUID == 0 && sudoGID == 0 && sudoUser != "" {
|
||||
sudoUserObject, _ := user.Lookup(sudoUser)
|
||||
if sudoUserObject != nil {
|
||||
sudoUID, _ = strconv.Atoi(sudoUserObject.Uid)
|
||||
sudoGID, _ = strconv.Atoi(sudoUserObject.Gid)
|
||||
}
|
||||
}
|
||||
if sudoUID > 0 && sudoGID > 0 {
|
||||
globalCtx = filemanager.WithDefault(globalCtx, "", "", sudoUID, sudoGID)
|
||||
}
|
||||
if disableColor {
|
||||
log.SetStdLogger(log.NewDefaultFactory(context.Background(), log.Formatter{BaseTime: time.Now(), DisableColors: true}, os.Stderr, "", nil, false).Logger())
|
||||
}
|
||||
if workingDir != "" {
|
||||
_, err := os.Stat(workingDir)
|
||||
if err != nil {
|
||||
filemanager.MkdirAll(globalCtx, workingDir, 0o777)
|
||||
}
|
||||
err = os.Chdir(workingDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
if len(configPaths) == 0 && len(configDirectories) == 0 {
|
||||
configPaths = append(configPaths, "config.json")
|
||||
}
|
||||
globalCtx = service.ContextWith(globalCtx, deprecated.NewEnvManager(log.StdLogger()))
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
//go:build generate && generate_completions
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/sagernet/sing-box/log"
|
||||
|
||||
func main() {
|
||||
err := generateCompletions()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func generateCompletions() error {
|
||||
err := mainCommand.GenBashCompletionFile("release/completions/sing-box.bash")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = mainCommand.GenFishCompletionFile("release/completions/sing-box.fish", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = mainCommand.GenZshCompletionFile("release/completions/sing-box.zsh")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+66
-3
@@ -1,11 +1,74 @@
|
||||
//go:build !generate
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/sagernet/sing-box/log"
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
_ "github.com/sagernet/sing-box/include"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
globalCtx context.Context
|
||||
configPaths []string
|
||||
configDirectories []string
|
||||
workingDir string
|
||||
disableColor bool
|
||||
)
|
||||
|
||||
var mainCommand = &cobra.Command{
|
||||
Use: "sing-box",
|
||||
PersistentPreRun: preRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
mainCommand.PersistentFlags().StringArrayVarP(&configPaths, "config", "c", nil, "set configuration file path")
|
||||
mainCommand.PersistentFlags().StringArrayVarP(&configDirectories, "config-directory", "C", nil, "set configuration directory path")
|
||||
mainCommand.PersistentFlags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
|
||||
mainCommand.PersistentFlags().BoolVarP(&disableColor, "disable-color", "", false, "disable color output")
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := mainCommand.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func preRun(cmd *cobra.Command, args []string) {
|
||||
globalCtx = context.Background()
|
||||
sudoUser := os.Getenv("SUDO_USER")
|
||||
sudoUID, _ := strconv.Atoi(os.Getenv("SUDO_UID"))
|
||||
sudoGID, _ := strconv.Atoi(os.Getenv("SUDO_GID"))
|
||||
if sudoUID == 0 && sudoGID == 0 && sudoUser != "" {
|
||||
sudoUserObject, _ := user.Lookup(sudoUser)
|
||||
if sudoUserObject != nil {
|
||||
sudoUID, _ = strconv.Atoi(sudoUserObject.Uid)
|
||||
sudoGID, _ = strconv.Atoi(sudoUserObject.Gid)
|
||||
}
|
||||
}
|
||||
if sudoUID > 0 && sudoGID > 0 {
|
||||
globalCtx = filemanager.WithDefault(globalCtx, "", "", sudoUID, sudoGID)
|
||||
}
|
||||
if disableColor {
|
||||
log.SetStdLogger(log.NewDefaultFactory(context.Background(), log.Formatter{BaseTime: time.Now(), DisableColors: true}, os.Stderr, "", nil, false).Logger())
|
||||
}
|
||||
if workingDir != "" {
|
||||
_, err := os.Stat(workingDir)
|
||||
if err != nil {
|
||||
filemanager.MkdirAll(globalCtx, workingDir, 0o777)
|
||||
}
|
||||
err = os.Chdir(workingDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
if len(configPaths) == 0 && len(configDirectories) == 0 {
|
||||
configPaths = append(configPaths, "config.json")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||
if options.ConnectTimeout != 0 {
|
||||
dialer.Timeout = time.Duration(options.ConnectTimeout)
|
||||
} else {
|
||||
dialer.Timeout = C.TCPConnectTimeout
|
||||
dialer.Timeout = C.TCPTimeout
|
||||
}
|
||||
// TODO: Add an option to customize the keep alive period
|
||||
dialer.KeepAlive = C.TCPKeepAliveInitial
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package geosite_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/sagernet/sing-box/common/geosite"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGeosite(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err := geosite.Write(&buffer, map[string][]geosite.Item{
|
||||
"test": {
|
||||
{
|
||||
Type: geosite.RuleTypeDomain,
|
||||
Value: "example.org",
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
reader, codes, err := geosite.NewReader(bytes.NewReader(buffer.Bytes()))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"test"}, codes)
|
||||
items, err := reader.Read("test")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []geosite.Item{{
|
||||
Type: geosite.RuleTypeDomain,
|
||||
Value: "example.org",
|
||||
}}, items)
|
||||
}
|
||||
@@ -26,22 +26,14 @@ func Open(path string) (*Reader, []string, error) {
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
reader, codes, err := NewReader(content)
|
||||
reader := &Reader{
|
||||
reader: content,
|
||||
}
|
||||
err = reader.readMetadata()
|
||||
if err != nil {
|
||||
content.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return reader, codes, nil
|
||||
}
|
||||
|
||||
func NewReader(readSeeker io.ReadSeeker) (*Reader, []string, error) {
|
||||
reader := &Reader{
|
||||
reader: readSeeker,
|
||||
}
|
||||
err := reader.readMetadata()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
codes := make([]string, 0, len(reader.domainIndex))
|
||||
for code := range reader.domainIndex {
|
||||
codes = append(codes, code)
|
||||
|
||||
@@ -19,11 +19,9 @@ func Write(writer varbin.Writer, domains map[string][]Item) error {
|
||||
index := make(map[string]int)
|
||||
for _, code := range keys {
|
||||
index[code] = content.Len()
|
||||
for _, item := range domains[code] {
|
||||
err := varbin.Write(content, binary.BigEndian, item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := varbin.Write(content, binary.BigEndian, domains[code])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-19
@@ -40,27 +40,21 @@ func PeekStream(ctx context.Context, metadata *adapter.InboundContext, conn net.
|
||||
}
|
||||
deadline := time.Now().Add(timeout)
|
||||
var errors []error
|
||||
for i := 0; ; i++ {
|
||||
err := conn.SetReadDeadline(deadline)
|
||||
if err != nil {
|
||||
return E.Cause(err, "set read deadline")
|
||||
err := conn.SetReadDeadline(deadline)
|
||||
if err != nil {
|
||||
return E.Cause(err, "set read deadline")
|
||||
}
|
||||
defer conn.SetReadDeadline(time.Time{})
|
||||
for _, sniffer := range sniffers {
|
||||
if buffer.IsEmpty() {
|
||||
err = sniffer(ctx, metadata, io.TeeReader(conn, buffer))
|
||||
} else {
|
||||
err = sniffer(ctx, metadata, io.MultiReader(bytes.NewReader(buffer.Bytes()), io.TeeReader(conn, buffer)))
|
||||
}
|
||||
_, err = buffer.ReadOnceFrom(conn)
|
||||
_ = conn.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
if i > 0 {
|
||||
break
|
||||
}
|
||||
return E.Cause(err, "read payload")
|
||||
}
|
||||
errors = nil
|
||||
for _, sniffer := range sniffers {
|
||||
err = sniffer(ctx, metadata, bytes.NewReader(buffer.Bytes()))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errors = append(errors, err)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
return E.Errors(errors...)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ const (
|
||||
ruleItemWIFISSID
|
||||
ruleItemWIFIBSSID
|
||||
ruleItemAdGuardDomain
|
||||
ruleItemProcessPathRegex
|
||||
ruleItemFinal uint8 = 0xFF
|
||||
)
|
||||
|
||||
@@ -208,8 +207,6 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
||||
rule.ProcessName, err = readRuleItemString(reader)
|
||||
case ruleItemProcessPath:
|
||||
rule.ProcessPath, err = readRuleItemString(reader)
|
||||
case ruleItemProcessPathRegex:
|
||||
rule.ProcessPathRegex, err = readRuleItemString(reader)
|
||||
case ruleItemPackageName:
|
||||
rule.PackageName, err = readRuleItemString(reader)
|
||||
case ruleItemWIFISSID:
|
||||
@@ -329,12 +326,6 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(rule.ProcessPathRegex) > 0 {
|
||||
err = writeRuleItemString(writer, ruleItemProcessPathRegex, rule.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(rule.PackageName) > 0 {
|
||||
err = writeRuleItemString(writer, ruleItemPackageName, rule.PackageName)
|
||||
if err != nil {
|
||||
|
||||
@@ -217,10 +217,18 @@ func init() {
|
||||
|
||||
func uTLSClientHelloID(name string) (utls.ClientHelloID, error) {
|
||||
switch name {
|
||||
case "chrome_psk", "chrome_psk_shuffle", "chrome_padding_psk_shuffle", "chrome_pq":
|
||||
fallthrough
|
||||
case "chrome", "":
|
||||
return utls.HelloChrome_Auto, nil
|
||||
case "chrome_psk":
|
||||
return utls.HelloChrome_100_PSK, nil
|
||||
case "chrome_psk_shuffle":
|
||||
return utls.HelloChrome_112_PSK_Shuf, nil
|
||||
case "chrome_padding_psk_shuffle":
|
||||
return utls.HelloChrome_114_Padding_PSK_Shuf, nil
|
||||
case "chrome_pq":
|
||||
return utls.HelloChrome_115_PQ, nil
|
||||
case "chrome_pq_psk":
|
||||
return utls.HelloChrome_115_PQ_PSK, nil
|
||||
case "firefox":
|
||||
return utls.HelloFirefox_Auto, nil
|
||||
case "edge":
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -114,7 +113,6 @@ func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err e
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
Timeout: C.TCPTimeout,
|
||||
}
|
||||
defer client.CloseIdleConnections()
|
||||
resp, err := client.Do(req.WithContext(ctx))
|
||||
|
||||
+1
-2
@@ -5,8 +5,7 @@ import "time"
|
||||
const (
|
||||
TCPKeepAliveInitial = 10 * time.Minute
|
||||
TCPKeepAliveInterval = 75 * time.Second
|
||||
TCPConnectTimeout = 5 * time.Second
|
||||
TCPTimeout = 15 * time.Second
|
||||
TCPTimeout = 5 * time.Second
|
||||
ReadPayloadTimeout = 300 * time.Millisecond
|
||||
DNSTimeout = 10 * time.Second
|
||||
QUICTimeout = 30 * time.Second
|
||||
|
||||
+6
-177
@@ -2,179 +2,11 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.11.0-alpha.4
|
||||
!!! failure "Help needed"
|
||||
|
||||
* Fixes and improvements
|
||||
Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
||||
|
||||
#### 1.11.0-alpha.2
|
||||
|
||||
* Add warnings for usage of deprecated features
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.11.0-alpha.1
|
||||
|
||||
* Update quic-go to v0.48.0
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.10.1
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.10.0
|
||||
|
||||
Important changes since 1.9:
|
||||
|
||||
* Introducing auto-redirect **1**
|
||||
* Add AdGuard DNS Filter support **2**
|
||||
* TUN address fields are merged **3**
|
||||
* Add custom options for `auto-route` and `auto-redirect` **4**
|
||||
* Drop support for go1.18 and go1.19 **5**
|
||||
* Add tailing comma support in JSON configuration
|
||||
* Improve sniffers **6**
|
||||
* Add new `inline` rule-set type **7**
|
||||
* Add access control options for Clash API **8**
|
||||
* Add `rule_set_ip_cidr_accept_empty` DNS address filter rule item **9**
|
||||
* Add auto reload support for local rule-set
|
||||
* Update fsnotify usages **10**
|
||||
* Add IP address support for `rule-set match` command
|
||||
* Add `rule-set decompile` command
|
||||
* Add `process_path_regex` rule item
|
||||
* Update uTLS to v1.6.7 **11**
|
||||
* Optimize memory usages of rule-sets **12**
|
||||
|
||||
**1**:
|
||||
|
||||
The new auto-redirect feature allows TUN to automatically
|
||||
configure connection redirection to improve proxy performance.
|
||||
|
||||
When auto-redirect is enabled, new route address set options will allow you to
|
||||
automatically configure destination IP CIDR rules from a specified rule set to the firewall.
|
||||
|
||||
Specified or unspecified destinations will bypass the sing-box routes to get better performance
|
||||
(for example, keep hardware offloading of direct traffics on the router).
|
||||
|
||||
See [TUN](/configuration/inbound/tun).
|
||||
|
||||
**2**:
|
||||
|
||||
The new feature allows you to use AdGuard DNS Filter lists in a sing-box without AdGuard Home.
|
||||
|
||||
See [AdGuard DNS Filter](/configuration/rule-set/adguard/).
|
||||
|
||||
**3**:
|
||||
|
||||
See [Migration](/migration/#tun-address-fields-are-merged).
|
||||
|
||||
**4**:
|
||||
|
||||
See [iproute2_table_index](/configuration/inbound/tun/#iproute2_table_index),
|
||||
[iproute2_rule_index](/configuration/inbound/tun/#iproute2_rule_index),
|
||||
[auto_redirect_input_mark](/configuration/inbound/tun/#auto_redirect_input_mark) and
|
||||
[auto_redirect_output_mark](/configuration/inbound/tun/#auto_redirect_output_mark).
|
||||
|
||||
**5**:
|
||||
|
||||
Due to maintenance difficulties, sing-box 1.10.0 requires at least Go 1.20 to compile.
|
||||
|
||||
**6**:
|
||||
|
||||
BitTorrent, DTLS, RDP, SSH sniffers are added.
|
||||
|
||||
Now the QUIC sniffer can correctly extract the server name from Chromium requests and
|
||||
can identify common QUIC clients, including
|
||||
Chromium, Safari, Firefox, quic-go (including uquic disguised as Chrome).
|
||||
|
||||
**7**:
|
||||
|
||||
The new [rule-set](/configuration/rule-set/) type inline (which also becomes the default type)
|
||||
allows you to write headless rules directly without creating a rule-set file.
|
||||
|
||||
**8**:
|
||||
|
||||
With the new access control options, not only can you allow Clash dashboards
|
||||
to access the Clash API on your local network,
|
||||
you can also manually limit the websites that can access the API instead of allowing everyone.
|
||||
|
||||
See [Clash API](/configuration/experimental/clash-api/).
|
||||
|
||||
**9**:
|
||||
|
||||
See [DNS Rule](/configuration/dns/rule/#rule_set_ip_cidr_accept_empty).
|
||||
|
||||
**10**:
|
||||
|
||||
sing-box now uses fsnotify correctly and will not cancel watching
|
||||
if the target file is deleted or recreated via rename (e.g. `mv`).
|
||||
|
||||
This affects all path options that support reload, including
|
||||
`tls.certificate_path`, `tls.key_path`, `tls.ech.key_path` and `rule_set.path`.
|
||||
|
||||
**11**:
|
||||
|
||||
Some legacy chrome fingerprints have been removed and will fallback to chrome,
|
||||
see [utls](/configuration/shared/tls#utls).
|
||||
|
||||
**12**:
|
||||
|
||||
See [Source Format](/configuration/rule-set/source-format/#version).
|
||||
|
||||
### 1.9.7
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.10.0-beta.11
|
||||
|
||||
* Update uTLS to v1.6.7 **1**
|
||||
|
||||
**1**:
|
||||
|
||||
Some legacy chrome fingerprints have been removed and will fallback to chrome,
|
||||
see [utls](/configuration/shared/tls#utls).
|
||||
|
||||
#### 1.10.0-beta.10
|
||||
|
||||
* Add `process_path_regex` rule item
|
||||
* Fixes and improvements
|
||||
|
||||
_The macOS standalone versions of sing-box (>=1.9.5/<1.10.0-beta.11) now silently fail and require manual granting of
|
||||
the **Full Disk Access** permission to system extension to start, probably due to Apple's changed security policy. We
|
||||
will prompt users about this in feature versions._
|
||||
|
||||
### 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, which should be completed within a week
|
||||
(SFI on the App Store and others on TestFlight are already available).
|
||||
|
||||
#### 1.10.0-beta.8
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
_With the help of a netizen, we are in the process of getting sing-box apps back on the App Store, which should be
|
||||
completed within a month (TestFlight is already available)._
|
||||
|
||||
#### 1.10.0-beta.7
|
||||
|
||||
* Update quic-go to v0.47.0
|
||||
* Fixes and improvements
|
||||
If your company or organization is willing to help us return to the App Store, please [contact us](mailto:contact@sagernet.org).
|
||||
|
||||
#### 1.10.0-beta.6
|
||||
|
||||
@@ -211,11 +43,6 @@ completed within a month (TestFlight is already available)._
|
||||
* 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.10.0-alpha.29
|
||||
|
||||
* Update quic-go to v0.46.0
|
||||
@@ -274,9 +101,11 @@ See [Source Format](/configuration/rule-set/source-format/#version).
|
||||
|
||||
**1**:
|
||||
|
||||
The new [rule-set](/configuration/rule-set/) type inline (which also becomes the default type)
|
||||
The new [rule-set] type inline (which also becomes the default type)
|
||||
allows you to write headless rules directly without creating a rule-set file.
|
||||
|
||||
[rule-set]: /configuration/rule-set/
|
||||
|
||||
**2**:
|
||||
|
||||
sing-box now uses fsnotify correctly and will not cancel watching
|
||||
|
||||
@@ -40,7 +40,6 @@ SFA provides an unprivileged TUN implementation through Android VpnService.
|
||||
|-----------------------|------------------|-----------------------------------|
|
||||
| `process_name` | :material-close: | No permission |
|
||||
| `process_path` | :material-close: | No permission |
|
||||
| `process_path_regex` | :material-close: | No permission |
|
||||
| `package_name` | :material-check: | / |
|
||||
| `user` | :material-close: | Use `package_name` instead |
|
||||
| `user_id` | :material-close: | Use `package_name` instead |
|
||||
|
||||
@@ -42,7 +42,6 @@ SFI/SFM/SFT provides an unprivileged TUN implementation through NetworkExtension
|
||||
|-----------------------|------------------|-----------------------|
|
||||
| `process_name` | :material-close: | No permission |
|
||||
| `process_path` | :material-close: | No permission |
|
||||
| `process_path_regex` | :material-close: | No permission |
|
||||
| `package_name` | :material-close: | / |
|
||||
| `user` | :material-close: | No permission |
|
||||
| `user_id` | :material-close: | No permission |
|
||||
|
||||
@@ -7,6 +7,13 @@ icon: material/apple
|
||||
SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides
|
||||
platform-specific function implementation, such as TUN transparent proxy implementation.
|
||||
|
||||
!!! failure "Unavailable"
|
||||
|
||||
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).
|
||||
|
||||
|
||||
## :material-graph: Requirements
|
||||
|
||||
* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+
|
||||
@@ -14,13 +21,13 @@ platform-specific function implementation, such as TUN transparent proxy impleme
|
||||
|
||||
## :material-download: Download
|
||||
|
||||
* [App Store](https://apps.apple.com/app/sing-box-vt/id6673731168)
|
||||
* TestFlight (Beta)
|
||||
* [App Store](https://apps.apple.com/us/app/sing-box/id6451272673)
|
||||
* ~~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).
|
||||
Once you donate, you can get an invitation by sending us your Apple ID [via email](mailto:contact@sagernet.org),
|
||||
or join our Telegram group for sponsors from [@yet_another_sponsor_bot](https://t.me/yet_another_sponsor_bot).
|
||||
|
||||
## :material-file-download: Download (macOS standalone version)
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
Maintained by Project S to provide a unified experience and platform-specific functionality.
|
||||
|
||||
| Platform | Client |
|
||||
|---------------------------------------|------------------------------------------|
|
||||
| ------------------------------------- | ---------------------------------------- |
|
||||
| :material-android: Android | [sing-box for Android](./android/) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [Unavailable](./apple/) |
|
||||
| :material-laptop: Desktop | Working in progress |
|
||||
|
||||
Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core
|
||||
|
||||
@@ -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-android: Android | [sing-box for Android](./android/) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [不可用](./apple/) |
|
||||
| :material-laptop: Desktop | 施工中 |
|
||||
|
||||
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
|
||||
VPN 客户端功能, 但代码质量很差且包含广告。
|
||||
|
||||
@@ -6,8 +6,7 @@ icon: material/new-box
|
||||
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
@@ -104,9 +103,6 @@ icon: material/new-box
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -272,16 +268,6 @@ Match process name.
|
||||
|
||||
Match process path.
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
Match process path using regular expression.
|
||||
|
||||
#### package_name
|
||||
|
||||
Match android package name.
|
||||
|
||||
@@ -6,8 +6,7 @@ icon: material/new-box
|
||||
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
@@ -104,9 +103,6 @@ icon: material/new-box
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -270,16 +266,6 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
匹配进程路径。
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS.
|
||||
|
||||
使用正则表达式匹配进程路径。
|
||||
|
||||
#### package_name
|
||||
|
||||
匹配 Android 应用包名。
|
||||
|
||||
@@ -47,7 +47,7 @@ TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
||||
|
||||
#### fallback
|
||||
|
||||
!!! failure ""
|
||||
!!! quote ""
|
||||
|
||||
There is no evidence that GFW detects and blocks Trojan servers based on HTTP responses, and opening the standard http/s port on the server is a much bigger signature.
|
||||
|
||||
|
||||
@@ -232,12 +232,12 @@ Automatically configure iptables/nftables to redirect connections.
|
||||
|
||||
*In Android*:
|
||||
|
||||
Only local IPv4 connections are forwarded. To share your VPN connection over hotspot or repeater,
|
||||
Only local connections are forwarded. To share your VPN connection over hotspot or repeater,
|
||||
use [VPNHotspot](https://github.com/Mygod/VPNHotspot).
|
||||
|
||||
*In Linux*:
|
||||
|
||||
`auto_route` with `auto_redirect` works as expected on routers **without intervention**.
|
||||
`auto_route` with `auto_redirect` now works as expected on routers **without intervention**.
|
||||
|
||||
#### auto_redirect_input_mark
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
仅支持 Linux,且需要 `auto_route` 已启用。
|
||||
|
||||
自动配置 iptables/nftables 以重定向连接。
|
||||
自动配置 iptables 以重定向 TCP 连接。
|
||||
|
||||
*在 Android 中*:
|
||||
|
||||
@@ -240,7 +240,7 @@ tun 接口的 IPv6 前缀。
|
||||
|
||||
*在 Linux 中*:
|
||||
|
||||
带有 `auto_redirect `的 `auto_route` 可以在路由器上按预期工作,**无需干预**。
|
||||
带有 `auto_redirect `的 `auto_route` 现在可以在路由器上按预期工作,**无需干预**。
|
||||
|
||||
#### auto_redirect_input_mark
|
||||
|
||||
|
||||
@@ -4,10 +4,9 @@ icon: material/alert-decagram
|
||||
|
||||
!!! quote "Changes in sing-box 1.10.0"
|
||||
|
||||
:material-plus: [client](#client)
|
||||
:material-plus: [client](#client)
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
@@ -102,9 +101,6 @@ icon: material/alert-decagram
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -281,16 +277,6 @@ Match process name.
|
||||
|
||||
Match process path.
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
Match process path using regular expression.
|
||||
|
||||
#### package_name
|
||||
|
||||
Match android package name.
|
||||
|
||||
@@ -6,8 +6,7 @@ icon: material/alert-decagram
|
||||
|
||||
:material-plus: [client](#client)
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
@@ -100,9 +99,6 @@ icon: material/alert-decagram
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -279,16 +275,6 @@ icon: material/alert-decagram
|
||||
|
||||
匹配进程路径。
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS.
|
||||
|
||||
使用正则表达式匹配进程路径。
|
||||
|
||||
#### package_name
|
||||
|
||||
匹配 Android 应用包名。
|
||||
|
||||
@@ -57,9 +57,6 @@
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -163,16 +160,6 @@ Match process name.
|
||||
|
||||
Match process path.
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
Match process path using regular expression.
|
||||
|
||||
#### package_name
|
||||
|
||||
Match android package name.
|
||||
|
||||
@@ -83,10 +83,7 @@
|
||||
|
||||
如果设置,域名将在请求发出之前解析为 IP。
|
||||
|
||||
| 出站 | 受影响的域名 | 默认回退值 |
|
||||
|----------|--------------------------|-------------------------------------------|
|
||||
| `direct` | 请求中的域名 | `inbound.domain_strategy` |
|
||||
| others | 服务器地址中的域名 | / |
|
||||
默认使用 `dns.strategy`。
|
||||
|
||||
#### fallback_delay
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.10.0"
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
:material-alert-decagram: [utls](#utls)
|
||||
|
||||
@@ -214,25 +210,28 @@ The path to the server private key, in PEM format.
|
||||
|
||||
==Client only==
|
||||
|
||||
!!! failure ""
|
||||
|
||||
There is no evidence that GFW detects and blocks servers based on TLS client fingerprinting, and using an imperfect emulation that has not been security reviewed could pose security risks.
|
||||
!!! note ""
|
||||
|
||||
uTLS is poorly maintained and the effect may be unproven, use at your own risk.
|
||||
|
||||
uTLS is a fork of "crypto/tls", which provides ClientHello fingerprinting resistance.
|
||||
|
||||
Available fingerprint values:
|
||||
|
||||
!!! warning "Removed since sing-box 1.10.0"
|
||||
!!! question "Since sing-box 1.8.0"
|
||||
|
||||
Some legacy chrome fingerprints have been removed and will fallback to chrome:
|
||||
|
||||
:material-close: chrome_psk
|
||||
:material-close: chrome_psk_shuffle
|
||||
:material-close: chrome_padding_psk_shuffle
|
||||
:material-close: chrome_pq
|
||||
:material-close: chrome_pq_psk
|
||||
:material-plus: chrome_psk
|
||||
:material-plus: chrome_psk_shuffle
|
||||
:material-plus: chrome_padding_psk_shuffle
|
||||
:material-plus: chrome_pq
|
||||
:material-plus: chrome_pq_psk
|
||||
|
||||
* chrome
|
||||
* chrome_psk
|
||||
* chrome_psk_shuffle
|
||||
* chrome_padding_psk_shuffle
|
||||
* chrome_pq
|
||||
* chrome_pq_psk
|
||||
* firefox
|
||||
* edge
|
||||
* safari
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.10.0 中的更改"
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
:material-alert-decagram: [utls](#utls)
|
||||
|
||||
@@ -48,8 +44,8 @@ icon: material/alert-decagram
|
||||
"handshake": {
|
||||
"server": "google.com",
|
||||
"server_port": 443,
|
||||
...
|
||||
// 拨号字段
|
||||
|
||||
... // 拨号字段
|
||||
},
|
||||
"private_key": "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc",
|
||||
"short_id": [
|
||||
@@ -206,25 +202,28 @@ TLS 版本值:
|
||||
|
||||
==仅客户端==
|
||||
|
||||
!!! failure ""
|
||||
!!! note ""
|
||||
|
||||
没有证据表明 GFW 根据 TLS 客户端指纹检测并阻止服务器,并且,使用一个未经安全审查的不完美模拟可能带来安全隐患。
|
||||
uTLS 维护不善且其效果可能未经证实,使用风险自负。
|
||||
|
||||
uTLS 是 "crypto/tls" 的一个分支,它提供了 ClientHello 指纹识别阻力。
|
||||
|
||||
可用的指纹值:
|
||||
|
||||
!!! warning "已在 sing-box 1.10.0 移除"
|
||||
!!! question "自 sing-box 1.8.0 起"
|
||||
|
||||
一些旧 chrome 指纹已被删除,并将会退到 chrome:
|
||||
|
||||
:material-close: chrome_psk
|
||||
:material-close: chrome_psk_shuffle
|
||||
:material-close: chrome_padding_psk_shuffle
|
||||
:material-close: chrome_pq
|
||||
:material-close: chrome_pq_psk
|
||||
:material-plus: chrome_psk
|
||||
:material-plus: chrome_psk_shuffle
|
||||
:material-plus: chrome_padding_psk_shuffle
|
||||
:material-plus: chrome_pq
|
||||
:material-plus: chrome_pq_psk
|
||||
|
||||
* chrome
|
||||
* chrome_psk
|
||||
* chrome_psk_shuffle
|
||||
* chrome_padding_psk_shuffle
|
||||
* chrome_pq
|
||||
* chrome_pq_psk
|
||||
* firefox
|
||||
* edge
|
||||
* safari
|
||||
|
||||
@@ -14,11 +14,6 @@ icon: material/delete-alert
|
||||
|
||||
Old fields are deprecated and will be removed in sing-box 1.11.0.
|
||||
|
||||
#### Match source rule items are renamed
|
||||
|
||||
`rule_set_ipcidr_match_source` route and DNS rule items are renamed to
|
||||
`rule_set_ip_cidr_match_source` and will be remove in sing-box 1.11.0.
|
||||
|
||||
#### Drop support for go1.18 and go1.19
|
||||
|
||||
Due to maintenance difficulties, sing-box 1.10.0 requires at least Go 1.20 to compile.
|
||||
|
||||
@@ -6,18 +6,13 @@ icon: material/delete-alert
|
||||
|
||||
## 1.10.0
|
||||
|
||||
#### Match source 规则项已重命名
|
||||
|
||||
`rule_set_ipcidr_match_source` 路由和 DNS 规则项已被重命名为
|
||||
`rule_set_ip_cidr_match_source` 且将在 sing-box 1.11.0 中被移除。
|
||||
|
||||
#### TUN 地址字段已合并
|
||||
|
||||
`inet4_address` 和 `inet6_address` 已合并为 `address`,
|
||||
`inet4_route_address` 和 `inet6_route_address` 已合并为 `route_address`,
|
||||
`inet4_route_exclude_address` 和 `inet6_route_exclude_address` 已合并为 `route_exclude_address`。
|
||||
|
||||
旧字段已废弃,且将在 sing-box 1.11.0 中被移除。
|
||||
旧字段已废弃,且将在 sing-box 1.11.0 中移除。
|
||||
|
||||
#### 移除对 go1.18 和 go1.19 的支持
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@ description: Welcome to the wiki page for the sing-box project.
|
||||
|
||||
# :material-home: Home
|
||||
|
||||
!!! failure "Help needed"
|
||||
|
||||
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).
|
||||
|
||||
Welcome to the wiki page for the sing-box project.
|
||||
|
||||
The universal proxy platform.
|
||||
|
||||
@@ -4,6 +4,13 @@ description: 欢迎来到该 sing-box 项目的文档页。
|
||||
|
||||
# :material-home: 开始
|
||||
|
||||
!!! failure "需要帮助"
|
||||
|
||||
由于我们的 Apple 开发者账户出现问题,Apple 平台上的 sing-box 应用暂时无法下载或更新。
|
||||
|
||||
如果您的公司或组织愿意帮助我们重返 App Store,请[联系我们](mailto:contact@sagernet.org)。
|
||||
|
||||
|
||||
欢迎来到该 sing-box 项目的文档页。
|
||||
|
||||
通用代理平台。
|
||||
|
||||
@@ -6,18 +6,26 @@ icon: material/file-code
|
||||
|
||||
## :material-graph: Requirements
|
||||
|
||||
### sing-box 1.10
|
||||
Before sing-box 1.4.0:
|
||||
|
||||
* Go 1.20.0 - ~
|
||||
* 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 - ~ 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
|
||||
|
||||
@@ -6,17 +6,25 @@ icon: material/file-code
|
||||
|
||||
## :material-graph: 要求
|
||||
|
||||
### sing-box 1.10
|
||||
sing-box 1.4.0 前:
|
||||
|
||||
* 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
|
||||
* Go 1.18.5 - 1.20.x
|
||||
|
||||
### sing-box 1.9
|
||||
从 sing-box 1.4.0:
|
||||
|
||||
* 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
|
||||
* 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`
|
||||
|
||||
您可以从 https://go.dev/doc/install 下载并安装 Go,推荐使用最新版本。
|
||||
|
||||
|
||||
@@ -87,12 +87,12 @@ icon: material/package
|
||||
|
||||
## :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 |
|
||||
| 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) |
|
||||
| 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:
|
||||
|
||||
|
||||
@@ -85,14 +85,15 @@ icon: material/package
|
||||
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
|
||||
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||
|
||||
|
||||
## :material-alert: 存在问题的源
|
||||
|
||||
| 类型 | 平台 | 链接 | 原因 |
|
||||
|------------|---------|-------------------------------------------------------------------------------------------|-----------------|
|
||||
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改 |
|
||||
| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 |
|
||||
| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 |
|
||||
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) |
|
||||
| 类型 | 平台 | 链接 | 原因 |
|
||||
|------------|---------|-------------------------------------------------------------------------------------------|-----------------------|
|
||||
| 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) |
|
||||
|
||||
如果您是其用户,请向他们报告问题:
|
||||
|
||||
|
||||
@@ -70,23 +70,6 @@ Old fields are deprecated and will be removed in sing-box 1.11.0.
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
@@ -70,22 +70,6 @@ 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` 行为更新
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
icon: material/hand-coin
|
||||
---
|
||||
|
||||
# Sponsors
|
||||
|
||||
Do you or your friends use sing-box?
|
||||
|
||||
You can help keep the project bug-free and feature rich by sponsoring
|
||||
the project maintainer via [GitHub Sponsors](https://github.com/sponsors/nekohasekai).
|
||||
|
||||

|
||||
|
||||
### Special Sponsors
|
||||
|
||||
**Viral Tech, Inc.**
|
||||
|
||||
Helping us re-list sing-box apps on the Apple Store.
|
||||
|
||||
---
|
||||
|
||||
[](https://www.jetbrains.com)
|
||||
|
||||
Free license for the amazing IDEs.
|
||||
|
||||
---
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
@@ -60,7 +60,7 @@ func (s *Server) downloadExternalUI() error {
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
ForceAttemptHTTP2: true,
|
||||
TLSHandshakeTimeout: C.TCPTimeout,
|
||||
TLSHandshakeTimeout: 5 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||||
},
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package deprecated
|
||||
|
||||
import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
type Note struct {
|
||||
Name string
|
||||
Description string
|
||||
DeprecatedVersion string
|
||||
ScheduledVersion string
|
||||
EnvName string
|
||||
MigrationLink string
|
||||
}
|
||||
|
||||
func (n Note) Impending() bool {
|
||||
if n.ScheduledVersion == "" {
|
||||
return false
|
||||
}
|
||||
if !semver.IsValid("v" + C.Version) {
|
||||
return false
|
||||
}
|
||||
versionMinor := semver.Compare(semver.MajorMinor("v"+C.Version), "v"+n.ScheduledVersion)
|
||||
if versionMinor < 0 {
|
||||
panic("invalid deprecated note: " + n.Name)
|
||||
}
|
||||
return versionMinor <= 1
|
||||
}
|
||||
|
||||
func (n Note) Message() string {
|
||||
return F.ToString(
|
||||
n.Description, " is deprecated in sing-box ", n.DeprecatedVersion,
|
||||
" and will be removed in sing-box ", n.ScheduledVersion, ", please checkout documentation for migration.",
|
||||
)
|
||||
}
|
||||
|
||||
func (n Note) MessageWithLink() string {
|
||||
return F.ToString(
|
||||
n.Description, " is deprecated in sing-box ", n.DeprecatedVersion,
|
||||
" and will be removed in sing-box ", n.ScheduledVersion, ", checkout documentation for migration: ", n.MigrationLink,
|
||||
)
|
||||
}
|
||||
|
||||
var OptionBadMatchSource = Note{
|
||||
Name: "bad-match-source",
|
||||
Description: "legacy match source rule item",
|
||||
DeprecatedVersion: "1.10.0",
|
||||
ScheduledVersion: "1.11.0",
|
||||
MigrationLink: "https://sing-box.sagernet.org/deprecated/#match-source-rule-items-are-renamed",
|
||||
}
|
||||
|
||||
var OptionGEOIP = Note{
|
||||
Name: "geoip",
|
||||
Description: "geoip database",
|
||||
DeprecatedVersion: "1.8.0",
|
||||
ScheduledVersion: "1.12.0",
|
||||
EnvName: "GEOIP",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-geoip-to-rule-sets",
|
||||
}
|
||||
|
||||
var OptionGEOSITE = Note{
|
||||
Name: "geosite",
|
||||
Description: "geosite database",
|
||||
DeprecatedVersion: "1.8.0",
|
||||
ScheduledVersion: "1.12.0",
|
||||
EnvName: "GEOSITE",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-geosite-to-rule-sets",
|
||||
}
|
||||
|
||||
var OptionTUNAddressX = Note{
|
||||
Name: "tun-address-x",
|
||||
Description: "legacy tun address fields",
|
||||
DeprecatedVersion: "1.10.0",
|
||||
ScheduledVersion: "1.12.0",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#tun-address-fields-are-merged",
|
||||
}
|
||||
|
||||
var Options = []Note{
|
||||
OptionBadMatchSource,
|
||||
OptionGEOIP,
|
||||
OptionGEOSITE,
|
||||
OptionTUNAddressX,
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package deprecated
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
)
|
||||
|
||||
type envManager struct {
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
func NewEnvManager(logger logger.Logger) Manager {
|
||||
return &envManager{logger: logger}
|
||||
}
|
||||
|
||||
func (f *envManager) ReportDeprecated(feature Note) {
|
||||
if !feature.Impending() {
|
||||
f.logger.Warn(feature.MessageWithLink())
|
||||
return
|
||||
}
|
||||
enable, enableErr := strconv.ParseBool(os.Getenv("ENABLE_DEPRECATED_" + feature.EnvName))
|
||||
if enableErr == nil && enable {
|
||||
f.logger.Warn(feature.MessageWithLink())
|
||||
return
|
||||
}
|
||||
f.logger.Error(feature.MessageWithLink())
|
||||
f.logger.Fatal("to continuing using this feature, set ENABLE_DEPRECATED_" + feature.EnvName + "=true")
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package deprecated
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
type Manager interface {
|
||||
ReportDeprecated(feature Note)
|
||||
}
|
||||
|
||||
func Report(ctx context.Context, feature Note) {
|
||||
manager := service.FromContext[Manager](ctx)
|
||||
if manager == nil {
|
||||
return
|
||||
}
|
||||
manager.ReportDeprecated(feature)
|
||||
}
|
||||
@@ -16,5 +16,4 @@ const (
|
||||
CommandSetSystemProxyEnabled
|
||||
CommandConnections
|
||||
CommandCloseConnection
|
||||
CommandGetDeprecatedNotes
|
||||
)
|
||||
|
||||
@@ -20,7 +20,6 @@ type CommandClient struct {
|
||||
type CommandClientOptions struct {
|
||||
Command int32
|
||||
StatusInterval int64
|
||||
IsMainClient bool
|
||||
}
|
||||
|
||||
type CommandClientHandler interface {
|
||||
@@ -29,7 +28,6 @@ type CommandClientHandler interface {
|
||||
ClearLogs()
|
||||
WriteLogs(messageList StringIterator)
|
||||
WriteStatus(message *StatusMessage)
|
||||
OpenURL(url string)
|
||||
WriteGroups(message OutboundGroupIterator)
|
||||
InitializeClashMode(modeList StringIterator, currentMode string)
|
||||
UpdateClashMode(newMode string)
|
||||
@@ -93,13 +91,9 @@ func (c *CommandClient) Connect() error {
|
||||
c.handler.Connected()
|
||||
go c.handleLogConn(conn)
|
||||
case CommandStatus:
|
||||
err = binary.Write(conn, binary.BigEndian, c.options.IsMainClient)
|
||||
if err != nil {
|
||||
return E.Cause(err, "write is main client")
|
||||
}
|
||||
err = binary.Write(conn, binary.BigEndian, c.options.StatusInterval)
|
||||
if err != nil {
|
||||
return E.Cause(err, "write header")
|
||||
return E.Cause(err, "write interval")
|
||||
}
|
||||
c.handler.Connected()
|
||||
go c.handleStatusConn(conn)
|
||||
|
||||
@@ -18,10 +18,6 @@ func (c *CommandClient) CloseConnection(connId string) error {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
err = binary.Write(conn, binary.BigEndian, uint8(CommandCloseConnection))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writer := bufio.NewWriter(conn)
|
||||
err = varbin.Write(writer, binary.BigEndian, connId)
|
||||
if err != nil {
|
||||
|
||||
@@ -25,7 +25,6 @@ func (c *CommandClient) handleConnectionsConn(conn net.Conn) {
|
||||
connections Connections
|
||||
)
|
||||
for {
|
||||
rawConnections = nil
|
||||
err := varbin.Read(reader, binary.BigEndian, &rawConnections)
|
||||
if err != nil {
|
||||
c.handler.Disconnected(err.Error())
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/varbin"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
func (c *CommandClient) GetDeprecatedNotes() (DeprecatedNoteIterator, error) {
|
||||
conn, err := c.directConnect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
err = binary.Write(conn, binary.BigEndian, uint8(CommandGetDeprecatedNotes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = readError(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var features []deprecated.Note
|
||||
err = varbin.Read(conn, binary.BigEndian, &features)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newIterator(common.Map(features, func(it deprecated.Note) *DeprecatedNote { return (*DeprecatedNote)(&it) })), nil
|
||||
}
|
||||
|
||||
func (s *CommandServer) handleGetDeprecatedNotes(conn net.Conn) error {
|
||||
boxService := s.service
|
||||
if boxService == nil {
|
||||
return writeError(conn, E.New("service not ready"))
|
||||
}
|
||||
err := writeError(conn, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return varbin.Write(conn, binary.BigEndian, service.FromContext[deprecated.Manager](boxService.ctx).(*deprecatedManager).Get())
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/varbin"
|
||||
)
|
||||
|
||||
type myEvent interface {
|
||||
writeTo(writer varbin.Writer)
|
||||
}
|
||||
|
||||
func readEvent(reader varbin.Reader) (myEvent, error) {
|
||||
eventType, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch eventType {
|
||||
case eventTypeEmpty:
|
||||
return nil, nil
|
||||
case eventTypeOpenURL:
|
||||
url, err := varbin.ReadValue[string](reader, binary.BigEndian)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &eventOpenURL{URL: url}, nil
|
||||
default:
|
||||
return nil, E.New("unknown event type: ", eventType)
|
||||
}
|
||||
}
|
||||
|
||||
type eventOpenURL struct {
|
||||
URL string
|
||||
}
|
||||
|
||||
func (e *eventOpenURL) writeTo(writer varbin.Writer) {
|
||||
writer.WriteByte(eventTypeOpenURL)
|
||||
varbin.Write(writer, binary.BigEndian, e.URL)
|
||||
}
|
||||
@@ -33,7 +33,6 @@ type CommandServer struct {
|
||||
urlTestUpdate chan struct{}
|
||||
modeUpdate chan struct{}
|
||||
logReset chan struct{}
|
||||
events chan myEvent
|
||||
|
||||
closedConnections []Connection
|
||||
}
|
||||
@@ -53,7 +52,6 @@ func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServ
|
||||
urlTestUpdate: make(chan struct{}, 1),
|
||||
modeUpdate: make(chan struct{}, 1),
|
||||
logReset: make(chan struct{}, 1),
|
||||
events: make(chan myEvent, 8),
|
||||
}
|
||||
server.observer = observable.NewObserver[string](server.subscriber, 64)
|
||||
return server
|
||||
@@ -63,12 +61,6 @@ func (s *CommandServer) SetService(newService *BoxService) {
|
||||
if newService != nil {
|
||||
service.PtrFromContext[urltest.HistoryStorage](newService.ctx).SetHook(s.urlTestUpdate)
|
||||
newService.instance.Router().ClashServer().(*clashapi.Server).SetModeUpdateHook(s.modeUpdate)
|
||||
newService.platformInterface.openURLFunc = func(url string) {
|
||||
select {
|
||||
case s.events <- &eventOpenURL{URL: url}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
s.service = newService
|
||||
s.notifyURLTestUpdate()
|
||||
@@ -182,8 +174,6 @@ func (s *CommandServer) handleConnection(conn net.Conn) error {
|
||||
return s.handleConnectionsConn(conn)
|
||||
case CommandCloseConnection:
|
||||
return s.handleCloseConnection(conn)
|
||||
case CommandGetDeprecatedNotes:
|
||||
return s.handleGetDeprecatedNotes(conn)
|
||||
default:
|
||||
return E.New("unknown command: ", command)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
std_bufio "bufio"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"runtime"
|
||||
@@ -10,15 +9,9 @@ import (
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
"github.com/sagernet/sing/common/memory"
|
||||
)
|
||||
|
||||
const (
|
||||
eventTypeEmpty byte = iota
|
||||
eventTypeOpenURL
|
||||
)
|
||||
|
||||
type StatusMessage struct {
|
||||
Memory int64
|
||||
Goroutines int32
|
||||
@@ -51,74 +44,31 @@ func (s *CommandServer) readStatus() StatusMessage {
|
||||
}
|
||||
|
||||
func (s *CommandServer) handleStatusConn(conn net.Conn) error {
|
||||
var isMainClient bool
|
||||
err := binary.Read(conn, binary.BigEndian, &isMainClient)
|
||||
if err != nil {
|
||||
return E.Cause(err, "read is main client")
|
||||
}
|
||||
var interval int64
|
||||
err = binary.Read(conn, binary.BigEndian, &interval)
|
||||
err := binary.Read(conn, binary.BigEndian, &interval)
|
||||
if err != nil {
|
||||
return E.Cause(err, "read interval")
|
||||
}
|
||||
ticker := time.NewTicker(time.Duration(interval))
|
||||
defer ticker.Stop()
|
||||
ctx := connKeepAlive(conn)
|
||||
writer := std_bufio.NewWriter(conn)
|
||||
if isMainClient {
|
||||
for {
|
||||
writer.WriteByte(eventTypeEmpty)
|
||||
err = binary.Write(conn, binary.BigEndian, s.readStatus())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writer.Flush()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ticker.C:
|
||||
case event := <-s.events:
|
||||
event.writeTo(writer)
|
||||
writer.Flush()
|
||||
}
|
||||
for {
|
||||
err = binary.Write(conn, binary.BigEndian, s.readStatus())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
for {
|
||||
err = binary.Write(conn, binary.BigEndian, s.readStatus())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
writer.Flush()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ticker.C:
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ticker.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CommandClient) handleStatusConn(conn net.Conn) {
|
||||
reader := std_bufio.NewReader(conn)
|
||||
for {
|
||||
if c.options.IsMainClient {
|
||||
rawEvent, err := readEvent(reader)
|
||||
if err != nil {
|
||||
c.handler.Disconnected(err.Error())
|
||||
return
|
||||
}
|
||||
switch event := rawEvent.(type) {
|
||||
case *eventOpenURL:
|
||||
c.handler.OpenURL(event.URL)
|
||||
continue
|
||||
case nil:
|
||||
default:
|
||||
panic(F.ToString("unexpected event type: ", event))
|
||||
return
|
||||
}
|
||||
}
|
||||
var message StatusMessage
|
||||
err := binary.Read(reader, binary.BigEndian, &message)
|
||||
err := binary.Read(conn, binary.BigEndian, &message)
|
||||
if err != nil {
|
||||
c.handler.Disconnected(err.Error())
|
||||
return
|
||||
|
||||
@@ -134,9 +134,6 @@ func (s *interfaceMonitorStub) RegisterCallback(callback tun.DefaultInterfaceUpd
|
||||
func (s *interfaceMonitorStub) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) OpenURL(url string) {
|
||||
}
|
||||
|
||||
func FormatConfig(configContent string) (string, error) {
|
||||
options, err := parseConfig(configContent)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
)
|
||||
|
||||
var _ deprecated.Manager = (*deprecatedManager)(nil)
|
||||
|
||||
type deprecatedManager struct {
|
||||
access sync.Mutex
|
||||
features []deprecated.Note
|
||||
}
|
||||
|
||||
func (m *deprecatedManager) ReportDeprecated(feature deprecated.Note) {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
m.features = append(m.features, feature)
|
||||
}
|
||||
|
||||
func (m *deprecatedManager) Get() []deprecated.Note {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
features := m.features
|
||||
m.features = nil
|
||||
return features
|
||||
}
|
||||
|
||||
var _ = deprecated.Note(DeprecatedNote{})
|
||||
|
||||
type DeprecatedNote struct {
|
||||
Name string
|
||||
Description string
|
||||
DeprecatedVersion string
|
||||
ScheduledVersion string
|
||||
EnvName string
|
||||
MigrationLink string
|
||||
}
|
||||
|
||||
func (n DeprecatedNote) Impending() bool {
|
||||
return deprecated.Note(n).Impending()
|
||||
}
|
||||
|
||||
func (n DeprecatedNote) Message() string {
|
||||
return deprecated.Note(n).Message()
|
||||
}
|
||||
|
||||
func (n DeprecatedNote) MessageWithLink() string {
|
||||
return deprecated.Note(n).MessageWithLink()
|
||||
}
|
||||
|
||||
type DeprecatedNoteIterator interface {
|
||||
HasNext() bool
|
||||
Next() *DeprecatedNote
|
||||
}
|
||||
@@ -17,8 +17,8 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
@@ -69,9 +69,8 @@ type httpClient struct {
|
||||
|
||||
func NewHTTPClient() HTTPClient {
|
||||
client := new(httpClient)
|
||||
client.client.Timeout = 15 * time.Second
|
||||
client.client.Transport = &client.transport
|
||||
client.transport.ForceAttemptHTTP2 = true
|
||||
client.transport.TLSHandshakeTimeout = C.TCPTimeout
|
||||
client.transport.TLSClientConfig = &client.tls
|
||||
client.transport.DisableKeepAlives = true
|
||||
return client
|
||||
@@ -128,6 +127,7 @@ func (c *httpClient) TrySocks5(port int32) {
|
||||
}
|
||||
|
||||
func (c *httpClient) KeepAlive() {
|
||||
c.transport.ForceAttemptHTTP2 = true
|
||||
c.transport.DisableKeepAlives = false
|
||||
}
|
||||
|
||||
|
||||
@@ -25,5 +25,4 @@ type Interface interface {
|
||||
ClearDNSCache()
|
||||
ReadWIFIState() adapter.WIFIState
|
||||
process.Searcher
|
||||
OpenURL(url string)
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ func DecodeProfileContent(data []byte) (*ProfileContent, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Read(bReader, binary.BigEndian, &content.Type)
|
||||
err = binary.Read(reader, binary.BigEndian, &content.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -233,17 +233,17 @@ func DecodeProfileContent(data []byte) (*ProfileContent, error) {
|
||||
}
|
||||
}
|
||||
if content.Type == ProfileTypeRemote || (version == 0 && content.Type != ProfileTypeLocal) {
|
||||
err = binary.Read(bReader, binary.BigEndian, &content.AutoUpdate)
|
||||
err = binary.Read(reader, binary.BigEndian, &content.AutoUpdate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if version >= 1 {
|
||||
err = binary.Read(bReader, binary.BigEndian, &content.AutoUpdateInterval)
|
||||
err = binary.Read(reader, binary.BigEndian, &content.AutoUpdateInterval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
err = binary.Read(bReader, binary.BigEndian, &content.LastUpdated)
|
||||
err = binary.Read(reader, binary.BigEndian, &content.LastUpdated)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/sagernet/sing-box/common/process"
|
||||
"github.com/sagernet/sing-box/common/urltest"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
@@ -34,9 +33,9 @@ type BoxService struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
instance *box.Box
|
||||
platformInterface *platformInterfaceWrapper
|
||||
pauseManager pause.Manager
|
||||
urlTestHistoryStorage *urltest.HistoryStorage
|
||||
|
||||
servicePauseFields
|
||||
}
|
||||
|
||||
@@ -50,7 +49,6 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
||||
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
||||
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
||||
ctx = service.ContextWith[deprecated.Manager](ctx, new(deprecatedManager))
|
||||
platformWrapper := &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()}
|
||||
instance, err := box.New(box.Options{
|
||||
Context: ctx,
|
||||
@@ -67,7 +65,6 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
instance: instance,
|
||||
platformInterface: platformWrapper,
|
||||
urlTestHistoryStorage: urlTestHistoryStorage,
|
||||
pauseManager: service.FromContext[pause.Manager](ctx),
|
||||
}, nil
|
||||
@@ -103,10 +100,9 @@ var (
|
||||
)
|
||||
|
||||
type platformInterfaceWrapper struct {
|
||||
iif PlatformInterface
|
||||
useProcFS bool
|
||||
router adapter.Router
|
||||
openURLFunc func(url string)
|
||||
iif PlatformInterface
|
||||
useProcFS bool
|
||||
router adapter.Router
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
|
||||
@@ -240,9 +236,3 @@ func (w *platformInterfaceWrapper) DisableColors() bool {
|
||||
func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) {
|
||||
w.iif.WriteLog(message)
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) OpenURL(url string) {
|
||||
if w.openURLFunc != nil {
|
||||
w.openURLFunc(url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,48 +7,47 @@ require (
|
||||
github.com/caddyserver/certmagic v0.20.0
|
||||
github.com/cloudflare/circl v1.3.7
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/go-chi/chi/v5 v5.1.0
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/gofrs/uuid/v5 v5.3.0
|
||||
github.com/gofrs/uuid/v5 v5.2.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2
|
||||
github.com/libdns/alidns v1.0.3
|
||||
github.com/libdns/cloudflare v0.1.1
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa
|
||||
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d
|
||||
github.com/mholt/acmez v1.2.0
|
||||
github.com/miekg/dns v1.1.62
|
||||
github.com/miekg/dns v1.1.61
|
||||
github.com/ooni/go-libtor v1.1.8
|
||||
github.com/oschwald/maxminddb-golang v1.12.0
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1
|
||||
github.com/sagernet/cors v1.2.1
|
||||
github.com/sagernet/fswatch v0.1.1
|
||||
github.com/sagernet/gomobile v0.1.4
|
||||
github.com/sagernet/gomobile v0.1.3
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
||||
github.com/sagernet/quic-go v0.48.0-beta.1
|
||||
github.com/sagernet/quic-go v0.46.0-beta.4
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.5.0-rc.2
|
||||
github.com/sagernet/sing-dns v0.3.0-rc.2
|
||||
github.com/sagernet/sing v0.5.0-beta.1
|
||||
github.com/sagernet/sing-dns v0.3.0-beta.14
|
||||
github.com/sagernet/sing-mux v0.2.0
|
||||
github.com/sagernet/sing-quic v0.3.0-rc.1
|
||||
github.com/sagernet/sing-quic v0.3.0-beta.3
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.4.0-rc.4
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d
|
||||
github.com/sagernet/sing-vmess v0.1.12
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||
github.com/sagernet/utls v1.6.7
|
||||
github.com/sagernet/utls v1.5.4
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.uber.org/zap v1.27.0
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/crypto v0.25.0
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||
golang.org/x/mod v0.20.0
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/sys v0.26.0
|
||||
golang.org/x/net v0.27.0
|
||||
golang.org/x/sys v0.22.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
google.golang.org/grpc v1.63.2
|
||||
google.golang.org/protobuf v1.33.0
|
||||
@@ -62,6 +61,7 @@ require (
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gaukas/godicttls v0.0.4 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
@@ -90,10 +90,11 @@ require (
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/mod v0.19.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
@@ -8,7 +8,7 @@ github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4
|
||||
github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
@@ -17,8 +17,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
|
||||
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
@@ -30,8 +32,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk=
|
||||
github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM=
|
||||
github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
@@ -70,12 +72,12 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa h1:9mcjV+RGZVC3reJBNDjjNPyS8PmFG97zq56X7WNaFO4=
|
||||
github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa/go.mod h1:4tLB5c8U0CxpkFM+AJJB77jEaVDbLH5XQvy42vAGsWw=
|
||||
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d h1:j9LtzkYstLFoNvXW824QQeN7Y26uPL5249kzWKbzO9U=
|
||||
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
|
||||
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
||||
@@ -102,47 +104,47 @@ github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/gomobile v0.1.4 h1:WzX9ka+iHdupMgy2Vdich+OAt7TM8C2cZbIbzNjBrJY=
|
||||
github.com/sagernet/gomobile v0.1.4/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||
github.com/sagernet/gomobile v0.1.3 h1:ohjIb1Ou2+1558PnZour3od69suSuvkdSVOlO1tC4B8=
|
||||
github.com/sagernet/gomobile v0.1.3/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.48.0-beta.1 h1:86hQZrmuoARI3BpDRkQaP0iAVpywA4YsRrzJPYuPKWg=
|
||||
github.com/sagernet/quic-go v0.48.0-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/+or9YMLaG5VeTk4k=
|
||||
github.com/sagernet/quic-go v0.46.0-beta.4 h1:k9f7VSKaM47AY6MPND0Qf1KRN7HwimPg9zdOFTXTiCk=
|
||||
github.com/sagernet/quic-go v0.46.0-beta.4/go.mod h1:zJmVdJUNqEDXfubf4KtIOUHHerggjBduiGRLNzJspcM=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.5.0-rc.2 h1:tIrs6pRbjJWvI0ITRSg47P1wosY+iSuHpw9t5/hBx+Q=
|
||||
github.com/sagernet/sing v0.5.0-rc.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-dns v0.3.0-rc.2 h1:z1yROBxd/6wik5h53Sz5df1DSmbPTaOu/Z0wAmyXGoQ=
|
||||
github.com/sagernet/sing-dns v0.3.0-rc.2/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
|
||||
github.com/sagernet/sing v0.5.0-beta.1 h1:THZMZgJcDQxutE++6Ckih1HlvMtXple94RBGa6GSg2I=
|
||||
github.com/sagernet/sing v0.5.0-beta.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-dns v0.3.0-beta.14 h1:/s+fJzYKsvLaNDt/2rjpsrDcN8wmCO2JbX6OFrl8Nww=
|
||||
github.com/sagernet/sing-dns v0.3.0-beta.14/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00=
|
||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
|
||||
github.com/sagernet/sing-quic v0.3.0-rc.1 h1:SlzL1yfEAKJyRduub8vzOVtbyTLAX7RZEEBZxO5utts=
|
||||
github.com/sagernet/sing-quic v0.3.0-rc.1/go.mod h1:uX+aUHA0fgIN6U3WViseDpSdTQriViZ7qz0Wbsf1mNQ=
|
||||
github.com/sagernet/sing-quic v0.3.0-beta.3 h1:8S98VXZxtSiOqVCFbCNbMEvKDPhOF/VNBYMjVC3xMhw=
|
||||
github.com/sagernet/sing-quic v0.3.0-beta.3/go.mod h1:rFPUlYnSj1Bx9gFSghjCqrCzfGvpjhkisOiTKpjq5vQ=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.4.0-rc.4 h1:EFz+UjLZTm+YS3ob1vpqjOga67wyvnxWcbQKfe5wE3Y=
|
||||
github.com/sagernet/sing-tun v0.4.0-rc.4/go.mod h1:+lQdWhqD4atzrCgRhoyrxBCg1OBru/hAv2BT3kdgmGM=
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d h1:2nBM9W9fOCM45hjlu1Fh9qyzBCgKEkq+SOuRCbCCs7c=
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.13.0.20240703164908-1f043289199d/go.mod h1:81JwnnYw8X9W9XvmZetSTTiPgIE3SbAbnc+EHKwPJ5U=
|
||||
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
|
||||
github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
||||
github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co=
|
||||
github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8/go.mod h1:K4J7/npM+VAMUeUmTa2JaA02JmyheP0GpRBOUvn3ecc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -170,18 +172,18 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -190,19 +192,19 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
@@ -55,18 +54,15 @@ type Tun struct {
|
||||
|
||||
func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions, platformInterface platform.Interface) (*Tun, error) {
|
||||
address := options.Address
|
||||
var deprecatedAddressUsed bool
|
||||
//nolint:staticcheck
|
||||
//goland:noinspection GoDeprecation
|
||||
if len(options.Inet4Address) > 0 {
|
||||
address = append(address, options.Inet4Address...)
|
||||
deprecatedAddressUsed = true
|
||||
}
|
||||
//nolint:staticcheck
|
||||
//goland:noinspection GoDeprecation
|
||||
if len(options.Inet6Address) > 0 {
|
||||
address = append(address, options.Inet6Address...)
|
||||
deprecatedAddressUsed = true
|
||||
}
|
||||
inet4Address := common.Filter(address, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
@@ -80,13 +76,11 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
//goland:noinspection GoDeprecation
|
||||
if len(options.Inet4RouteAddress) > 0 {
|
||||
routeAddress = append(routeAddress, options.Inet4RouteAddress...)
|
||||
deprecatedAddressUsed = true
|
||||
}
|
||||
//nolint:staticcheck
|
||||
//goland:noinspection GoDeprecation
|
||||
if len(options.Inet6RouteAddress) > 0 {
|
||||
routeAddress = append(routeAddress, options.Inet6RouteAddress...)
|
||||
deprecatedAddressUsed = true
|
||||
}
|
||||
inet4RouteAddress := common.Filter(routeAddress, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
@@ -100,13 +94,11 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
//goland:noinspection GoDeprecation
|
||||
if len(options.Inet4RouteExcludeAddress) > 0 {
|
||||
routeExcludeAddress = append(routeExcludeAddress, options.Inet4RouteExcludeAddress...)
|
||||
deprecatedAddressUsed = true
|
||||
}
|
||||
//nolint:staticcheck
|
||||
//goland:noinspection GoDeprecation
|
||||
if len(options.Inet6RouteExcludeAddress) > 0 {
|
||||
routeExcludeAddress = append(routeExcludeAddress, options.Inet6RouteExcludeAddress...)
|
||||
deprecatedAddressUsed = true
|
||||
}
|
||||
inet4RouteExcludeAddress := common.Filter(routeExcludeAddress, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
@@ -115,10 +107,6 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
return it.Addr().Is6()
|
||||
})
|
||||
|
||||
if deprecatedAddressUsed {
|
||||
deprecated.Report(ctx, deprecated.OptionTUNAddressX)
|
||||
}
|
||||
|
||||
tunMTU := options.MTU
|
||||
if tunMTU == 0 {
|
||||
tunMTU = 9000
|
||||
|
||||
+3
-8
@@ -11,22 +11,18 @@ theme:
|
||||
logo: assets/icon.svg
|
||||
favicon: assets/icon.svg
|
||||
palette:
|
||||
- media: "(prefers-color-scheme)"
|
||||
toggle:
|
||||
icon: material/link
|
||||
name: Switch to light mode
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
scheme: default
|
||||
primary: white
|
||||
toggle:
|
||||
icon: material/toggle-switch
|
||||
icon: material/brightness-7
|
||||
name: Switch to dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
primary: black
|
||||
toggle:
|
||||
icon: material/toggle-switch-off
|
||||
name: Switch to system preference
|
||||
icon: material/brightness-4
|
||||
name: Switch to light mode
|
||||
features:
|
||||
# - navigation.instant
|
||||
- navigation.tracking
|
||||
@@ -48,7 +44,6 @@ nav:
|
||||
- Migration: migration.md
|
||||
- Deprecated: deprecated.md
|
||||
- Support: support.md
|
||||
- Sponsors: sponsors.md
|
||||
- Installation:
|
||||
- Package Manager: installation/package-manager.md
|
||||
- Docker: installation/docker.md
|
||||
|
||||
+17
-2
@@ -64,7 +64,7 @@ func (r Rule) IsValid() bool {
|
||||
}
|
||||
}
|
||||
|
||||
type DefaultRule struct {
|
||||
type _DefaultRule struct {
|
||||
Inbound Listable[string] `json:"inbound,omitempty"`
|
||||
IPVersion int `json:"ip_version,omitempty"`
|
||||
Network Listable[string] `json:"network,omitempty"`
|
||||
@@ -88,7 +88,6 @@ type DefaultRule struct {
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
User Listable[string] `json:"user,omitempty"`
|
||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
||||
@@ -104,6 +103,22 @@ type DefaultRule struct {
|
||||
Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"`
|
||||
}
|
||||
|
||||
type DefaultRule _DefaultRule
|
||||
|
||||
func (r *DefaultRule) UnmarshalJSON(bytes []byte) error {
|
||||
err := json.Unmarshal(bytes, (*_DefaultRule)(r))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//nolint:staticcheck
|
||||
//goland:noinspection GoDeprecation
|
||||
if r.Deprecated_RulesetIPCIDRMatchSource {
|
||||
r.Deprecated_RulesetIPCIDRMatchSource = false
|
||||
r.RuleSetIPCIDRMatchSource = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *DefaultRule) IsValid() bool {
|
||||
var defaultValue DefaultRule
|
||||
defaultValue.Invert = r.Invert
|
||||
|
||||
+17
-2
@@ -64,7 +64,7 @@ func (r DNSRule) IsValid() bool {
|
||||
}
|
||||
}
|
||||
|
||||
type DefaultDNSRule struct {
|
||||
type _DefaultDNSRule struct {
|
||||
Inbound Listable[string] `json:"inbound,omitempty"`
|
||||
IPVersion int `json:"ip_version,omitempty"`
|
||||
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||
@@ -88,7 +88,6 @@ type DefaultDNSRule struct {
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
User Listable[string] `json:"user,omitempty"`
|
||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
||||
@@ -109,6 +108,22 @@ type DefaultDNSRule struct {
|
||||
Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"`
|
||||
}
|
||||
|
||||
type DefaultDNSRule _DefaultDNSRule
|
||||
|
||||
func (r *DefaultDNSRule) UnmarshalJSON(bytes []byte) error {
|
||||
err := json.UnmarshalDisallowUnknownFields(bytes, (*_DefaultDNSRule)(r))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//nolint:staticcheck
|
||||
//goland:noinspection GoDeprecation
|
||||
if r.Deprecated_RulesetIPCIDRMatchSource {
|
||||
r.Deprecated_RulesetIPCIDRMatchSource = false
|
||||
r.RuleSetIPCIDRMatchSource = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *DefaultDNSRule) IsValid() bool {
|
||||
var defaultValue DefaultDNSRule
|
||||
defaultValue.Invert = r.Invert
|
||||
|
||||
+29
-30
@@ -48,6 +48,17 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
|
||||
if r.Tag == "" {
|
||||
return E.New("missing tag")
|
||||
}
|
||||
if r.Type != C.RuleSetTypeInline {
|
||||
switch r.Format {
|
||||
case "":
|
||||
return E.New("missing format")
|
||||
case C.RuleSetFormatSource, C.RuleSetFormatBinary:
|
||||
default:
|
||||
return E.New("unknown rule-set format: " + r.Format)
|
||||
}
|
||||
} else {
|
||||
r.Format = ""
|
||||
}
|
||||
var v any
|
||||
switch r.Type {
|
||||
case "", C.RuleSetTypeInline:
|
||||
@@ -60,17 +71,6 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
|
||||
default:
|
||||
return E.New("unknown rule-set type: " + r.Type)
|
||||
}
|
||||
if r.Type != C.RuleSetTypeInline {
|
||||
switch r.Format {
|
||||
case "":
|
||||
return E.New("missing format")
|
||||
case C.RuleSetFormatSource, C.RuleSetFormatBinary:
|
||||
default:
|
||||
return E.New("unknown rule-set format: " + r.Format)
|
||||
}
|
||||
} else {
|
||||
r.Format = ""
|
||||
}
|
||||
err = UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -144,25 +144,24 @@ func (r HeadlessRule) IsValid() bool {
|
||||
}
|
||||
|
||||
type DefaultHeadlessRule struct {
|
||||
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||
Network Listable[string] `json:"network,omitempty"`
|
||||
Domain Listable[string] `json:"domain,omitempty"`
|
||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
||||
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
|
||||
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
|
||||
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
|
||||
SourcePort Listable[uint16] `json:"source_port,omitempty"`
|
||||
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
|
||||
Port Listable[uint16] `json:"port,omitempty"`
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||
Network Listable[string] `json:"network,omitempty"`
|
||||
Domain Listable[string] `json:"domain,omitempty"`
|
||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
||||
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
|
||||
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
|
||||
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
|
||||
SourcePort Listable[uint16] `json:"source_port,omitempty"`
|
||||
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
|
||||
Port Listable[uint16] `json:"port,omitempty"`
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
|
||||
DomainMatcher *domain.Matcher `json:"-"`
|
||||
SourceIPSet *netipx.IPSet `json:"-"`
|
||||
|
||||
@@ -11,6 +11,11 @@ import (
|
||||
)
|
||||
|
||||
func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Outbound) (adapter.Outbound, error) {
|
||||
var metadata *adapter.InboundContext
|
||||
if tag != "" {
|
||||
ctx, metadata = adapter.AppendContext(ctx)
|
||||
metadata.Outbound = tag
|
||||
}
|
||||
if options.Type == "" {
|
||||
return nil, E.New("missing outbound type")
|
||||
}
|
||||
|
||||
+2
-2
@@ -70,7 +70,7 @@ func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, opti
|
||||
}
|
||||
|
||||
func (h *Direct) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
switch h.overrideOption {
|
||||
@@ -98,7 +98,7 @@ func (h *Direct) DialContext(ctx context.Context, network string, destination M.
|
||||
}
|
||||
|
||||
func (h *Direct) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
switch h.overrideOption {
|
||||
|
||||
+3
-2
@@ -120,7 +120,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||
var group task.Group
|
||||
group.Append0(func(_ context.Context) error {
|
||||
group.Append0(func(ctx context.Context) error {
|
||||
for {
|
||||
var message mDNS.Msg
|
||||
var destination M.Socksaddr
|
||||
@@ -185,10 +185,11 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
||||
}
|
||||
|
||||
func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWaiter N.PacketReadWaiter, readCounters []N.CountFunc, cached []*N.PacketBuffer, metadata adapter.InboundContext) error {
|
||||
ctx = adapter.WithContext(ctx, &metadata)
|
||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||
var group task.Group
|
||||
group.Append0(func(_ context.Context) error {
|
||||
group.Append0(func(ctx context.Context) error {
|
||||
for {
|
||||
var (
|
||||
message mDNS.Msg
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||
}
|
||||
|
||||
func (h *HTTP) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||
|
||||
@@ -79,7 +79,7 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
|
||||
}
|
||||
|
||||
func (h *Shadowsocks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
if h.multiplexDialer == nil {
|
||||
@@ -107,7 +107,7 @@ func (h *Shadowsocks) DialContext(ctx context.Context, network string, destinati
|
||||
}
|
||||
|
||||
func (h *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
if h.multiplexDialer == nil {
|
||||
@@ -149,7 +149,7 @@ var _ N.Dialer = (*shadowsocksDialer)(nil)
|
||||
type shadowsocksDialer Shadowsocks
|
||||
|
||||
func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
switch N.NetworkName(network) {
|
||||
@@ -177,7 +177,7 @@ func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, des
|
||||
}
|
||||
|
||||
func (h *shadowsocksDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr)
|
||||
|
||||
@@ -92,7 +92,7 @@ func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.Context
|
||||
}
|
||||
|
||||
func (h *ShadowTLS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
switch N.NetworkName(network) {
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
|
||||
}
|
||||
|
||||
func (h *Socks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
switch N.NetworkName(network) {
|
||||
@@ -91,7 +91,7 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
|
||||
}
|
||||
|
||||
func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
if h.uotClient != nil {
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ func (h *Trojan) Close() error {
|
||||
type trojanDialer Trojan
|
||||
|
||||
func (h *trojanDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
var conn net.Conn
|
||||
|
||||
+2
-2
@@ -143,7 +143,7 @@ func (h *VLESS) Close() error {
|
||||
type vlessDialer VLESS
|
||||
|
||||
func (h *vlessDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
var conn net.Conn
|
||||
@@ -186,7 +186,7 @@ func (h *vlessDialer) DialContext(ctx context.Context, network string, destinati
|
||||
|
||||
func (h *vlessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
var conn net.Conn
|
||||
|
||||
+2
-2
@@ -157,7 +157,7 @@ func (h *VMess) NewPacketConnection(ctx context.Context, conn N.PacketConn, meta
|
||||
type vmessDialer VMess
|
||||
|
||||
func (h *vmessDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
var conn net.Conn
|
||||
@@ -185,7 +185,7 @@ func (h *vmessDialer) DialContext(ctx context.Context, network string, destinati
|
||||
}
|
||||
|
||||
func (h *vmessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
ctx, metadata := adapter.AppendContext(ctx)
|
||||
metadata.Outbound = h.tag
|
||||
metadata.Destination = destination
|
||||
var conn net.Conn
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,235 +0,0 @@
|
||||
# fish completion for sing-box -*- shell-script -*-
|
||||
|
||||
function __sing_box_debug
|
||||
set -l file "$BASH_COMP_DEBUG_FILE"
|
||||
if test -n "$file"
|
||||
echo "$argv" >> $file
|
||||
end
|
||||
end
|
||||
|
||||
function __sing_box_perform_completion
|
||||
__sing_box_debug "Starting __sing_box_perform_completion"
|
||||
|
||||
# Extract all args except the last one
|
||||
set -l args (commandline -opc)
|
||||
# Extract the last arg and escape it in case it is a space
|
||||
set -l lastArg (string escape -- (commandline -ct))
|
||||
|
||||
__sing_box_debug "args: $args"
|
||||
__sing_box_debug "last arg: $lastArg"
|
||||
|
||||
# Disable ActiveHelp which is not supported for fish shell
|
||||
set -l requestComp "SING_BOX_ACTIVE_HELP=0 $args[1] __complete $args[2..-1] $lastArg"
|
||||
|
||||
__sing_box_debug "Calling $requestComp"
|
||||
set -l results (eval $requestComp 2> /dev/null)
|
||||
|
||||
# Some programs may output extra empty lines after the directive.
|
||||
# Let's ignore them or else it will break completion.
|
||||
# Ref: https://github.com/spf13/cobra/issues/1279
|
||||
for line in $results[-1..1]
|
||||
if test (string trim -- $line) = ""
|
||||
# Found an empty line, remove it
|
||||
set results $results[1..-2]
|
||||
else
|
||||
# Found non-empty line, we have our proper output
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
set -l comps $results[1..-2]
|
||||
set -l directiveLine $results[-1]
|
||||
|
||||
# For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
|
||||
# completions must be prefixed with the flag
|
||||
set -l flagPrefix (string match -r -- '-.*=' "$lastArg")
|
||||
|
||||
__sing_box_debug "Comps: $comps"
|
||||
__sing_box_debug "DirectiveLine: $directiveLine"
|
||||
__sing_box_debug "flagPrefix: $flagPrefix"
|
||||
|
||||
for comp in $comps
|
||||
printf "%s%s\n" "$flagPrefix" "$comp"
|
||||
end
|
||||
|
||||
printf "%s\n" "$directiveLine"
|
||||
end
|
||||
|
||||
# this function limits calls to __sing_box_perform_completion, by caching the result behind $__sing_box_perform_completion_once_result
|
||||
function __sing_box_perform_completion_once
|
||||
__sing_box_debug "Starting __sing_box_perform_completion_once"
|
||||
|
||||
if test -n "$__sing_box_perform_completion_once_result"
|
||||
__sing_box_debug "Seems like a valid result already exists, skipping __sing_box_perform_completion"
|
||||
return 0
|
||||
end
|
||||
|
||||
set --global __sing_box_perform_completion_once_result (__sing_box_perform_completion)
|
||||
if test -z "$__sing_box_perform_completion_once_result"
|
||||
__sing_box_debug "No completions, probably due to a failure"
|
||||
return 1
|
||||
end
|
||||
|
||||
__sing_box_debug "Performed completions and set __sing_box_perform_completion_once_result"
|
||||
return 0
|
||||
end
|
||||
|
||||
# this function is used to clear the $__sing_box_perform_completion_once_result variable after completions are run
|
||||
function __sing_box_clear_perform_completion_once_result
|
||||
__sing_box_debug ""
|
||||
__sing_box_debug "========= clearing previously set __sing_box_perform_completion_once_result variable =========="
|
||||
set --erase __sing_box_perform_completion_once_result
|
||||
__sing_box_debug "Successfully erased the variable __sing_box_perform_completion_once_result"
|
||||
end
|
||||
|
||||
function __sing_box_requires_order_preservation
|
||||
__sing_box_debug ""
|
||||
__sing_box_debug "========= checking if order preservation is required =========="
|
||||
|
||||
__sing_box_perform_completion_once
|
||||
if test -z "$__sing_box_perform_completion_once_result"
|
||||
__sing_box_debug "Error determining if order preservation is required"
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l directive (string sub --start 2 $__sing_box_perform_completion_once_result[-1])
|
||||
__sing_box_debug "Directive is: $directive"
|
||||
|
||||
set -l shellCompDirectiveKeepOrder 32
|
||||
set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) % 2)
|
||||
__sing_box_debug "Keeporder is: $keeporder"
|
||||
|
||||
if test $keeporder -ne 0
|
||||
__sing_box_debug "This does require order preservation"
|
||||
return 0
|
||||
end
|
||||
|
||||
__sing_box_debug "This doesn't require order preservation"
|
||||
return 1
|
||||
end
|
||||
|
||||
|
||||
# This function does two things:
|
||||
# - Obtain the completions and store them in the global __sing_box_comp_results
|
||||
# - Return false if file completion should be performed
|
||||
function __sing_box_prepare_completions
|
||||
__sing_box_debug ""
|
||||
__sing_box_debug "========= starting completion logic =========="
|
||||
|
||||
# Start fresh
|
||||
set --erase __sing_box_comp_results
|
||||
|
||||
__sing_box_perform_completion_once
|
||||
__sing_box_debug "Completion results: $__sing_box_perform_completion_once_result"
|
||||
|
||||
if test -z "$__sing_box_perform_completion_once_result"
|
||||
__sing_box_debug "No completion, probably due to a failure"
|
||||
# Might as well do file completion, in case it helps
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l directive (string sub --start 2 $__sing_box_perform_completion_once_result[-1])
|
||||
set --global __sing_box_comp_results $__sing_box_perform_completion_once_result[1..-2]
|
||||
|
||||
__sing_box_debug "Completions are: $__sing_box_comp_results"
|
||||
__sing_box_debug "Directive is: $directive"
|
||||
|
||||
set -l shellCompDirectiveError 1
|
||||
set -l shellCompDirectiveNoSpace 2
|
||||
set -l shellCompDirectiveNoFileComp 4
|
||||
set -l shellCompDirectiveFilterFileExt 8
|
||||
set -l shellCompDirectiveFilterDirs 16
|
||||
|
||||
if test -z "$directive"
|
||||
set directive 0
|
||||
end
|
||||
|
||||
set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2)
|
||||
if test $compErr -eq 1
|
||||
__sing_box_debug "Received error directive: aborting."
|
||||
# Might as well do file completion, in case it helps
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2)
|
||||
set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2)
|
||||
if test $filefilter -eq 1; or test $dirfilter -eq 1
|
||||
__sing_box_debug "File extension filtering or directory filtering not supported"
|
||||
# Do full file completion instead
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2)
|
||||
set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2)
|
||||
|
||||
__sing_box_debug "nospace: $nospace, nofiles: $nofiles"
|
||||
|
||||
# If we want to prevent a space, or if file completion is NOT disabled,
|
||||
# we need to count the number of valid completions.
|
||||
# To do so, we will filter on prefix as the completions we have received
|
||||
# may not already be filtered so as to allow fish to match on different
|
||||
# criteria than the prefix.
|
||||
if test $nospace -ne 0; or test $nofiles -eq 0
|
||||
set -l prefix (commandline -t | string escape --style=regex)
|
||||
__sing_box_debug "prefix: $prefix"
|
||||
|
||||
set -l completions (string match -r -- "^$prefix.*" $__sing_box_comp_results)
|
||||
set --global __sing_box_comp_results $completions
|
||||
__sing_box_debug "Filtered completions are: $__sing_box_comp_results"
|
||||
|
||||
# Important not to quote the variable for count to work
|
||||
set -l numComps (count $__sing_box_comp_results)
|
||||
__sing_box_debug "numComps: $numComps"
|
||||
|
||||
if test $numComps -eq 1; and test $nospace -ne 0
|
||||
# We must first split on \t to get rid of the descriptions to be
|
||||
# able to check what the actual completion will be.
|
||||
# We don't need descriptions anyway since there is only a single
|
||||
# real completion which the shell will expand immediately.
|
||||
set -l split (string split --max 1 \t $__sing_box_comp_results[1])
|
||||
|
||||
# Fish won't add a space if the completion ends with any
|
||||
# of the following characters: @=/:.,
|
||||
set -l lastChar (string sub -s -1 -- $split)
|
||||
if not string match -r -q "[@=/:.,]" -- "$lastChar"
|
||||
# In other cases, to support the "nospace" directive we trick the shell
|
||||
# by outputting an extra, longer completion.
|
||||
__sing_box_debug "Adding second completion to perform nospace directive"
|
||||
set --global __sing_box_comp_results $split[1] $split[1].
|
||||
__sing_box_debug "Completions are now: $__sing_box_comp_results"
|
||||
end
|
||||
end
|
||||
|
||||
if test $numComps -eq 0; and test $nofiles -eq 0
|
||||
# To be consistent with bash and zsh, we only trigger file
|
||||
# completion when there are no other completions
|
||||
__sing_box_debug "Requesting file completion"
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves
|
||||
# so we can properly delete any completions provided by another script.
|
||||
# Only do this if the program can be found, or else fish may print some errors; besides,
|
||||
# the existing completions will only be loaded if the program can be found.
|
||||
if type -q "sing-box"
|
||||
# The space after the program name is essential to trigger completion for the program
|
||||
# and not completion of the program name itself.
|
||||
# Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish.
|
||||
complete --do-complete "sing-box " > /dev/null 2>&1
|
||||
end
|
||||
|
||||
# Remove any pre-existing completions for the program since we will be handling all of them.
|
||||
complete -c sing-box -e
|
||||
|
||||
# this will get called after the two calls below and clear the $__sing_box_perform_completion_once_result global
|
||||
complete -c sing-box -n '__sing_box_clear_perform_completion_once_result'
|
||||
# The call to __sing_box_prepare_completions will setup __sing_box_comp_results
|
||||
# which provides the program's completion choices.
|
||||
# If this doesn't require order preservation, we don't use the -k flag
|
||||
complete -c sing-box -n 'not __sing_box_requires_order_preservation && __sing_box_prepare_completions' -f -a '$__sing_box_comp_results'
|
||||
# otherwise we use the -k flag
|
||||
complete -k -c sing-box -n '__sing_box_requires_order_preservation && __sing_box_prepare_completions' -f -a '$__sing_box_comp_results'
|
||||
@@ -1,212 +0,0 @@
|
||||
#compdef sing-box
|
||||
compdef _sing-box sing-box
|
||||
|
||||
# zsh completion for sing-box -*- shell-script -*-
|
||||
|
||||
__sing-box_debug()
|
||||
{
|
||||
local file="$BASH_COMP_DEBUG_FILE"
|
||||
if [[ -n ${file} ]]; then
|
||||
echo "$*" >> "${file}"
|
||||
fi
|
||||
}
|
||||
|
||||
_sing-box()
|
||||
{
|
||||
local shellCompDirectiveError=1
|
||||
local shellCompDirectiveNoSpace=2
|
||||
local shellCompDirectiveNoFileComp=4
|
||||
local shellCompDirectiveFilterFileExt=8
|
||||
local shellCompDirectiveFilterDirs=16
|
||||
local shellCompDirectiveKeepOrder=32
|
||||
|
||||
local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder
|
||||
local -a completions
|
||||
|
||||
__sing-box_debug "\n========= starting completion logic =========="
|
||||
__sing-box_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}"
|
||||
|
||||
# The user could have moved the cursor backwards on the command-line.
|
||||
# We need to trigger completion from the $CURRENT location, so we need
|
||||
# to truncate the command-line ($words) up to the $CURRENT location.
|
||||
# (We cannot use $CURSOR as its value does not work when a command is an alias.)
|
||||
words=("${=words[1,CURRENT]}")
|
||||
__sing-box_debug "Truncated words[*]: ${words[*]},"
|
||||
|
||||
lastParam=${words[-1]}
|
||||
lastChar=${lastParam[-1]}
|
||||
__sing-box_debug "lastParam: ${lastParam}, lastChar: ${lastChar}"
|
||||
|
||||
# For zsh, when completing a flag with an = (e.g., sing-box -n=<TAB>)
|
||||
# completions must be prefixed with the flag
|
||||
setopt local_options BASH_REMATCH
|
||||
if [[ "${lastParam}" =~ '-.*=' ]]; then
|
||||
# We are dealing with a flag with an =
|
||||
flagPrefix="-P ${BASH_REMATCH}"
|
||||
fi
|
||||
|
||||
# Prepare the command to obtain completions
|
||||
requestComp="${words[1]} __complete ${words[2,-1]}"
|
||||
if [ "${lastChar}" = "" ]; then
|
||||
# If the last parameter is complete (there is a space following it)
|
||||
# We add an extra empty parameter so we can indicate this to the go completion code.
|
||||
__sing-box_debug "Adding extra empty parameter"
|
||||
requestComp="${requestComp} \"\""
|
||||
fi
|
||||
|
||||
__sing-box_debug "About to call: eval ${requestComp}"
|
||||
|
||||
# Use eval to handle any environment variables and such
|
||||
out=$(eval ${requestComp} 2>/dev/null)
|
||||
__sing-box_debug "completion output: ${out}"
|
||||
|
||||
# Extract the directive integer following a : from the last line
|
||||
local lastLine
|
||||
while IFS='\n' read -r line; do
|
||||
lastLine=${line}
|
||||
done < <(printf "%s\n" "${out[@]}")
|
||||
__sing-box_debug "last line: ${lastLine}"
|
||||
|
||||
if [ "${lastLine[1]}" = : ]; then
|
||||
directive=${lastLine[2,-1]}
|
||||
# Remove the directive including the : and the newline
|
||||
local suffix
|
||||
(( suffix=${#lastLine}+2))
|
||||
out=${out[1,-$suffix]}
|
||||
else
|
||||
# There is no directive specified. Leave $out as is.
|
||||
__sing-box_debug "No directive found. Setting do default"
|
||||
directive=0
|
||||
fi
|
||||
|
||||
__sing-box_debug "directive: ${directive}"
|
||||
__sing-box_debug "completions: ${out}"
|
||||
__sing-box_debug "flagPrefix: ${flagPrefix}"
|
||||
|
||||
if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then
|
||||
__sing-box_debug "Completion received error. Ignoring completions."
|
||||
return
|
||||
fi
|
||||
|
||||
local activeHelpMarker="_activeHelp_ "
|
||||
local endIndex=${#activeHelpMarker}
|
||||
local startIndex=$((${#activeHelpMarker}+1))
|
||||
local hasActiveHelp=0
|
||||
while IFS='\n' read -r comp; do
|
||||
# Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
|
||||
if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
|
||||
__sing-box_debug "ActiveHelp found: $comp"
|
||||
comp="${comp[$startIndex,-1]}"
|
||||
if [ -n "$comp" ]; then
|
||||
compadd -x "${comp}"
|
||||
__sing-box_debug "ActiveHelp will need delimiter"
|
||||
hasActiveHelp=1
|
||||
fi
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -n "$comp" ]; then
|
||||
# If requested, completions are returned with a description.
|
||||
# The description is preceded by a TAB character.
|
||||
# For zsh's _describe, we need to use a : instead of a TAB.
|
||||
# We first need to escape any : as part of the completion itself.
|
||||
comp=${comp//:/\\:}
|
||||
|
||||
local tab="$(printf '\t')"
|
||||
comp=${comp//$tab/:}
|
||||
|
||||
__sing-box_debug "Adding completion: ${comp}"
|
||||
completions+=${comp}
|
||||
lastComp=$comp
|
||||
fi
|
||||
done < <(printf "%s\n" "${out[@]}")
|
||||
|
||||
# Add a delimiter after the activeHelp statements, but only if:
|
||||
# - there are completions following the activeHelp statements, or
|
||||
# - file completion will be performed (so there will be choices after the activeHelp)
|
||||
if [ $hasActiveHelp -eq 1 ]; then
|
||||
if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
|
||||
__sing-box_debug "Adding activeHelp delimiter"
|
||||
compadd -x "--"
|
||||
hasActiveHelp=0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
|
||||
__sing-box_debug "Activating nospace."
|
||||
noSpace="-S ''"
|
||||
fi
|
||||
|
||||
if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then
|
||||
__sing-box_debug "Activating keep order."
|
||||
keepOrder="-V"
|
||||
fi
|
||||
|
||||
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
|
||||
# File extension filtering
|
||||
local filteringCmd
|
||||
filteringCmd='_files'
|
||||
for filter in ${completions[@]}; do
|
||||
if [ ${filter[1]} != '*' ]; then
|
||||
# zsh requires a glob pattern to do file filtering
|
||||
filter="\*.$filter"
|
||||
fi
|
||||
filteringCmd+=" -g $filter"
|
||||
done
|
||||
filteringCmd+=" ${flagPrefix}"
|
||||
|
||||
__sing-box_debug "File filtering command: $filteringCmd"
|
||||
_arguments '*:filename:'"$filteringCmd"
|
||||
elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
|
||||
# File completion for directories only
|
||||
local subdir
|
||||
subdir="${completions[1]}"
|
||||
if [ -n "$subdir" ]; then
|
||||
__sing-box_debug "Listing directories in $subdir"
|
||||
pushd "${subdir}" >/dev/null 2>&1
|
||||
else
|
||||
__sing-box_debug "Listing directories in ."
|
||||
fi
|
||||
|
||||
local result
|
||||
_arguments '*:dirname:_files -/'" ${flagPrefix}"
|
||||
result=$?
|
||||
if [ -n "$subdir" ]; then
|
||||
popd >/dev/null 2>&1
|
||||
fi
|
||||
return $result
|
||||
else
|
||||
__sing-box_debug "Calling _describe"
|
||||
if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then
|
||||
__sing-box_debug "_describe found some completions"
|
||||
|
||||
# Return the success of having called _describe
|
||||
return 0
|
||||
else
|
||||
__sing-box_debug "_describe did not find completions."
|
||||
__sing-box_debug "Checking if we should do file completion."
|
||||
if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then
|
||||
__sing-box_debug "deactivating file completion"
|
||||
|
||||
# We must return an error code here to let zsh know that there were no
|
||||
# completions found by _describe; this is what will trigger other
|
||||
# matching algorithms to attempt to find completions.
|
||||
# For example zsh can match letters in the middle of words.
|
||||
return 1
|
||||
else
|
||||
# Perform file completion
|
||||
__sing-box_debug "Activating file completion"
|
||||
|
||||
# We must return the result of this command, so it must be the
|
||||
# last command, or else we must store its result to return it.
|
||||
_arguments '*:filename:_files'" ${flagPrefix}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# don't run the completion function when being source-ed or eval-ed
|
||||
if [ "$funcstack[1]" = "_sing-box" ]; then
|
||||
_sing-box
|
||||
fi
|
||||
@@ -1,5 +0,0 @@
|
||||
config sing-box 'main'
|
||||
option enabled '1'
|
||||
option conffile '/etc/sing-box/config.json'
|
||||
option workdir '/usr/share/sing-box'
|
||||
option log_stderr '1'
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
PROG="/usr/bin/sing-box"
|
||||
|
||||
start_service() {
|
||||
config_load "sing-box"
|
||||
|
||||
local enabled config_file working_directory
|
||||
local log_stdout log_stderr
|
||||
config_get_bool enabled "main" "enabled" "0"
|
||||
[ "$enabled" -eq "1" ] || return 0
|
||||
|
||||
config_get config_file "main" "conffile" "/etc/sing-box/config.json"
|
||||
config_get working_directory "main" "workdir" "/usr/share/sing-box"
|
||||
config_get_bool log_stdout "main" "log_stdout" "1"
|
||||
config_get_bool log_stderr "main" "log_stderr" "1"
|
||||
|
||||
procd_open_instance
|
||||
procd_swet_param command "$PROG" run -c "$conffile" -D "$workdir"
|
||||
procd_set_param file "$conffile"
|
||||
procd_set_param stderr "$log_stderr"
|
||||
procd_set_param limits core="unlimited"
|
||||
sprocd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param respawn
|
||||
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "sing-box"
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/sbin/openrc-run
|
||||
|
||||
name=$RC_SVCNAME
|
||||
description="sing-box service"
|
||||
supervisor="supervise-daemon"
|
||||
command="/usr/bin/sing-box"
|
||||
command_args="-D /var/lib/sing-box -C /etc/sing-box run"
|
||||
extra_started_commands="reload"
|
||||
|
||||
depend() {
|
||||
after net dns
|
||||
}
|
||||
|
||||
reload() {
|
||||
ebegin "Reloading $RC_SVCNAME"
|
||||
$supervisor "$RC_SVCNAME" --signal HUP
|
||||
eend $?
|
||||
}
|
||||
+10
-12
@@ -153,14 +153,14 @@ func NewRouter(
|
||||
Logger: router.dnsLogger,
|
||||
})
|
||||
for i, ruleOptions := range options.Rules {
|
||||
routeRule, err := NewRule(ctx, router, router.logger, ruleOptions, true)
|
||||
routeRule, err := NewRule(router, router.logger, ruleOptions, true)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "parse rule[", i, "]")
|
||||
}
|
||||
router.rules = append(router.rules, routeRule)
|
||||
}
|
||||
for i, dnsRuleOptions := range dnsOptions.Rules {
|
||||
dnsRule, err := NewDNSRule(ctx, router, router.logger, dnsRuleOptions, true)
|
||||
dnsRule, err := NewDNSRule(router, router.logger, dnsRuleOptions, true)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "parse dns rule[", i, "]")
|
||||
}
|
||||
@@ -338,7 +338,6 @@ func NewRouter(
|
||||
_ = router.interfaceFinder.Update()
|
||||
})
|
||||
interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, router.logger, tun.DefaultInterfaceMonitorOptions{
|
||||
InterfaceFinder: router.interfaceFinder,
|
||||
OverrideAndroidVPN: options.OverrideAndroidVPN,
|
||||
UnderNetworkExtension: platformInterface != nil && platformInterface.UnderNetworkExtension(),
|
||||
})
|
||||
@@ -659,15 +658,14 @@ func (r *Router) Close() error {
|
||||
|
||||
func (r *Router) PostStart() error {
|
||||
monitor := taskmonitor.New(r.logger, C.StopTimeout)
|
||||
var cacheContext *adapter.HTTPStartContext
|
||||
if len(r.ruleSets) > 0 {
|
||||
monitor.Start("initialize rule-set")
|
||||
cacheContext = adapter.NewHTTPStartContext()
|
||||
ruleSetStartContext := NewRuleSetStartContext()
|
||||
var ruleSetStartGroup task.Group
|
||||
for i, ruleSet := range r.ruleSets {
|
||||
ruleSetInPlace := ruleSet
|
||||
ruleSetStartGroup.Append0(func(ctx context.Context) error {
|
||||
err := ruleSetInPlace.StartContext(ctx, cacheContext)
|
||||
err := ruleSetInPlace.StartContext(ctx, ruleSetStartContext)
|
||||
if err != nil {
|
||||
return E.Cause(err, "initialize rule-set[", i, "]")
|
||||
}
|
||||
@@ -681,9 +679,7 @@ func (r *Router) PostStart() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if cacheContext != nil {
|
||||
cacheContext.Close()
|
||||
ruleSetStartContext.Close()
|
||||
}
|
||||
needFindProcess := r.needFindProcess
|
||||
needWIFIState := r.needWIFIState
|
||||
@@ -1025,14 +1021,16 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
)
|
||||
} else {
|
||||
err = sniff.PeekPacket(
|
||||
ctx, &metadata,
|
||||
ctx,
|
||||
&metadata,
|
||||
buffer.Bytes(),
|
||||
sniff.DomainNameQuery,
|
||||
sniff.QUICClientHello,
|
||||
sniff.STUNMessage,
|
||||
sniff.UTP,
|
||||
sniff.UDPTracker,
|
||||
sniff.DTLSRecord)
|
||||
sniff.DTLSRecord,
|
||||
)
|
||||
}
|
||||
if E.IsMulti(err, sniff.ErrClientHelloFragmented) && len(bufferList) == 0 {
|
||||
bufferList = append(bufferList, buffer)
|
||||
@@ -1057,8 +1055,8 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
}
|
||||
}
|
||||
}
|
||||
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
|
||||
}
|
||||
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
|
||||
for _, cachedBuffer := range common.Reverse(bufferList) {
|
||||
conn = bufio.NewCachedPacketConn(conn, cachedBuffer, destination)
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/geoip"
|
||||
"github.com/sagernet/sing-box/common/geosite"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
"github.com/sagernet/sing/common/rw"
|
||||
@@ -32,7 +32,7 @@ func (r *Router) LoadGeosite(code string) (adapter.Rule, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule, err = NewDefaultRule(r.ctx, r, nil, geosite.Compile(items))
|
||||
rule, err = NewDefaultRule(r, nil, geosite.Compile(items))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -41,7 +41,6 @@ func (r *Router) LoadGeosite(code string) (adapter.Rule, error) {
|
||||
}
|
||||
|
||||
func (r *Router) prepareGeoIPDatabase() error {
|
||||
deprecated.Report(r.ctx, deprecated.OptionGEOIP)
|
||||
var geoPath string
|
||||
if r.geoIPOptions.Path != "" {
|
||||
geoPath = r.geoIPOptions.Path
|
||||
@@ -88,7 +87,6 @@ func (r *Router) prepareGeoIPDatabase() error {
|
||||
}
|
||||
|
||||
func (r *Router) prepareGeositeDatabase() error {
|
||||
deprecated.Report(r.ctx, deprecated.OptionGEOSITE)
|
||||
var geoPath string
|
||||
if r.geositeOptions.Path != "" {
|
||||
geoPath = r.geositeOptions.Path
|
||||
@@ -160,7 +158,7 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
ForceAttemptHTTP2: true,
|
||||
TLSHandshakeTimeout: C.TCPTimeout,
|
||||
TLSHandshakeTimeout: 5 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||||
},
|
||||
@@ -215,7 +213,7 @@ func (r *Router) downloadGeositeDatabase(savePath string) error {
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
ForceAttemptHTTP2: true,
|
||||
TLSHandshakeTimeout: C.TCPTimeout,
|
||||
TLSHandshakeTimeout: 5 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||||
},
|
||||
|
||||
+7
-27
@@ -1,17 +1,14 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func NewRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.Rule, checkOutbound bool) (adapter.Rule, error) {
|
||||
func NewRule(router adapter.Router, logger log.ContextLogger, options option.Rule, checkOutbound bool) (adapter.Rule, error) {
|
||||
switch options.Type {
|
||||
case "", C.RuleTypeDefault:
|
||||
if !options.DefaultOptions.IsValid() {
|
||||
@@ -20,7 +17,7 @@ func NewRule(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||
if options.DefaultOptions.Outbound == "" && checkOutbound {
|
||||
return nil, E.New("missing outbound field")
|
||||
}
|
||||
return NewDefaultRule(ctx, router, logger, options.DefaultOptions)
|
||||
return NewDefaultRule(router, logger, options.DefaultOptions)
|
||||
case C.RuleTypeLogical:
|
||||
if !options.LogicalOptions.IsValid() {
|
||||
return nil, E.New("missing conditions")
|
||||
@@ -28,7 +25,7 @@ func NewRule(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||
if options.LogicalOptions.Outbound == "" && checkOutbound {
|
||||
return nil, E.New("missing outbound field")
|
||||
}
|
||||
return NewLogicalRule(ctx, router, logger, options.LogicalOptions)
|
||||
return NewLogicalRule(router, logger, options.LogicalOptions)
|
||||
default:
|
||||
return nil, E.New("unknown rule type: ", options.Type)
|
||||
}
|
||||
@@ -45,7 +42,7 @@ type RuleItem interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
func NewDefaultRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.DefaultRule) (*DefaultRule, error) {
|
||||
func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options option.DefaultRule) (*DefaultRule, error) {
|
||||
rule := &DefaultRule{
|
||||
abstractDefaultRule{
|
||||
invert: options.Invert,
|
||||
@@ -182,14 +179,6 @@ func NewDefaultRule(ctx context.Context, router adapter.Router, logger log.Conte
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.ProcessPathRegex) > 0 {
|
||||
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "process_path_regex")
|
||||
}
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.PackageName) > 0 {
|
||||
item := NewPackageNameItem(options.PackageName)
|
||||
rule.items = append(rule.items, item)
|
||||
@@ -221,16 +210,7 @@ func NewDefaultRule(ctx context.Context, router adapter.Router, logger log.Conte
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.RuleSet) > 0 {
|
||||
var matchSource bool
|
||||
if options.RuleSetIPCIDRMatchSource {
|
||||
matchSource = true
|
||||
} else
|
||||
//nolint:staticcheck
|
||||
if options.Deprecated_RulesetIPCIDRMatchSource {
|
||||
matchSource = true
|
||||
deprecated.Report(ctx, deprecated.OptionBadMatchSource)
|
||||
}
|
||||
item := NewRuleSetItem(router, options.RuleSet, matchSource, false)
|
||||
item := NewRuleSetItem(router, options.RuleSet, options.RuleSetIPCIDRMatchSource, false)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
@@ -243,7 +223,7 @@ type LogicalRule struct {
|
||||
abstractLogicalRule
|
||||
}
|
||||
|
||||
func NewLogicalRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.LogicalRule) (*LogicalRule, error) {
|
||||
func NewLogicalRule(router adapter.Router, logger log.ContextLogger, options option.LogicalRule) (*LogicalRule, error) {
|
||||
r := &LogicalRule{
|
||||
abstractLogicalRule{
|
||||
rules: make([]adapter.HeadlessRule, len(options.Rules)),
|
||||
@@ -260,7 +240,7 @@ func NewLogicalRule(ctx context.Context, router adapter.Router, logger log.Conte
|
||||
return nil, E.New("unknown logical mode: ", options.Mode)
|
||||
}
|
||||
for i, subRule := range options.Rules {
|
||||
rule, err := NewRule(ctx, router, logger, subRule, false)
|
||||
rule, err := NewRule(router, logger, subRule, false)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "sub rule[", i, "]")
|
||||
}
|
||||
|
||||
+7
-26
@@ -1,19 +1,17 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func NewDNSRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.DNSRule, checkServer bool) (adapter.DNSRule, error) {
|
||||
func NewDNSRule(router adapter.Router, logger log.ContextLogger, options option.DNSRule, checkServer bool) (adapter.DNSRule, error) {
|
||||
switch options.Type {
|
||||
case "", C.RuleTypeDefault:
|
||||
if !options.DefaultOptions.IsValid() {
|
||||
@@ -22,7 +20,7 @@ func NewDNSRule(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
if options.DefaultOptions.Server == "" && checkServer {
|
||||
return nil, E.New("missing server field")
|
||||
}
|
||||
return NewDefaultDNSRule(ctx, router, logger, options.DefaultOptions)
|
||||
return NewDefaultDNSRule(router, logger, options.DefaultOptions)
|
||||
case C.RuleTypeLogical:
|
||||
if !options.LogicalOptions.IsValid() {
|
||||
return nil, E.New("missing conditions")
|
||||
@@ -30,7 +28,7 @@ func NewDNSRule(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
if options.LogicalOptions.Server == "" && checkServer {
|
||||
return nil, E.New("missing server field")
|
||||
}
|
||||
return NewLogicalDNSRule(ctx, router, logger, options.LogicalOptions)
|
||||
return NewLogicalDNSRule(router, logger, options.LogicalOptions)
|
||||
default:
|
||||
return nil, E.New("unknown rule type: ", options.Type)
|
||||
}
|
||||
@@ -45,7 +43,7 @@ type DefaultDNSRule struct {
|
||||
clientSubnet *netip.Prefix
|
||||
}
|
||||
|
||||
func NewDefaultDNSRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) {
|
||||
func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) {
|
||||
rule := &DefaultDNSRule{
|
||||
abstractDefaultRule: abstractDefaultRule{
|
||||
invert: options.Invert,
|
||||
@@ -185,14 +183,6 @@ func NewDefaultDNSRule(ctx context.Context, router adapter.Router, logger log.Co
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.ProcessPathRegex) > 0 {
|
||||
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "process_path_regex")
|
||||
}
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.PackageName) > 0 {
|
||||
item := NewPackageNameItem(options.PackageName)
|
||||
rule.items = append(rule.items, item)
|
||||
@@ -229,16 +219,7 @@ func NewDefaultDNSRule(ctx context.Context, router adapter.Router, logger log.Co
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.RuleSet) > 0 {
|
||||
var matchSource bool
|
||||
if options.RuleSetIPCIDRMatchSource {
|
||||
matchSource = true
|
||||
} else
|
||||
//nolint:staticcheck
|
||||
if options.Deprecated_RulesetIPCIDRMatchSource {
|
||||
matchSource = true
|
||||
deprecated.Report(ctx, deprecated.OptionBadMatchSource)
|
||||
}
|
||||
item := NewRuleSetItem(router, options.RuleSet, matchSource, options.RuleSetIPCIDRAcceptEmpty)
|
||||
item := NewRuleSetItem(router, options.RuleSet, options.RuleSetIPCIDRMatchSource, options.RuleSetIPCIDRAcceptEmpty)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
@@ -294,7 +275,7 @@ type LogicalDNSRule struct {
|
||||
clientSubnet *netip.Prefix
|
||||
}
|
||||
|
||||
func NewLogicalDNSRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.LogicalDNSRule) (*LogicalDNSRule, error) {
|
||||
func NewLogicalDNSRule(router adapter.Router, logger log.ContextLogger, options option.LogicalDNSRule) (*LogicalDNSRule, error) {
|
||||
r := &LogicalDNSRule{
|
||||
abstractLogicalRule: abstractLogicalRule{
|
||||
rules: make([]adapter.HeadlessRule, len(options.Rules)),
|
||||
@@ -314,7 +295,7 @@ func NewLogicalDNSRule(ctx context.Context, router adapter.Router, logger log.Co
|
||||
return nil, E.New("unknown logical mode: ", options.Mode)
|
||||
}
|
||||
for i, subRule := range options.Rules {
|
||||
rule, err := NewDNSRule(ctx, router, logger, subRule, false)
|
||||
rule, err := NewDNSRule(router, logger, subRule, false)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "sub rule[", i, "]")
|
||||
}
|
||||
|
||||
@@ -123,14 +123,6 @@ func NewDefaultHeadlessRule(router adapter.Router, options option.DefaultHeadles
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.ProcessPathRegex) > 0 {
|
||||
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "process_path_regex")
|
||||
}
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.PackageName) > 0 {
|
||||
item := NewPackageNameItem(options.PackageName)
|
||||
rule.items = append(rule.items, item)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user