Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a06d10c3bc | ||
|
|
63cc6cc76c | ||
|
|
d55c5b5cab | ||
|
|
b624c2dcc7 | ||
|
|
9415444ebd | ||
|
|
95606191d8 | ||
|
|
e586d9e9bc | ||
|
|
8c7eaa4477 | ||
|
|
8464c8cb7c | ||
|
|
39d7127651 | ||
|
|
e2077009c4 | ||
|
|
700a8eb425 | ||
|
|
3b0cba0852 | ||
|
|
f5554dd8b8 | ||
|
|
4d0362d530 | ||
|
|
97ccd2ca04 | ||
|
|
1ed6654ad4 | ||
|
|
5385f75f53 | ||
|
|
ad97d4e11f | ||
|
|
09d4e91b77 | ||
|
|
3dbdda9555 | ||
|
|
1f4ed6ff8f | ||
|
|
6ddbe19bc0 | ||
|
|
d7205ecc60 | ||
|
|
9e243e0ff9 | ||
|
|
02bc3e0a0a | ||
|
|
87be6dc235 | ||
|
|
c1c30976dc | ||
|
|
9bac18bcd1 | ||
|
|
ceda5cc95d | ||
|
|
27d6b63e71 | ||
|
|
b57abcc73c | ||
|
|
f1147965dd | ||
|
|
45f3234c73 | ||
|
|
aae3fded32 | ||
|
|
090494faf5 | ||
|
|
db5719e22f | ||
|
|
064fb9b873 | ||
|
|
f6a1e123fc |
121
.github/workflows/docker.yml
vendored
121
.github/workflows/docker.yml
vendored
@@ -1,16 +1,93 @@
|
|||||||
name: Build Docker Images
|
name: Publish Docker Images
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types:
|
types:
|
||||||
- released
|
- published
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
tag:
|
tag:
|
||||||
description: "The tag version you want to build"
|
description: "The tag version you want to build"
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY_IMAGE: ghcr.io/sagernet/sing-box
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- linux/amd64
|
||||||
|
- linux/arm/v6
|
||||||
|
- linux/arm/v7
|
||||||
|
- linux/arm64
|
||||||
|
- linux/386
|
||||||
|
- linux/ppc64le
|
||||||
|
- linux/riscv64
|
||||||
|
- linux/s390x
|
||||||
|
steps:
|
||||||
|
- 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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||||
|
with:
|
||||||
|
ref: ${{ steps.ref.outputs.ref }}
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
platform=${{ matrix.platform }}
|
||||||
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
|
- name: Setup QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Login to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
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
|
||||||
|
with:
|
||||||
|
platforms: ${{ matrix.platform }}
|
||||||
|
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: |
|
||||||
|
mkdir -p /tmp/digests
|
||||||
|
digest="${{ steps.build.outputs.digest }}"
|
||||||
|
touch "/tmp/digests/${digest#sha256:}"
|
||||||
|
- name: Upload digest
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: digests-${{ env.PLATFORM_PAIR }}
|
||||||
|
path: /tmp/digests/*
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
merge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
steps:
|
steps:
|
||||||
- name: Get commit to build
|
- name: Get commit to build
|
||||||
id: ref
|
id: ref
|
||||||
@@ -29,34 +106,28 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "latest=$latest"
|
echo "latest=$latest"
|
||||||
echo "latest=$latest" >> $GITHUB_OUTPUT
|
echo "latest=$latest" >> $GITHUB_OUTPUT
|
||||||
- name: Checkout
|
- name: Download digests
|
||||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ steps.ref.outputs.ref }}
|
path: /tmp/digests
|
||||||
- name: Setup Docker Buildx
|
pattern: digests-*
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Setup QEMU for Docker Buildx
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Docker metadata
|
- name: Create manifest list and push
|
||||||
id: metadata
|
working-directory: /tmp/digests
|
||||||
uses: docker/metadata-action@v5
|
run: |
|
||||||
with:
|
docker buildx imagetools create \
|
||||||
images: ghcr.io/sagernet/sing-box
|
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}" \
|
||||||
- name: Build and release Docker images
|
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}" \
|
||||||
uses: docker/build-push-action@v6
|
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
|
||||||
with:
|
- name: Inspect image
|
||||||
platforms: linux/386,linux/amd64,linux/arm64,linux/s390x
|
run: |
|
||||||
context: .
|
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}
|
||||||
target: dist
|
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}
|
||||||
build-args: |
|
|
||||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
|
||||||
tags: |
|
|
||||||
ghcr.io/sagernet/sing-box:${{ steps.ref.outputs.latest }}
|
|
||||||
ghcr.io/sagernet/sing-box:${{ steps.ref.outputs.ref }}
|
|
||||||
push: true
|
|
||||||
|
|||||||
3
.github/workflows/stale.yml
vendored
3
.github/workflows/stale.yml
vendored
@@ -12,4 +12,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
|
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
days-before-close: 5
|
days-before-close: 5
|
||||||
|
exempt-issue-labels: 'bug,enhancement'
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ builds:
|
|||||||
- linux_arm_7
|
- linux_arm_7
|
||||||
- linux_s390x
|
- linux_s390x
|
||||||
- linux_riscv64
|
- linux_riscv64
|
||||||
|
- linux_mips64le
|
||||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||||
snapshot:
|
snapshot:
|
||||||
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
||||||
@@ -48,10 +49,19 @@ nfpms:
|
|||||||
- src: release/config/config.json
|
- src: release/config/config.json
|
||||||
dst: /etc/sing-box/config.json
|
dst: /etc/sing-box/config.json
|
||||||
type: config
|
type: config
|
||||||
|
|
||||||
- src: release/config/sing-box.service
|
- src: release/config/sing-box.service
|
||||||
dst: /usr/lib/systemd/system/sing-box.service
|
dst: /usr/lib/systemd/system/sing-box.service
|
||||||
- src: release/config/sing-box@.service
|
- src: release/config/sing-box@.service
|
||||||
dst: /usr/lib/systemd/system/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
|
- src: LICENSE
|
||||||
dst: /usr/share/licenses/sing-box/LICENSE
|
dst: /usr/share/licenses/sing-box/LICENSE
|
||||||
deb:
|
deb:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
version: 2
|
||||||
project_name: sing-box
|
project_name: sing-box
|
||||||
builds:
|
builds:
|
||||||
- &template
|
- &template
|
||||||
@@ -7,7 +8,9 @@ builds:
|
|||||||
- -v
|
- -v
|
||||||
- -trimpath
|
- -trimpath
|
||||||
ldflags:
|
ldflags:
|
||||||
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid=
|
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }}
|
||||||
|
- -s
|
||||||
|
- -buildid=
|
||||||
tags:
|
tags:
|
||||||
- with_gvisor
|
- with_gvisor
|
||||||
- with_quic
|
- with_quic
|
||||||
@@ -23,13 +26,13 @@ builds:
|
|||||||
targets:
|
targets:
|
||||||
- linux_386
|
- linux_386
|
||||||
- linux_amd64_v1
|
- linux_amd64_v1
|
||||||
- linux_amd64_v3
|
|
||||||
- linux_arm64
|
- linux_arm64
|
||||||
|
- linux_arm_6
|
||||||
- linux_arm_7
|
- linux_arm_7
|
||||||
- linux_s390x
|
- linux_s390x
|
||||||
- linux_riscv64
|
- linux_riscv64
|
||||||
|
- linux_mips64le
|
||||||
- windows_amd64_v1
|
- windows_amd64_v1
|
||||||
- windows_amd64_v3
|
|
||||||
- windows_386
|
- windows_386
|
||||||
- windows_arm64
|
- windows_arm64
|
||||||
- darwin_amd64_v1
|
- darwin_amd64_v1
|
||||||
@@ -86,8 +89,6 @@ builds:
|
|||||||
- android_arm64
|
- android_arm64
|
||||||
- android_386
|
- android_386
|
||||||
- android_amd64
|
- android_amd64
|
||||||
snapshot:
|
|
||||||
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
|
||||||
archives:
|
archives:
|
||||||
- &template
|
- &template
|
||||||
id: archive
|
id: archive
|
||||||
@@ -101,7 +102,7 @@ archives:
|
|||||||
wrap_in_directory: true
|
wrap_in_directory: true
|
||||||
files:
|
files:
|
||||||
- LICENSE
|
- LICENSE
|
||||||
name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
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 }}'
|
||||||
- id: archive-legacy
|
- id: archive-legacy
|
||||||
<<: *template
|
<<: *template
|
||||||
builds:
|
builds:
|
||||||
@@ -110,7 +111,7 @@ archives:
|
|||||||
nfpms:
|
nfpms:
|
||||||
- id: package
|
- id: package
|
||||||
package_name: sing-box
|
package_name: sing-box
|
||||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
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 }}'
|
||||||
builds:
|
builds:
|
||||||
- main
|
- main
|
||||||
homepage: https://sing-box.sagernet.org/
|
homepage: https://sing-box.sagernet.org/
|
||||||
@@ -121,15 +122,26 @@ nfpms:
|
|||||||
- deb
|
- deb
|
||||||
- rpm
|
- rpm
|
||||||
- archlinux
|
- archlinux
|
||||||
|
# - apk
|
||||||
|
# - ipk
|
||||||
priority: extra
|
priority: extra
|
||||||
contents:
|
contents:
|
||||||
- src: release/config/config.json
|
- src: release/config/config.json
|
||||||
dst: /etc/sing-box/config.json
|
dst: /etc/sing-box/config.json
|
||||||
type: config
|
type: config
|
||||||
|
|
||||||
- src: release/config/sing-box.service
|
- src: release/config/sing-box.service
|
||||||
dst: /usr/lib/systemd/system/sing-box.service
|
dst: /usr/lib/systemd/system/sing-box.service
|
||||||
- src: release/config/sing-box@.service
|
- src: release/config/sing-box@.service
|
||||||
dst: /usr/lib/systemd/system/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
|
- src: LICENSE
|
||||||
dst: /usr/share/licenses/sing-box/LICENSE
|
dst: /usr/share/licenses/sing-box/LICENSE
|
||||||
deb:
|
deb:
|
||||||
@@ -141,13 +153,34 @@ nfpms:
|
|||||||
signature:
|
signature:
|
||||||
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
||||||
overrides:
|
overrides:
|
||||||
deb:
|
apk:
|
||||||
conflicts:
|
contents:
|
||||||
- sing-box-beta
|
- src: release/config/config.json
|
||||||
rpm:
|
dst: /etc/sing-box/config.json
|
||||||
conflicts:
|
type: config
|
||||||
- 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:
|
source:
|
||||||
enabled: false
|
enabled: false
|
||||||
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
|
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
|
||||||
|
|||||||
62
Makefile
62
Makefile
@@ -32,6 +32,9 @@ ci_build:
|
|||||||
go build $(PARAMS) $(MAIN)
|
go build $(PARAMS) $(MAIN)
|
||||||
go build $(MAIN_PARAMS) $(MAIN)
|
go build $(MAIN_PARAMS) $(MAIN)
|
||||||
|
|
||||||
|
generate_completions:
|
||||||
|
go run -v --tags generate,generate_completions $(MAIN)
|
||||||
|
|
||||||
install:
|
install:
|
||||||
go build -o $(PREFIX)/bin/$(NAME) $(MAIN_PARAMS) $(MAIN)
|
go build -o $(PREFIX)/bin/$(NAME) $(MAIN_PARAMS) $(MAIN)
|
||||||
|
|
||||||
@@ -71,7 +74,6 @@ release:
|
|||||||
dist/*.deb \
|
dist/*.deb \
|
||||||
dist/*.rpm \
|
dist/*.rpm \
|
||||||
dist/*_amd64.pkg.tar.zst \
|
dist/*_amd64.pkg.tar.zst \
|
||||||
dist/*_amd64v3.pkg.tar.zst \
|
|
||||||
dist/*_arm64.pkg.tar.zst \
|
dist/*_arm64.pkg.tar.zst \
|
||||||
dist/release
|
dist/release
|
||||||
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
|
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
|
||||||
@@ -104,10 +106,12 @@ publish_android:
|
|||||||
publish_android_appcenter:
|
publish_android_appcenter:
|
||||||
cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadPlayRelease
|
cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadPlayRelease
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: find why and remove `-destination 'generic/platform=iOS'`
|
||||||
build_ios:
|
build_ios:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFI.xcarchive && \
|
rm -rf build/SFI.xcarchive && \
|
||||||
xcodebuild archive -scheme SFI -configuration Release -archivePath build/SFI.xcarchive
|
xcodebuild archive -scheme SFI -configuration Release -destination 'generic/platform=iOS' -archivePath build/SFI.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
upload_ios_app_store:
|
upload_ios_app_store:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
@@ -118,55 +122,61 @@ release_ios: build_ios upload_ios_app_store
|
|||||||
build_macos:
|
build_macos:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFM.xcarchive && \
|
rm -rf build/SFM.xcarchive && \
|
||||||
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive
|
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
upload_macos_app_store:
|
upload_macos_app_store:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
||||||
|
|
||||||
release_macos: build_macos upload_macos_app_store
|
release_macos: build_macos upload_macos_app_store
|
||||||
|
|
||||||
build_macos_independent:
|
build_macos_standalone:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFT.System.xcarchive && \
|
rm -rf build/SFM.System.xcarchive && \
|
||||||
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive
|
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
notarize_macos_independent:
|
build_macos_dmg:
|
||||||
cd ../sing-box-for-apple && \
|
|
||||||
xcodebuild -exportArchive -archivePath "build/SFM.System.xcarchive" -exportOptionsPlist SFM.System/Upload.plist -allowProvisioningUpdates
|
|
||||||
|
|
||||||
wait_notarize_macos_independent:
|
|
||||||
sleep 60
|
|
||||||
|
|
||||||
export_macos_independent:
|
|
||||||
rm -rf dist/SFM
|
rm -rf dist/SFM
|
||||||
mkdir -p dist/SFM
|
mkdir -p dist/SFM
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
xcodebuild -exportNotarizedApp -archivePath build/SFM.System.xcarchive -exportPath "../sing-box/dist/SFM"
|
rm -rf build/SFM.System && \
|
||||||
|
rm -rf build/SFM.dmg && \
|
||||||
|
xcodebuild -exportArchive \
|
||||||
|
-archivePath "build/SFM.System.xcarchive" \
|
||||||
|
-exportOptionsPlist SFM.System/Export.plist -allowProvisioningUpdates \
|
||||||
|
-exportPath "build/SFM.System" && \
|
||||||
|
create-dmg \
|
||||||
|
--volname "sing-box" \
|
||||||
|
--volicon "build/SFM.System/SFM.app/Contents/Resources/AppIcon.icns" \
|
||||||
|
--icon "SFM.app" 0 0 \
|
||||||
|
--hide-extension "SFM.app" \
|
||||||
|
--app-drop-link 0 0 \
|
||||||
|
--skip-jenkins \
|
||||||
|
--notarize "notarytool-password" \
|
||||||
|
"../sing-box/dist/SFM/SFM.dmg" "build/SFM.System/SFM.app"
|
||||||
|
|
||||||
upload_macos_independent:
|
upload_macos_dmg:
|
||||||
cd dist/SFM && \
|
cd dist/SFM && \
|
||||||
rm -f *.zip && \
|
cp SFM.dmg "SFM-${VERSION}-universal.dmg" && \
|
||||||
zip -ry "SFM-${VERSION}-universal.zip" SFM.app && \
|
ghr --replace --draft --prerelease "v${VERSION}" "SFM-${VERSION}-universal.dmg"
|
||||||
ghr --replace --draft --prerelease "v${VERSION}" *.zip
|
|
||||||
|
|
||||||
release_macos_independent: build_macos_independent notarize_macos_independent wait_notarize_macos_independent export_macos_independent upload_macos_independent
|
release_macos_standalone: build_macos_standalone build_macos_dmg upload_macos_dmg
|
||||||
|
|
||||||
build_tvos:
|
build_tvos:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
rm -rf build/SFT.xcarchive && \
|
rm -rf build/SFT.xcarchive && \
|
||||||
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive
|
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive -allowProvisioningUpdates
|
||||||
|
|
||||||
upload_tvos_app_store:
|
upload_tvos_app_store:
|
||||||
cd ../sing-box-for-apple && \
|
cd ../sing-box-for-apple && \
|
||||||
xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates
|
||||||
|
|
||||||
release_tvos: build_tvos upload_tvos_app_store
|
release_tvos: build_tvos upload_tvos_app_store
|
||||||
|
|
||||||
update_apple_version:
|
update_apple_version:
|
||||||
go run ./cmd/internal/update_apple_version
|
go run ./cmd/internal/update_apple_version
|
||||||
|
|
||||||
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_independent
|
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_standalone
|
||||||
|
|
||||||
release_apple_beta: update_apple_version release_ios release_macos release_tvos
|
release_apple_beta: update_apple_version release_ios release_macos release_tvos
|
||||||
|
|
||||||
@@ -193,8 +203,8 @@ lib:
|
|||||||
go run ./cmd/internal/build_libbox -target ios
|
go run ./cmd/internal/build_libbox -target ios
|
||||||
|
|
||||||
lib_install:
|
lib_install:
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.3
|
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.4
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.3
|
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.4
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
venv/bin/mkdocs serve
|
venv/bin/mkdocs serve
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ The universal proxy platform.
|
|||||||
|
|
||||||
[](https://repology.org/project/sing-box/versions)
|
[](https://repology.org/project/sing-box/versions)
|
||||||
|
|
||||||
## Support
|
## Documentation
|
||||||
|
|
||||||
https://community.sagernet.org/c/sing-box/
|
https://sing-box.sagernet.org
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
Submodule clients/android updated: 440aaa9a1a...2aa661d507
Submodule clients/apple updated: aa4ce98421...c223f50ffb
@@ -26,8 +26,8 @@ func main() {
|
|||||||
common.Must(decoder.Decode(&project))
|
common.Must(decoder.Decode(&project))
|
||||||
objectsMap := project["objects"].(map[string]any)
|
objectsMap := project["objects"].(map[string]any)
|
||||||
projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
|
projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
|
||||||
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfa"}, newVersion.VersionString())
|
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfavt"}, newVersion.VersionString())
|
||||||
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfa.independent", "io.nekohasekai.sfa.system"}, newVersion.String())
|
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfavt.standalone", "io.nekohasekai.sfavt.system"}, newVersion.String())
|
||||||
if updated0 || updated1 {
|
if updated0 || updated1 {
|
||||||
log.Info("updated version to ", newVersion.VersionString(), " (", newVersion.String(), ")")
|
log.Info("updated version to ", newVersion.VersionString(), " (", newVersion.String(), ")")
|
||||||
}
|
}
|
||||||
|
|||||||
68
cmd/sing-box/cmd.go
Normal file
68
cmd/sing-box/cmd.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
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 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
28
cmd/sing-box/generate_completions.go
Normal file
28
cmd/sing-box/generate_completions.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//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
|
||||||
|
}
|
||||||
@@ -1,74 +1,11 @@
|
|||||||
|
//go:build !generate
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "github.com/sagernet/sing-box/log"
|
||||||
"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() {
|
func main() {
|
||||||
if err := mainCommand.Execute(); err != nil {
|
if err := mainCommand.Execute(); err != nil {
|
||||||
log.Fatal(err)
|
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package dialer
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/tfo-go"
|
"github.com/metacubex/tfo-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tcpDialer = tfo.Dialer
|
type tcpDialer = tfo.Dialer
|
||||||
|
|||||||
@@ -28,13 +28,12 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
|
|||||||
} else {
|
} else {
|
||||||
dialer = NewDetour(router, options.Detour)
|
dialer = NewDetour(router, options.Detour)
|
||||||
}
|
}
|
||||||
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
|
if options.Detour == "" {
|
||||||
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {
|
|
||||||
dialer = NewResolveDialer(
|
dialer = NewResolveDialer(
|
||||||
router,
|
router,
|
||||||
dialer,
|
dialer,
|
||||||
options.Detour == "" && !options.TCPFastOpen,
|
options.Detour == "" && !options.TCPFastOpen,
|
||||||
domainStrategy,
|
dns.DomainStrategy(options.DomainStrategy),
|
||||||
time.Duration(options.FallbackDelay))
|
time.Duration(options.FallbackDelay))
|
||||||
}
|
}
|
||||||
return dialer, nil
|
return dialer, nil
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import (
|
|||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/tfo-go"
|
|
||||||
|
"github.com/metacubex/tfo-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type slowOpenConn struct {
|
type slowOpenConn struct {
|
||||||
|
|||||||
@@ -18,28 +18,45 @@ type (
|
|||||||
PacketSniffer = func(ctx context.Context, packet []byte) (*adapter.InboundContext, error)
|
PacketSniffer = func(ctx context.Context, packet []byte) (*adapter.InboundContext, error)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func Skip(metadata adapter.InboundContext) bool {
|
||||||
|
// skip server first protocols
|
||||||
|
switch metadata.Destination.Port {
|
||||||
|
case 25, 465, 587:
|
||||||
|
// SMTP
|
||||||
|
return true
|
||||||
|
case 143, 993:
|
||||||
|
// IMAP
|
||||||
|
return true
|
||||||
|
case 110, 995:
|
||||||
|
// POP3
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) (*adapter.InboundContext, error) {
|
func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) (*adapter.InboundContext, error) {
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
timeout = C.ReadPayloadTimeout
|
timeout = C.ReadPayloadTimeout
|
||||||
}
|
}
|
||||||
deadline := time.Now().Add(timeout)
|
deadline := time.Now().Add(timeout)
|
||||||
var errors []error
|
var errors []error
|
||||||
|
for i := 0; ; i++ {
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
err := conn.SetReadDeadline(deadline)
|
err := conn.SetReadDeadline(deadline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "set read deadline")
|
return nil, E.Cause(err, "set read deadline")
|
||||||
}
|
}
|
||||||
_, err = buffer.ReadOnceFrom(conn)
|
_, err = buffer.ReadOnceFrom(conn)
|
||||||
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
_ = conn.SetReadDeadline(time.Time{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return nil, E.Cause(err, "read payload")
|
return nil, E.Cause(err, "read payload")
|
||||||
}
|
}
|
||||||
|
errors = nil
|
||||||
|
var metadata *adapter.InboundContext
|
||||||
for _, sniffer := range sniffers {
|
for _, sniffer := range sniffers {
|
||||||
metadata, err := sniffer(ctx, bytes.NewReader(buffer.Bytes()))
|
metadata, err = sniffer(ctx, bytes.NewReader(buffer.Bytes()))
|
||||||
if metadata != nil {
|
if metadata != nil {
|
||||||
return metadata, nil
|
return metadata, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,35 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
!!! failure "Help needed"
|
### 1.9.7
|
||||||
|
|
||||||
Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
* 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.9.6
|
||||||
|
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
### 1.9.5
|
||||||
|
|
||||||
|
* Update quic-go to v0.47.0
|
||||||
|
* Fix direct dialer not resolving domain
|
||||||
|
* Fix no error return when empty DNS cache retrieved
|
||||||
|
* Fix build with go1.23
|
||||||
|
* Fix stream sniffer
|
||||||
|
* Fix bad redirect in clash-api
|
||||||
|
* Fix wireguard events chan leak
|
||||||
|
* Fix cached conn eats up read deadlines
|
||||||
|
* Fix disconnected interface selected as default in windows
|
||||||
|
* Update Bundle Identifiers for Apple platform clients **1**
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
See [Migration](/migration/#bundle-identifier-updates-in-apple-platform-clients).
|
||||||
|
|
||||||
|
We are still working on getting all sing-box apps back on the App Store.
|
||||||
|
|
||||||
|
This work is expected to be completed within a week
|
||||||
|
(SFI on the App Store and others on TestFlight are already available).
|
||||||
|
|
||||||
### 1.9.4
|
### 1.9.4
|
||||||
|
|
||||||
@@ -23,6 +47,11 @@ icon: material/alert-decagram
|
|||||||
* Fix UDP connnection leak when sniffing
|
* Fix UDP connnection leak when sniffing
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
|
_Due to problems with our Apple developer account,
|
||||||
|
sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
||||||
|
If your company or organization is willing to help us return to the App Store,
|
||||||
|
please [contact us](mailto:contact@sagernet.org)._
|
||||||
|
|
||||||
### 1.9.3
|
### 1.9.3
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|||||||
@@ -7,13 +7,6 @@ icon: material/apple
|
|||||||
SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides
|
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.
|
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
|
## :material-graph: Requirements
|
||||||
|
|
||||||
* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+
|
* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+
|
||||||
@@ -21,13 +14,13 @@ platform-specific function implementation, such as TUN transparent proxy impleme
|
|||||||
|
|
||||||
## :material-download: Download
|
## :material-download: Download
|
||||||
|
|
||||||
* [App Store](https://apps.apple.com/us/app/sing-box/id6451272673)
|
* [App Store](https://apps.apple.com/app/sing-box-vt/id6673731168)
|
||||||
* ~~TestFlight (Beta)~~
|
* TestFlight (Beta)
|
||||||
|
|
||||||
TestFlight quota is only available to [sponsors](https://github.com/sponsors/nekohasekai)
|
TestFlight quota is only available to [sponsors](https://github.com/sponsors/nekohasekai)
|
||||||
(one-time sponsorships are accepted).
|
(one-time sponsorships are accepted).
|
||||||
Once you donate, you can get an invitation by sending us your Apple ID [via email](mailto:contact@sagernet.org),
|
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 join our Telegram group for sponsors from [@yet_another_sponsor_bot](https://t.me/yet_another_sponsor_bot).
|
or sending us your Apple ID [via email](mailto:contact@sagernet.org).
|
||||||
|
|
||||||
## :material-file-download: Download (macOS standalone version)
|
## :material-file-download: Download (macOS standalone version)
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
Maintained by Project S to provide a unified experience and platform-specific functionality.
|
Maintained by Project S to provide a unified experience and platform-specific functionality.
|
||||||
|
|
||||||
| Platform | Client |
|
| Platform | Client |
|
||||||
| ------------------------------------- | ---------------------------------------- |
|
|---------------------------------------|------------------------------------------|
|
||||||
| :material-android: Android | [sing-box for Android](./android/) |
|
| :material-android: Android | [sing-box for Android](./android/) |
|
||||||
| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [Unavailable](./apple/) |
|
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
|
||||||
| :material-laptop: Desktop | Working in progress |
|
| :material-laptop: Desktop | Working in progress |
|
||||||
|
|
||||||
Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core
|
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 维护,提供统一的体验与平台特定的功能。
|
由 Project S 维护,提供统一的体验与平台特定的功能。
|
||||||
|
|
||||||
| 平台 | 客户端 |
|
| 平台 | 客户端 |
|
||||||
| ------------------------------------- | ----------------------------------- |
|
|---------------------------------------|------------------------------------------|
|
||||||
| :material-android: Android | [sing-box for Android](./android/) |
|
| :material-android: Android | [sing-box for Android](./android/) |
|
||||||
| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [不可用](./apple/) |
|
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
|
||||||
| :material-laptop: Desktop | 施工中 |
|
| :material-laptop: Desktop | 施工中 |
|
||||||
|
|
||||||
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
|
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
|
||||||
VPN 客户端功能, 但代码质量很差且包含广告。
|
VPN 客户端功能, 但代码质量很差且包含广告。
|
||||||
|
|||||||
@@ -83,7 +83,10 @@
|
|||||||
|
|
||||||
如果设置,域名将在请求发出之前解析为 IP。
|
如果设置,域名将在请求发出之前解析为 IP。
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
| 出站 | 受影响的域名 | 默认回退值 |
|
||||||
|
|----------|--------------------------|-------------------------------------------|
|
||||||
|
| `direct` | 请求中的域名 | `inbound.domain_strategy` |
|
||||||
|
| others | 服务器地址中的域名 | / |
|
||||||
|
|
||||||
#### fallback_delay
|
#### fallback_delay
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ description: Welcome to the wiki page for the sing-box project.
|
|||||||
|
|
||||||
# :material-home: Home
|
# :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.
|
Welcome to the wiki page for the sing-box project.
|
||||||
|
|
||||||
The universal proxy platform.
|
The universal proxy platform.
|
||||||
|
|||||||
@@ -6,26 +6,18 @@ icon: material/file-code
|
|||||||
|
|
||||||
## :material-graph: Requirements
|
## :material-graph: Requirements
|
||||||
|
|
||||||
Before sing-box 1.4.0:
|
### sing-box 1.10
|
||||||
|
|
||||||
* Go 1.18.5 - 1.20.x
|
* Go 1.20.0 - ~
|
||||||
|
|
||||||
Since sing-box 1.4.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ with tag `with_quic` enabled
|
|
||||||
|
|
||||||
Since sing-box 1.5.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ with tag `with_quic` or `with_ech` enabled
|
|
||||||
|
|
||||||
Since sing-box 1.8.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
|
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
|
||||||
* Go 1.21.0 - ~ with tag `with_ech` enabled
|
* Go 1.21.0 - ~ with tag `with_ech` enabled
|
||||||
|
|
||||||
|
### sing-box 1.9
|
||||||
|
|
||||||
|
* Go 1.18.5 - 1.22.x
|
||||||
|
* Go 1.20.0 - 1.22.x with tag `with_quic`, or `with_utls` enabled
|
||||||
|
* Go 1.21.0 - 1.22.x with tag `with_ech` enabled
|
||||||
|
|
||||||
You can download and install Go from: https://go.dev/doc/install, latest version is recommended.
|
You can download and install Go from: https://go.dev/doc/install, latest version is recommended.
|
||||||
|
|
||||||
## :material-fast-forward: Simple Build
|
## :material-fast-forward: Simple Build
|
||||||
|
|||||||
@@ -6,25 +6,17 @@ icon: material/file-code
|
|||||||
|
|
||||||
## :material-graph: 要求
|
## :material-graph: 要求
|
||||||
|
|
||||||
sing-box 1.4.0 前:
|
### sing-box 1.10
|
||||||
|
|
||||||
* Go 1.18.5 - 1.20.x
|
* Go 1.20.0 - ~
|
||||||
|
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
|
||||||
|
* Go 1.21.0 - ~ with tag `with_ech` enabled
|
||||||
|
|
||||||
从 sing-box 1.4.0:
|
### sing-box 1.9
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
* Go 1.18.5 - 1.22.x
|
||||||
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic`
|
* Go 1.20.0 - 1.22.x with tag `with_quic`, or `with_utls` enabled
|
||||||
|
* Go 1.21.0 - 1.22.x with tag `with_ech` enabled
|
||||||
从 sing-box 1.5.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic` 或 `with_ech`
|
|
||||||
|
|
||||||
从 sing-box 1.8.0:
|
|
||||||
|
|
||||||
* Go 1.18.5 - ~
|
|
||||||
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic` 或 `with_utls`
|
|
||||||
* Go 1.20.1 - ~ 如果启用构建标记 `with_ech`
|
|
||||||
|
|
||||||
您可以从 https://go.dev/doc/install 下载并安装 Go,推荐使用最新版本。
|
您可以从 https://go.dev/doc/install 下载并安装 Go,推荐使用最新版本。
|
||||||
|
|
||||||
|
|||||||
@@ -24,14 +24,7 @@ icon: material/package
|
|||||||
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
||||||
sudo dnf install sing-box # or sing-box-beta
|
sudo dnf install sing-box # or sing-box-beta
|
||||||
```
|
```
|
||||||
|
(This applies to any distribution that uses `dnf` as the package manager: Fedora, CentOS, even OpenSUSE with DNF installed.)
|
||||||
=== ":material-redhat: CentOS / YUM"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo yum install -y yum-utils
|
|
||||||
sudo yum-config-manager --add-repo https://sing-box.app/sing-box.repo
|
|
||||||
sudo yum install sing-box # or sing-box-beta
|
|
||||||
```
|
|
||||||
|
|
||||||
## :material-download-box: Manual Installation
|
## :material-download-box: Manual Installation
|
||||||
|
|
||||||
@@ -46,6 +39,7 @@ icon: material/package
|
|||||||
```bash
|
```bash
|
||||||
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
||||||
```
|
```
|
||||||
|
(This applies to any distribution that uses `rpm` and `systemd`. Because of how `rpm` defines dependencies, if it installs, it probably works.)
|
||||||
|
|
||||||
=== ":simple-archlinux: Archlinux / PKG"
|
=== ":simple-archlinux: Archlinux / PKG"
|
||||||
|
|
||||||
@@ -63,6 +57,7 @@ icon: material/package
|
|||||||
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
||||||
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
||||||
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
||||||
|
| DEB | AOSC | `apt install sing-box` | [][aosc] |
|
||||||
|
|
||||||
=== ":material-apple: macOS"
|
=== ":material-apple: macOS"
|
||||||
|
|
||||||
@@ -90,6 +85,22 @@ icon: material/package
|
|||||||
|------------|----------|------------------------|--------------------------------------------------------------------------------------------|
|
|------------|----------|------------------------|--------------------------------------------------------------------------------------------|
|
||||||
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||||
|
|
||||||
|
## :material-alert: Problematic Sources
|
||||||
|
|
||||||
|
| Type | Platform | Link | Promblem(s) |
|
||||||
|
|------------|----------|-------------------------------------------------------------------------------------------|-----------------------------------------|
|
||||||
|
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | Problematic build tag list modification |
|
||||||
|
| Homebrew | / | [homebrew-core][brew] | Problematic build tag list modification |
|
||||||
|
| Termux | Android | [termux-packages][termux] | Problematic build tag list modification |
|
||||||
|
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | Old Go (go1.20) |
|
||||||
|
|
||||||
|
If you are a user of them, please report issues to them:
|
||||||
|
|
||||||
|
1. Please do not modify release build tags without full understanding of the related functionality: enabling non-default
|
||||||
|
labels may result in decreased performance; the lack of default labels may cause user confusion.
|
||||||
|
2. sing-box supports compiling with some older Go versions, but it is not recommended (especially versions that are no
|
||||||
|
longer supported by Go).
|
||||||
|
|
||||||
## :material-book-multiple: Service Management
|
## :material-book-multiple: Service Management
|
||||||
|
|
||||||
For Linux systems with [systemd][systemd], usually the installation already includes a sing-box service,
|
For Linux systems with [systemd][systemd], usually the installation already includes a sing-box service,
|
||||||
@@ -128,4 +139,6 @@ you can manage the service using the following command:
|
|||||||
|
|
||||||
[ports]: https://www.freshports.org/net/sing-box
|
[ports]: https://www.freshports.org/net/sing-box
|
||||||
|
|
||||||
|
[aosc]: https://packages.aosc.io/packages/sing-box
|
||||||
|
|
||||||
[systemd]: https://systemd.io/
|
[systemd]: https://systemd.io/
|
||||||
|
|||||||
@@ -24,14 +24,7 @@ icon: material/package
|
|||||||
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo
|
||||||
sudo dnf install sing-box # or sing-box-beta
|
sudo dnf install sing-box # or sing-box-beta
|
||||||
```
|
```
|
||||||
|
(这适用于任何使用 `dnf` 作为包管理器的发行版:Fedora、CentOS,甚至安装了 DNF 的 OpenSUSE。)
|
||||||
=== ":material-redhat: CentOS / YUM"
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo yum install -y yum-utils
|
|
||||||
sudo yum-config-manager --add-repo https://sing-box.app/sing-box.repo
|
|
||||||
sudo yum install sing-box # or sing-box-beta
|
|
||||||
```
|
|
||||||
|
|
||||||
## :material-download-box: 手动安装
|
## :material-download-box: 手动安装
|
||||||
|
|
||||||
@@ -46,6 +39,7 @@ icon: material/package
|
|||||||
```bash
|
```bash
|
||||||
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
|
||||||
```
|
```
|
||||||
|
(这适用于任何使用 `rpm` 和 `systemd` 的发行版。由于 `rpm` 定义依赖关系的方式,如果安装成功,就多半能用。)
|
||||||
|
|
||||||
=== ":simple-archlinux: Archlinux / PKG"
|
=== ":simple-archlinux: Archlinux / PKG"
|
||||||
|
|
||||||
@@ -63,6 +57,7 @@ icon: material/package
|
|||||||
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
||||||
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
||||||
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
||||||
|
| DEB | AOSC | `apt install sing-box` | [][aosc] |
|
||||||
|
|
||||||
=== ":material-apple: macOS"
|
=== ":material-apple: macOS"
|
||||||
|
|
||||||
@@ -90,6 +85,20 @@ icon: material/package
|
|||||||
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
|
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
|
||||||
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||||
|
|
||||||
|
## :material-alert: 存在问题的源
|
||||||
|
|
||||||
|
| 类型 | 平台 | 链接 | 原因 |
|
||||||
|
|------------|---------|-------------------------------------------------------------------------------------------|-----------------|
|
||||||
|
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改 |
|
||||||
|
| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 |
|
||||||
|
| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 |
|
||||||
|
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) |
|
||||||
|
|
||||||
|
如果您是其用户,请向他们报告问题:
|
||||||
|
|
||||||
|
1. 在未完全了解相关功能的情况下,请勿修改发布版本标签:启用非默认标签可能会导致性能下降;缺少默认标签可能会引起用户混淆。
|
||||||
|
2. sing-box 支持使用一些较旧的 Go 版本进行编译,但不推荐使用(特别是已不再受 Go 支持的版本)。
|
||||||
|
|
||||||
## :material-book-multiple: 服务管理
|
## :material-book-multiple: 服务管理
|
||||||
|
|
||||||
对于带有 [systemd][systemd] 的 Linux 系统,通常安装已经包含 sing-box 服务,
|
对于带有 [systemd][systemd] 的 Linux 系统,通常安装已经包含 sing-box 服务,
|
||||||
@@ -124,4 +133,6 @@ icon: material/package
|
|||||||
|
|
||||||
[ports]: https://www.freshports.org/net/sing-box
|
[ports]: https://www.freshports.org/net/sing-box
|
||||||
|
|
||||||
|
[aosc]: https://packages.aosc.io/packages/sing-box
|
||||||
|
|
||||||
[systemd]: https://systemd.io/
|
[systemd]: https://systemd.io/
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ icon: material/lightning-bolt
|
|||||||
|
|
||||||
# Hysteria 2
|
# Hysteria 2
|
||||||
|
|
||||||
The most popular Chinese-made simple protocol based on QUIC, the selling point is Brutal,
|
Hysteria 2 is a simple, Chinese-made protocol based on QUIC.
|
||||||
a congestion control algorithm that can resist packet loss by manually specifying the required rate by the user.
|
The selling point is Brutal, a congestion control algorithm that
|
||||||
|
tries to achieve a user-defined bandwidth despite packet loss.
|
||||||
|
|
||||||
!!! warning
|
!!! warning
|
||||||
|
|
||||||
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies.
|
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more obvious characteristics than TCP based proxies.
|
||||||
|
|
||||||
| Specification | Binary Characteristics | Active Detect Hiddenness |
|
| Specification | Resists passive detection | Resists active probes |
|
||||||
|---------------------------------------------------------------------------|------------------------|--------------------------|
|
|---------------------------------------------------------------------------|---------------------------|-----------------------|
|
||||||
| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: |
|
| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: |
|
||||||
|
|
||||||
## :material-text-box-check: Password Generator
|
## :material-text-box-check: Password Generator
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ To use sing-box with the official program, you need to fill in that combination
|
|||||||
Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your server.
|
Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your server.
|
||||||
|
|
||||||
=== ":material-harddisk: With local certificate"
|
=== ":material-harddisk: With local certificate"
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"inbounds": [
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ icon: material/send
|
|||||||
|
|
||||||
# Shadowsocks
|
# Shadowsocks
|
||||||
|
|
||||||
As the most well-known Chinese-made proxy protocol,
|
Shadowsocks is the most well-known Chinese-made proxy protocol.
|
||||||
Shadowsocks exists in multiple versions,
|
It exists in multiple versions, but only AEAD 2022 ciphers
|
||||||
but only AEAD 2022 ciphers TCP with multiplexing is recommended.
|
over TCP with multiplexing is recommended.
|
||||||
|
|
||||||
| Ciphers | Specification | Cryptographic Security | Binary Characteristics | Active Detect Hiddenness |
|
| Ciphers | Specification | Cryptographically sound | Resists passive detection | Resists active probes |
|
||||||
|----------------|------------------------------------------------------------|------------------------|------------------------|--------------------------|
|
|----------------|------------------------------------------------------------|-------------------------|---------------------------|-----------------------|
|
||||||
| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: |
|
| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: |
|
||||||
| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: |
|
| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: |
|
||||||
| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: |
|
| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: |
|
||||||
|
|
||||||
|
(We strongly recommend using multiplexing to send UDP traffic over TCP, because
|
||||||
|
doing otherwise is vulnerable to passive detection.)
|
||||||
|
|
||||||
## :material-text-box-check: Password Generator
|
## :material-text-box-check: Password Generator
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ icon: material/horse
|
|||||||
|
|
||||||
# Trojan
|
# Trojan
|
||||||
|
|
||||||
As the most commonly used TLS proxy made in China, Trojan can be used in various combinations,
|
Torjan is the most commonly used TLS proxy made in China. It can be used in various combinations,
|
||||||
but only the combination of uTLS and multiplexing is recommended.
|
but only the combination of uTLS and multiplexing is recommended.
|
||||||
|
|
||||||
| Protocol and implementation combination | Specification | Binary Characteristics | Active Detect Hiddenness |
|
| Protocol and implementation combination | Specification | Resists passive detection | Resists active probes |
|
||||||
|-----------------------------------------|----------------------------------------------------------------------|------------------------|--------------------------|
|
|-----------------------------------------|----------------------------------------------------------------------|---------------------------|-----------------------|
|
||||||
| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: |
|
| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: |
|
||||||
| Basic Go implementation | / | :material-alert: | :material-check: |
|
| Basic Go implementation | / | :material-alert: | :material-check: |
|
||||||
| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: |
|
| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: |
|
||||||
| with uTLS enabled | No formal definition | :material-help: | :material-check: |
|
| with uTLS enabled | No formal definition | :material-help: | :material-check: |
|
||||||
|
|
||||||
## :material-text-box-check: Password Generator
|
## :material-text-box-check: Password Generator
|
||||||
|
|
||||||
@@ -211,4 +211,3 @@ but only the combination of uTLS and multiplexing is recommended.
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,23 @@
|
|||||||
icon: material/arrange-bring-forward
|
icon: material/arrange-bring-forward
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 1.9.5
|
||||||
|
|
||||||
|
### Bundle Identifier updates in Apple platform clients
|
||||||
|
|
||||||
|
Due to problems with our old Apple developer account,
|
||||||
|
we can only change Bundle Identifiers to re-list sing-box apps,
|
||||||
|
which means the data will not be automatically inherited.
|
||||||
|
|
||||||
|
For iOS, you need to back up your old data yourself (if you still have access to it);
|
||||||
|
for tvOS, you need to re-import profiles from your iPhone or iPad or create it manually;
|
||||||
|
for macOS, you can migrate the data folder using the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Library/Group\ Containers && \
|
||||||
|
mv group.io.nekohasekai.sfa group.io.nekohasekai.sfavt
|
||||||
|
```
|
||||||
|
|
||||||
## 1.9.0
|
## 1.9.0
|
||||||
|
|
||||||
### `domain_suffix` behavior update
|
### `domain_suffix` behavior update
|
||||||
|
|||||||
@@ -2,6 +2,22 @@
|
|||||||
icon: material/arrange-bring-forward
|
icon: material/arrange-bring-forward
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 1.9.5
|
||||||
|
|
||||||
|
### Apple 平台客户端的 Bundle Identifier 更新
|
||||||
|
|
||||||
|
由于我们旧的苹果开发者账户存在问题,我们只能通过更新 Bundle Identifiers
|
||||||
|
来重新上架 sing-box 应用, 这意味着数据不会自动继承。
|
||||||
|
|
||||||
|
对于 iOS,您需要自行备份旧的数据(如果您仍然可以访问);
|
||||||
|
对于 Apple tvOS,您需要从 iPhone 或 iPad 重新导入配置或者手动创建;
|
||||||
|
对于 macOS,您可以使用以下命令迁移数据文件夹:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Library/Group\ Containers && \
|
||||||
|
mv group.io.nekohasekai.sfa group.io.nekohasekai.sfavt
|
||||||
|
```
|
||||||
|
|
||||||
## 1.9.0
|
## 1.9.0
|
||||||
|
|
||||||
### `domain_suffix` 行为更新
|
### `domain_suffix` 行为更新
|
||||||
|
|||||||
26
docs/sponsors.md
Normal file
26
docs/sponsors.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
icon: material/hand-coin
|
||||||
|
---
|
||||||
|
|
||||||
|
# Sponsors
|
||||||
|
|
||||||
|
Do you or your friends use sing-box?
|
||||||
|
|
||||||
|
You can help keep the project bug-free and feature rich by sponsoring
|
||||||
|
the project maintainer via [GitHub Sponsors](https://github.com/sponsors/nekohasekai).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Special Sponsors
|
||||||
|
|
||||||
|
**Viral Tech, Inc.**
|
||||||
|
|
||||||
|
Helping us re-list sing-box apps on the Apple Store.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[](https://www.jetbrains.com)
|
||||||
|
|
||||||
|
Free license for the amazing IDEs.
|
||||||
|
|
||||||
|
---
|
||||||
@@ -308,10 +308,11 @@ func authentication(serverSecret string) func(next http.Handler) http.Handler {
|
|||||||
|
|
||||||
func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) {
|
func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
if redirect {
|
contentType := r.Header.Get("Content-Type")
|
||||||
http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect)
|
if !redirect || contentType == "application/json" {
|
||||||
} else {
|
|
||||||
render.JSON(w, r, render.M{"hello": "clash"})
|
render.JSON(w, r, render.M{"hello": "clash"})
|
||||||
|
} else {
|
||||||
|
http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ func (p *platformLocalDNSTransport) Exchange(ctx context.Context, message *mDNS.
|
|||||||
context: ctx,
|
context: ctx,
|
||||||
}
|
}
|
||||||
var responseMessage *mDNS.Msg
|
var responseMessage *mDNS.Msg
|
||||||
return responseMessage, task.Run(ctx, func() error {
|
var group task.Group
|
||||||
|
group.Append0(func(ctx context.Context) error {
|
||||||
err = p.iif.Exchange(response, messageBytes)
|
err = p.iif.Exchange(response, messageBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -80,6 +81,11 @@ func (p *platformLocalDNSTransport) Exchange(ctx context.Context, message *mDNS.
|
|||||||
responseMessage = &response.message
|
responseMessage = &response.message
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
err = group.Run(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return responseMessage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) {
|
func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) {
|
||||||
@@ -96,7 +102,8 @@ func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, s
|
|||||||
context: ctx,
|
context: ctx,
|
||||||
}
|
}
|
||||||
var responseAddr []netip.Addr
|
var responseAddr []netip.Addr
|
||||||
return responseAddr, task.Run(ctx, func() error {
|
var group task.Group
|
||||||
|
group.Append0(func(ctx context.Context) error {
|
||||||
err := p.iif.Lookup(response, network, domain)
|
err := p.iif.Lookup(response, network, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -121,6 +128,11 @@ func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, s
|
|||||||
}*/
|
}*/
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
err := group.Run(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return responseAddr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Func interface {
|
type Func interface {
|
||||||
|
|||||||
16
go.mod
16
go.mod
@@ -16,27 +16,27 @@ require (
|
|||||||
github.com/libdns/alidns v1.0.3
|
github.com/libdns/alidns v1.0.3
|
||||||
github.com/libdns/cloudflare v0.1.1
|
github.com/libdns/cloudflare v0.1.1
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||||
|
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d
|
||||||
github.com/mholt/acmez v1.2.0
|
github.com/mholt/acmez v1.2.0
|
||||||
github.com/miekg/dns v1.1.59
|
github.com/miekg/dns v1.1.59
|
||||||
github.com/ooni/go-libtor v1.1.8
|
github.com/ooni/go-libtor v1.1.8
|
||||||
github.com/oschwald/maxminddb-golang v1.12.0
|
github.com/oschwald/maxminddb-golang v1.12.0
|
||||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1
|
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1
|
||||||
github.com/sagernet/gomobile v0.1.3
|
github.com/sagernet/gomobile v0.1.4
|
||||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
||||||
github.com/sagernet/quic-go v0.46.0-beta.4
|
github.com/sagernet/quic-go v0.47.0-beta.2
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||||
github.com/sagernet/sing v0.4.2
|
github.com/sagernet/sing v0.4.3
|
||||||
github.com/sagernet/sing-dns v0.2.3
|
github.com/sagernet/sing-dns v0.2.3
|
||||||
github.com/sagernet/sing-mux v0.2.0
|
github.com/sagernet/sing-mux v0.2.0
|
||||||
github.com/sagernet/sing-quic v0.2.2
|
github.com/sagernet/sing-quic v0.2.2
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||||
github.com/sagernet/sing-shadowtls v0.1.4
|
github.com/sagernet/sing-shadowtls v0.1.4
|
||||||
github.com/sagernet/sing-tun v0.3.2
|
github.com/sagernet/sing-tun v0.3.3
|
||||||
github.com/sagernet/sing-vmess v0.1.12
|
github.com/sagernet/sing-vmess v0.1.12
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||||
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6
|
|
||||||
github.com/sagernet/utls v1.5.4
|
github.com/sagernet/utls v1.5.4
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8
|
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||||
@@ -46,7 +46,7 @@ require (
|
|||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.23.0
|
golang.org/x/crypto v0.23.0
|
||||||
golang.org/x/net v0.25.0
|
golang.org/x/net v0.25.0
|
||||||
golang.org/x/sys v0.21.0
|
golang.org/x/sys v0.25.0
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
google.golang.org/grpc v1.63.2
|
google.golang.org/grpc v1.63.2
|
||||||
google.golang.org/protobuf v1.33.0
|
google.golang.org/protobuf v1.33.0
|
||||||
@@ -86,8 +86,8 @@ require (
|
|||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
||||||
golang.org/x/mod v0.18.0 // indirect
|
golang.org/x/mod v0.18.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.18.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||||
|
|||||||
32
go.sum
32
go.sum
@@ -69,6 +69,8 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
|||||||
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
|
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 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||||
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||||
@@ -95,19 +97,19 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
|
|||||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY=
|
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY=
|
||||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k=
|
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k=
|
||||||
github.com/sagernet/gomobile v0.1.3 h1:ohjIb1Ou2+1558PnZour3od69suSuvkdSVOlO1tC4B8=
|
github.com/sagernet/gomobile v0.1.4 h1:WzX9ka+iHdupMgy2Vdich+OAt7TM8C2cZbIbzNjBrJY=
|
||||||
github.com/sagernet/gomobile v0.1.3/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
github.com/sagernet/gomobile v0.1.4/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 h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I=
|
||||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
||||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
|
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
|
||||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||||
github.com/sagernet/quic-go v0.46.0-beta.4 h1:k9f7VSKaM47AY6MPND0Qf1KRN7HwimPg9zdOFTXTiCk=
|
github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU=
|
||||||
github.com/sagernet/quic-go v0.46.0-beta.4/go.mod h1:zJmVdJUNqEDXfubf4KtIOUHHerggjBduiGRLNzJspcM=
|
github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q=
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
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/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.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||||
github.com/sagernet/sing v0.4.2 h1:jzGNJdZVRI0xlAfFugsIQUPvyB9SuWvbJK7zQCXc4QM=
|
github.com/sagernet/sing v0.4.3 h1:Ty/NAiNnVd6844k7ujlL5lkzydhcTH5Psc432jXA4Y8=
|
||||||
github.com/sagernet/sing v0.4.2/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
github.com/sagernet/sing v0.4.3/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
||||||
github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
|
github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
|
||||||
github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
|
github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
|
||||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||||
@@ -120,14 +122,12 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
|
|||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
github.com/sagernet/sing-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 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||||
github.com/sagernet/sing-tun v0.3.2 h1:z0bLUT/YXH9RrJS9DsIpB0Bb9afl2hVJOmHd0zA3HJY=
|
github.com/sagernet/sing-tun v0.3.3 h1:LZnQNmfGcNG2KPTPkLgc+Lo7k606QJVkPp2DnjriwUk=
|
||||||
github.com/sagernet/sing-tun v0.3.2/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ=
|
github.com/sagernet/sing-tun v0.3.3/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ=
|
||||||
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
|
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/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 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||||
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26Wn/UByW6b7q8QKB0ZkPqsyqcz2PI=
|
|
||||||
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6/go.mod h1:73xRZuxwkFk4aiLw28hG8W6o9cr2UPrGL9pdY2UTbvY=
|
|
||||||
github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co=
|
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/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 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs=
|
||||||
@@ -173,8 +173,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.8.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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -184,14 +184,14 @@ 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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.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.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.25.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.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
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/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.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/tfo-go"
|
"github.com/metacubex/tfo-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
const go120Available = true
|
const go120Available = true
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ nav:
|
|||||||
- Migration: migration.md
|
- Migration: migration.md
|
||||||
- Deprecated: deprecated.md
|
- Deprecated: deprecated.md
|
||||||
- Support: support.md
|
- Support: support.md
|
||||||
|
- Sponsors: sponsors.md
|
||||||
- Installation:
|
- Installation:
|
||||||
- Package Manager: installation/package-manager.md
|
- Package Manager: installation/package-manager.md
|
||||||
- Docker: installation/docker.md
|
- Docker: installation/docker.md
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
|||||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
||||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||||
var group task.Group
|
var group task.Group
|
||||||
group.Append0(func(ctx context.Context) error {
|
group.Append0(func(_ context.Context) error {
|
||||||
for {
|
for {
|
||||||
var message mDNS.Msg
|
var message mDNS.Msg
|
||||||
var destination M.Socksaddr
|
var destination M.Socksaddr
|
||||||
@@ -185,11 +185,10 @@ 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 {
|
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)
|
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
||||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||||
var group task.Group
|
var group task.Group
|
||||||
group.Append0(func(ctx context.Context) error {
|
group.Append0(func(_ context.Context) error {
|
||||||
for {
|
for {
|
||||||
var (
|
var (
|
||||||
message mDNS.Msg
|
message mDNS.Msg
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ func (w *WireGuard) start() error {
|
|||||||
}
|
}
|
||||||
bind = wireguard.NewClientBind(w.ctx, w, w.listener, isConnect, connectAddr, reserved)
|
bind = wireguard.NewClientBind(w.ctx, w, w.listener, isConnect, connectAddr, reserved)
|
||||||
}
|
}
|
||||||
|
err = w.tunDevice.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
wgDevice := device.NewDevice(w.tunDevice, bind, &device.Logger{
|
wgDevice := device.NewDevice(w.tunDevice, bind, &device.Logger{
|
||||||
Verbosef: func(format string, args ...interface{}) {
|
Verbosef: func(format string, args ...interface{}) {
|
||||||
w.logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
|
w.logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
|
||||||
@@ -170,7 +174,7 @@ func (w *WireGuard) start() error {
|
|||||||
}
|
}
|
||||||
w.device = wgDevice
|
w.device = wgDevice
|
||||||
w.pauseCallback = w.pauseManager.RegisterCallback(w.onPauseUpdated)
|
w.pauseCallback = w.pauseManager.RegisterCallback(w.onPauseUpdated)
|
||||||
return w.tunDevice.Start()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) Close() error {
|
func (w *WireGuard) Close() error {
|
||||||
@@ -180,7 +184,6 @@ func (w *WireGuard) Close() error {
|
|||||||
if w.pauseCallback != nil {
|
if w.pauseCallback != nil {
|
||||||
w.pauseManager.UnregisterCallback(w.pauseCallback)
|
w.pauseManager.UnregisterCallback(w.pauseCallback)
|
||||||
}
|
}
|
||||||
w.tunDevice.Close()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1549
release/completions/sing-box.bash
Normal file
1549
release/completions/sing-box.bash
Normal file
File diff suppressed because it is too large
Load Diff
235
release/completions/sing-box.fish
Normal file
235
release/completions/sing-box.fish
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
# 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'
|
||||||
212
release/completions/sing-box.zsh
Normal file
212
release/completions/sing-box.zsh
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#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
|
||||||
5
release/config/openwrt.conf
Normal file
5
release/config/openwrt.conf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
config sing-box 'main'
|
||||||
|
option enabled '1'
|
||||||
|
option conffile '/etc/sing-box/config.json'
|
||||||
|
option workdir '/usr/share/sing-box'
|
||||||
|
option log_stderr '1'
|
||||||
31
release/config/openwrt.init
Normal file
31
release/config/openwrt.init
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/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"
|
||||||
|
}
|
||||||
18
release/config/sing-box.initd
Normal file
18
release/config/sing-box.initd
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/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 $?
|
||||||
|
}
|
||||||
@@ -832,7 +832,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
conn = deadline.NewConn(conn)
|
conn = deadline.NewConn(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata.InboundOptions.SniffEnabled {
|
if metadata.InboundOptions.SniffEnabled && !sniff.Skip(metadata) {
|
||||||
buffer := buf.NewPacket()
|
buffer := buf.NewPacket()
|
||||||
sniffMetadata, err := sniff.PeekStream(ctx, conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost)
|
sniffMetadata, err := sniff.PeekStream(ctx, conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost)
|
||||||
if sniffMetadata != nil {
|
if sniffMetadata != nil {
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS
|
|||||||
)
|
)
|
||||||
responseAddrs, cached = r.dnsClient.LookupCache(ctx, domain, strategy)
|
responseAddrs, cached = r.dnsClient.LookupCache(ctx, domain, strategy)
|
||||||
if cached {
|
if cached {
|
||||||
|
if len(responseAddrs) == 0 {
|
||||||
|
return nil, dns.RCodeNameError
|
||||||
|
}
|
||||||
return responseAddrs, nil
|
return responseAddrs, nil
|
||||||
}
|
}
|
||||||
r.dnsLogger.DebugContext(ctx, "lookup domain ", domain)
|
r.dnsLogger.DebugContext(ctx, "lookup domain ", domain)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
func NewRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) (adapter.RuleSet, error) {
|
func NewRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) (adapter.RuleSet, error) {
|
||||||
switch options.Type {
|
switch options.Type {
|
||||||
case C.RuleSetTypeLocal:
|
case C.RuleSetTypeLocal:
|
||||||
return NewLocalRuleSet(router, options)
|
return NewLocalRuleSet(ctx, router, options)
|
||||||
case C.RuleSetTypeRemote:
|
case C.RuleSetTypeRemote:
|
||||||
return NewRemoteRuleSet(ctx, router, logger, options), nil
|
return NewRemoteRuleSet(ctx, router, logger, options), nil
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/service/filemanager"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.RuleSet = (*LocalRuleSet)(nil)
|
var _ adapter.RuleSet = (*LocalRuleSet)(nil)
|
||||||
@@ -21,11 +22,11 @@ type LocalRuleSet struct {
|
|||||||
metadata adapter.RuleSetMetadata
|
metadata adapter.RuleSetMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLocalRuleSet(router adapter.Router, options option.RuleSet) (*LocalRuleSet, error) {
|
func NewLocalRuleSet(ctx context.Context, router adapter.Router, options option.RuleSet) (*LocalRuleSet, error) {
|
||||||
var plainRuleSet option.PlainRuleSet
|
var plainRuleSet option.PlainRuleSet
|
||||||
switch options.Format {
|
switch options.Format {
|
||||||
case C.RuleSetFormatSource, "":
|
case C.RuleSetFormatSource, "":
|
||||||
content, err := os.ReadFile(options.LocalOptions.Path)
|
content, err := os.ReadFile(filemanager.BasePath(ctx, options.LocalOptions.Path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -35,7 +36,7 @@ func NewLocalRuleSet(router adapter.Router, options option.RuleSet) (*LocalRuleS
|
|||||||
}
|
}
|
||||||
plainRuleSet = compat.Upgrade()
|
plainRuleSet = compat.Upgrade()
|
||||||
case C.RuleSetFormatBinary:
|
case C.RuleSetFormatBinary:
|
||||||
setFile, err := os.Open(options.LocalOptions.Path)
|
setFile, err := os.Open(filemanager.BasePath(ctx, options.LocalOptions.Path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,17 +230,13 @@ func (w *StackDevice) Events() <-chan wgTun.Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *StackDevice) Close() error {
|
func (w *StackDevice) Close() error {
|
||||||
select {
|
close(w.done)
|
||||||
case <-w.done:
|
close(w.events)
|
||||||
return os.ErrClosed
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
w.stack.Close()
|
w.stack.Close()
|
||||||
for _, endpoint := range w.stack.CleanupEndpoints() {
|
for _, endpoint := range w.stack.CleanupEndpoints() {
|
||||||
endpoint.Abort()
|
endpoint.Abort()
|
||||||
}
|
}
|
||||||
w.stack.Wait()
|
w.stack.Wait()
|
||||||
close(w.done)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
@@ -21,14 +22,16 @@ import (
|
|||||||
var _ Device = (*SystemDevice)(nil)
|
var _ Device = (*SystemDevice)(nil)
|
||||||
|
|
||||||
type SystemDevice struct {
|
type SystemDevice struct {
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
device tun.Tun
|
device tun.Tun
|
||||||
batchDevice tun.LinuxTUN
|
batchDevice tun.LinuxTUN
|
||||||
name string
|
name string
|
||||||
mtu int
|
mtu uint32
|
||||||
events chan wgTun.Event
|
inet4Addresses []netip.Prefix
|
||||||
addr4 netip.Addr
|
inet6Addresses []netip.Prefix
|
||||||
addr6 netip.Addr
|
gso bool
|
||||||
|
events chan wgTun.Event
|
||||||
|
closeOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSystemDevice(router adapter.Router, interfaceName string, localPrefixes []netip.Prefix, mtu uint32, gso bool) (*SystemDevice, error) {
|
func NewSystemDevice(router adapter.Router, interfaceName string, localPrefixes []netip.Prefix, mtu uint32, gso bool) (*SystemDevice, error) {
|
||||||
@@ -44,43 +47,17 @@ func NewSystemDevice(router adapter.Router, interfaceName string, localPrefixes
|
|||||||
if interfaceName == "" {
|
if interfaceName == "" {
|
||||||
interfaceName = tun.CalculateInterfaceName("wg")
|
interfaceName = tun.CalculateInterfaceName("wg")
|
||||||
}
|
}
|
||||||
tunInterface, err := tun.New(tun.Options{
|
|
||||||
Name: interfaceName,
|
|
||||||
Inet4Address: inet4Addresses,
|
|
||||||
Inet6Address: inet6Addresses,
|
|
||||||
MTU: mtu,
|
|
||||||
GSO: gso,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var inet4Address netip.Addr
|
|
||||||
var inet6Address netip.Addr
|
|
||||||
if len(inet4Addresses) > 0 {
|
|
||||||
inet4Address = inet4Addresses[0].Addr()
|
|
||||||
}
|
|
||||||
if len(inet6Addresses) > 0 {
|
|
||||||
inet6Address = inet6Addresses[0].Addr()
|
|
||||||
}
|
|
||||||
var batchDevice tun.LinuxTUN
|
|
||||||
if gso {
|
|
||||||
batchTUN, isBatchTUN := tunInterface.(tun.LinuxTUN)
|
|
||||||
if !isBatchTUN {
|
|
||||||
return nil, E.New("GSO is not supported on current platform")
|
|
||||||
}
|
|
||||||
batchDevice = batchTUN
|
|
||||||
}
|
|
||||||
return &SystemDevice{
|
return &SystemDevice{
|
||||||
dialer: common.Must1(dialer.NewDefault(router, option.DialerOptions{
|
dialer: common.Must1(dialer.NewDefault(router, option.DialerOptions{
|
||||||
BindInterface: interfaceName,
|
BindInterface: interfaceName,
|
||||||
})),
|
})),
|
||||||
device: tunInterface,
|
name: interfaceName,
|
||||||
batchDevice: batchDevice,
|
mtu: mtu,
|
||||||
name: interfaceName,
|
inet4Addresses: inet4Addresses,
|
||||||
mtu: int(mtu),
|
inet6Addresses: inet6Addresses,
|
||||||
events: make(chan wgTun.Event),
|
gso: gso,
|
||||||
addr4: inet4Address,
|
events: make(chan wgTun.Event, 1),
|
||||||
addr6: inet6Address,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,14 +70,39 @@ func (w *SystemDevice) ListenPacket(ctx context.Context, destination M.Socksaddr
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *SystemDevice) Inet4Address() netip.Addr {
|
func (w *SystemDevice) Inet4Address() netip.Addr {
|
||||||
return w.addr4
|
if len(w.inet4Addresses) == 0 {
|
||||||
|
return netip.Addr{}
|
||||||
|
}
|
||||||
|
return w.inet4Addresses[0].Addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *SystemDevice) Inet6Address() netip.Addr {
|
func (w *SystemDevice) Inet6Address() netip.Addr {
|
||||||
return w.addr6
|
if len(w.inet6Addresses) == 0 {
|
||||||
|
return netip.Addr{}
|
||||||
|
}
|
||||||
|
return w.inet6Addresses[0].Addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *SystemDevice) Start() error {
|
func (w *SystemDevice) Start() error {
|
||||||
|
tunInterface, err := tun.New(tun.Options{
|
||||||
|
Name: w.name,
|
||||||
|
Inet4Address: w.inet4Addresses,
|
||||||
|
Inet6Address: w.inet6Addresses,
|
||||||
|
MTU: w.mtu,
|
||||||
|
GSO: w.gso,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.device = tunInterface
|
||||||
|
if w.gso {
|
||||||
|
batchTUN, isBatchTUN := tunInterface.(tun.LinuxTUN)
|
||||||
|
if !isBatchTUN {
|
||||||
|
tunInterface.Close()
|
||||||
|
return E.New("GSO is not supported on current platform")
|
||||||
|
}
|
||||||
|
w.batchDevice = batchTUN
|
||||||
|
}
|
||||||
w.events <- wgTun.EventUp
|
w.events <- wgTun.EventUp
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -143,7 +145,7 @@ func (w *SystemDevice) Flush() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *SystemDevice) MTU() (int, error) {
|
func (w *SystemDevice) MTU() (int, error) {
|
||||||
return w.mtu, nil
|
return int(w.mtu), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *SystemDevice) Name() (string, error) {
|
func (w *SystemDevice) Name() (string, error) {
|
||||||
@@ -155,6 +157,7 @@ func (w *SystemDevice) Events() <-chan wgTun.Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *SystemDevice) Close() error {
|
func (w *SystemDevice) Close() error {
|
||||||
|
close(w.events)
|
||||||
return w.device.Close()
|
return w.device.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user