mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-30 05:37:27 +03:00
Compare commits
42 Commits
v1.10.0-be
...
renovate/g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05a431d203 | ||
|
|
e68a9e623f | ||
|
|
a9bb07db4a | ||
|
|
a07219d16d | ||
|
|
6362b778c9 | ||
|
|
cb46b648d7 | ||
|
|
04613c27e2 | ||
|
|
795e1cf2f0 | ||
|
|
1e36c75336 | ||
|
|
5a2c7037fe | ||
|
|
852c07c050 | ||
|
|
c2ab497ff4 | ||
|
|
1e3c136440 | ||
|
|
7a2cd77798 | ||
|
|
1cdaea49b6 | ||
|
|
a50b0bc1a9 | ||
|
|
00e6210928 | ||
|
|
2dbeb63b4e | ||
|
|
744cc985ba | ||
|
|
bd122478fc | ||
|
|
a18179ad24 | ||
|
|
388c75a815 | ||
|
|
8d0d49c388 | ||
|
|
03f5d6e4f2 | ||
|
|
25065d766a | ||
|
|
d44e7d9834 | ||
|
|
369bc7cea3 | ||
|
|
4b7a83da16 | ||
|
|
0f7154afbd | ||
|
|
a06d10c3bc | ||
|
|
63cc6cc76c | ||
|
|
d55c5b5cab | ||
|
|
b624c2dcc7 | ||
|
|
9415444ebd | ||
|
|
95606191d8 | ||
|
|
e586d9e9bc | ||
|
|
8c7eaa4477 | ||
|
|
8464c8cb7c | ||
|
|
39d7127651 | ||
|
|
e2077009c4 | ||
|
|
700a8eb425 | ||
|
|
3b0cba0852 |
10
.github/workflows/debug.yml
vendored
10
.github/workflows/debug.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -207,7 +207,7 @@ jobs:
|
||||
TAGS: with_clash_api,with_quic
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
14
.github/workflows/docker.yml
vendored
14
.github/workflows/docker.yml
vendored
@@ -27,12 +27,22 @@ jobs:
|
||||
- linux/ppc64le
|
||||
- linux/riscv64
|
||||
- linux/s390x
|
||||
- linux/mips64le
|
||||
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
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
ref: ${{ steps.ref.outputs.ref }}
|
||||
fetch-depth: 0
|
||||
- name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
2
.github/workflows/linux.yml
vendored
2
.github/workflows/linux.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
@@ -49,10 +49,19 @@ nfpms:
|
||||
- src: release/config/config.json
|
||||
dst: /etc/sing-box/config.json
|
||||
type: config
|
||||
|
||||
- src: release/config/sing-box.service
|
||||
dst: /usr/lib/systemd/system/sing-box.service
|
||||
- src: release/config/sing-box@.service
|
||||
dst: /usr/lib/systemd/system/sing-box@.service
|
||||
|
||||
- src: release/completions/sing-box.bash
|
||||
dst: /usr/share/bash-completion/completions/sing-box.bash
|
||||
- src: release/completions/sing-box.fish
|
||||
dst: /usr/share/fish/vendor_completions.d/sing-box.fish
|
||||
- src: release/completions/sing-box.zsh
|
||||
dst: /usr/share/zsh/site-functions/_sing-box
|
||||
|
||||
- src: LICENSE
|
||||
dst: /usr/share/licenses/sing-box/LICENSE
|
||||
deb:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
version: 2
|
||||
project_name: sing-box
|
||||
builds:
|
||||
- &template
|
||||
@@ -25,7 +26,6 @@ builds:
|
||||
targets:
|
||||
- linux_386
|
||||
- linux_amd64_v1
|
||||
- linux_amd64_v3
|
||||
- linux_arm64
|
||||
- linux_arm_6
|
||||
- linux_arm_7
|
||||
@@ -33,7 +33,6 @@ builds:
|
||||
- linux_riscv64
|
||||
- linux_mips64le
|
||||
- windows_amd64_v1
|
||||
- windows_amd64_v3
|
||||
- windows_386
|
||||
- windows_arm64
|
||||
- darwin_amd64_v1
|
||||
@@ -90,8 +89,6 @@ builds:
|
||||
- android_arm64
|
||||
- android_386
|
||||
- android_amd64
|
||||
snapshot:
|
||||
name_template: "{{ .Version }}.{{ .ShortCommit }}"
|
||||
archives:
|
||||
- &template
|
||||
id: archive
|
||||
@@ -105,7 +102,7 @@ archives:
|
||||
wrap_in_directory: true
|
||||
files:
|
||||
- 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
|
||||
<<: *template
|
||||
builds:
|
||||
@@ -114,7 +111,7 @@ archives:
|
||||
nfpms:
|
||||
- id: package
|
||||
package_name: sing-box
|
||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
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:
|
||||
- main
|
||||
homepage: https://sing-box.sagernet.org/
|
||||
@@ -125,15 +122,26 @@ nfpms:
|
||||
- deb
|
||||
- rpm
|
||||
- archlinux
|
||||
# - apk
|
||||
# - ipk
|
||||
priority: extra
|
||||
contents:
|
||||
- src: release/config/config.json
|
||||
dst: /etc/sing-box/config.json
|
||||
type: config
|
||||
|
||||
- src: release/config/sing-box.service
|
||||
dst: /usr/lib/systemd/system/sing-box.service
|
||||
- src: release/config/sing-box@.service
|
||||
dst: /usr/lib/systemd/system/sing-box@.service
|
||||
|
||||
- src: release/completions/sing-box.bash
|
||||
dst: /usr/share/bash-completion/completions/sing-box.bash
|
||||
- src: release/completions/sing-box.fish
|
||||
dst: /usr/share/fish/vendor_completions.d/sing-box.fish
|
||||
- src: release/completions/sing-box.zsh
|
||||
dst: /usr/share/zsh/site-functions/_sing-box
|
||||
|
||||
- src: LICENSE
|
||||
dst: /usr/share/licenses/sing-box/LICENSE
|
||||
deb:
|
||||
@@ -145,13 +153,34 @@ nfpms:
|
||||
signature:
|
||||
key_file: "{{ .Env.NFPM_KEY_PATH }}"
|
||||
overrides:
|
||||
deb:
|
||||
conflicts:
|
||||
- sing-box-beta
|
||||
rpm:
|
||||
conflicts:
|
||||
- sing-box-beta
|
||||
apk:
|
||||
contents:
|
||||
- src: release/config/config.json
|
||||
dst: /etc/sing-box/config.json
|
||||
type: config
|
||||
|
||||
- src: release/config/sing-box.initd
|
||||
dst: /etc/init.d/sing-box
|
||||
|
||||
- src: release/completions/sing-box.bash
|
||||
dst: /usr/share/bash-completion/completions/sing-box.bash
|
||||
- src: release/completions/sing-box.fish
|
||||
dst: /usr/share/fish/vendor_completions.d/sing-box.fish
|
||||
- src: release/completions/sing-box.zsh
|
||||
dst: /usr/share/zsh/site-functions/_sing-box
|
||||
|
||||
- src: LICENSE
|
||||
dst: /usr/share/licenses/sing-box/LICENSE
|
||||
ipk:
|
||||
contents:
|
||||
- src: release/config/config.json
|
||||
dst: /etc/sing-box/config.json
|
||||
type: config
|
||||
|
||||
- src: release/config/openwrt.init
|
||||
dst: /etc/init.d/sing-box
|
||||
- src: release/config/openwrt.conf
|
||||
dst: /etc/config/sing-box
|
||||
source:
|
||||
enabled: false
|
||||
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
|
||||
|
||||
7
Makefile
7
Makefile
@@ -27,6 +27,9 @@ ci_build:
|
||||
go build $(PARAMS) $(MAIN)
|
||||
go build $(MAIN_PARAMS) $(MAIN)
|
||||
|
||||
generate_completions:
|
||||
go run -v --tags generate,generate_completions $(MAIN)
|
||||
|
||||
install:
|
||||
go build -o $(PREFIX)/bin/$(NAME) $(MAIN_PARAMS) $(MAIN)
|
||||
|
||||
@@ -66,7 +69,6 @@ release:
|
||||
dist/*.deb \
|
||||
dist/*.rpm \
|
||||
dist/*_amd64.pkg.tar.zst \
|
||||
dist/*_amd64v3.pkg.tar.zst \
|
||||
dist/*_arm64.pkg.tar.zst \
|
||||
dist/release
|
||||
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
|
||||
@@ -145,7 +147,6 @@ build_macos_dmg:
|
||||
--hide-extension "SFM.app" \
|
||||
--app-drop-link 0 0 \
|
||||
--skip-jenkins \
|
||||
--codesign "B2324162A090F01F96111CF802A83F0F36674F80" \
|
||||
--notarize "notarytool-password" \
|
||||
"../sing-box/dist/SFM/SFM.dmg" "build/SFM.System/SFM.app"
|
||||
|
||||
@@ -170,7 +171,7 @@ release_tvos: build_tvos upload_tvos_app_store
|
||||
update_apple_version:
|
||||
go run ./cmd/internal/update_apple_version
|
||||
|
||||
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos
|
||||
release_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
|
||||
|
||||
|
||||
Submodule clients/android updated: dcf6e1f20a...2aa661d507
Submodule clients/apple updated: 8b5ad1928f...c223f50ffb
@@ -27,7 +27,7 @@ func main() {
|
||||
objectsMap := project["objects"].(map[string]any)
|
||||
projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
|
||||
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfavt"}, newVersion.VersionString())
|
||||
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfa.standalone", "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 {
|
||||
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
|
||||
|
||||
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")
|
||||
}
|
||||
import "github.com/sagernet/sing-box/log"
|
||||
|
||||
func main() {
|
||||
if err := mainCommand.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func preRun(cmd *cobra.Command, args []string) {
|
||||
globalCtx = context.Background()
|
||||
sudoUser := os.Getenv("SUDO_USER")
|
||||
sudoUID, _ := strconv.Atoi(os.Getenv("SUDO_UID"))
|
||||
sudoGID, _ := strconv.Atoi(os.Getenv("SUDO_GID"))
|
||||
if sudoUID == 0 && sudoGID == 0 && sudoUser != "" {
|
||||
sudoUserObject, _ := user.Lookup(sudoUser)
|
||||
if sudoUserObject != nil {
|
||||
sudoUID, _ = strconv.Atoi(sudoUserObject.Uid)
|
||||
sudoGID, _ = strconv.Atoi(sudoUserObject.Gid)
|
||||
}
|
||||
}
|
||||
if sudoUID > 0 && sudoGID > 0 {
|
||||
globalCtx = filemanager.WithDefault(globalCtx, "", "", sudoUID, sudoGID)
|
||||
}
|
||||
if disableColor {
|
||||
log.SetStdLogger(log.NewDefaultFactory(context.Background(), log.Formatter{BaseTime: time.Now(), DisableColors: true}, os.Stderr, "", nil, false).Logger())
|
||||
}
|
||||
if workingDir != "" {
|
||||
_, err := os.Stat(workingDir)
|
||||
if err != nil {
|
||||
filemanager.MkdirAll(globalCtx, workingDir, 0o777)
|
||||
}
|
||||
err = os.Chdir(workingDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
if len(configPaths) == 0 && len(configDirectories) == 0 {
|
||||
configPaths = append(configPaths, "config.json")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,21 +40,27 @@ func PeekStream(ctx context.Context, metadata *adapter.InboundContext, conn net.
|
||||
}
|
||||
deadline := time.Now().Add(timeout)
|
||||
var errors []error
|
||||
err := conn.SetReadDeadline(deadline)
|
||||
if err != nil {
|
||||
return E.Cause(err, "set read deadline")
|
||||
}
|
||||
defer conn.SetReadDeadline(time.Time{})
|
||||
for _, sniffer := range sniffers {
|
||||
if buffer.IsEmpty() {
|
||||
err = sniffer(ctx, metadata, io.TeeReader(conn, buffer))
|
||||
} else {
|
||||
err = sniffer(ctx, metadata, io.MultiReader(bytes.NewReader(buffer.Bytes()), io.TeeReader(conn, buffer)))
|
||||
for i := 0; ; i++ {
|
||||
err := conn.SetReadDeadline(deadline)
|
||||
if err != nil {
|
||||
return E.Cause(err, "set read deadline")
|
||||
}
|
||||
if err == nil {
|
||||
return nil
|
||||
_, err = buffer.ReadOnceFrom(conn)
|
||||
_ = conn.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
if i > 0 {
|
||||
break
|
||||
}
|
||||
return E.Cause(err, "read payload")
|
||||
}
|
||||
errors = nil
|
||||
for _, sniffer := range sniffers {
|
||||
err = sniffer(ctx, metadata, bytes.NewReader(buffer.Bytes()))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
return E.Errors(errors...)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ const (
|
||||
ruleItemWIFISSID
|
||||
ruleItemWIFIBSSID
|
||||
ruleItemAdGuardDomain
|
||||
ruleItemProcessPathRegex
|
||||
ruleItemFinal uint8 = 0xFF
|
||||
)
|
||||
|
||||
@@ -207,6 +208,8 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
||||
rule.ProcessName, err = readRuleItemString(reader)
|
||||
case ruleItemProcessPath:
|
||||
rule.ProcessPath, err = readRuleItemString(reader)
|
||||
case ruleItemProcessPathRegex:
|
||||
rule.ProcessPathRegex, err = readRuleItemString(reader)
|
||||
case ruleItemPackageName:
|
||||
rule.PackageName, err = readRuleItemString(reader)
|
||||
case ruleItemWIFISSID:
|
||||
@@ -326,6 +329,12 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(rule.ProcessPathRegex) > 0 {
|
||||
err = writeRuleItemString(writer, ruleItemProcessPathRegex, rule.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(rule.PackageName) > 0 {
|
||||
err = writeRuleItemString(writer, ruleItemPackageName, rule.PackageName)
|
||||
if err != nil {
|
||||
|
||||
@@ -217,18 +217,10 @@ func init() {
|
||||
|
||||
func uTLSClientHelloID(name string) (utls.ClientHelloID, error) {
|
||||
switch name {
|
||||
case "chrome_psk", "chrome_psk_shuffle", "chrome_padding_psk_shuffle", "chrome_pq":
|
||||
fallthrough
|
||||
case "chrome", "":
|
||||
return utls.HelloChrome_Auto, nil
|
||||
case "chrome_psk":
|
||||
return utls.HelloChrome_100_PSK, nil
|
||||
case "chrome_psk_shuffle":
|
||||
return utls.HelloChrome_112_PSK_Shuf, nil
|
||||
case "chrome_padding_psk_shuffle":
|
||||
return utls.HelloChrome_114_Padding_PSK_Shuf, nil
|
||||
case "chrome_pq":
|
||||
return utls.HelloChrome_115_PQ, nil
|
||||
case "chrome_pq_psk":
|
||||
return utls.HelloChrome_115_PQ_PSK, nil
|
||||
case "firefox":
|
||||
return utls.HelloFirefox_Auto, nil
|
||||
case "edge":
|
||||
|
||||
@@ -2,7 +2,31 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.10.0-beta.9
|
||||
#### 1.10.0-beta.12
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.9.7
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.10.0-beta.11
|
||||
|
||||
* Update uTLS to v1.6.7 **1**
|
||||
* Add ipk in release artifacts
|
||||
|
||||
**1**:
|
||||
|
||||
Some legacy chrome fingerprints have been removed and will fallback to chrome, see [utls](/configuration/shared/tls#utls).
|
||||
|
||||
#### 1.10.0-beta.10
|
||||
|
||||
* Add `process_path_regex` rule item
|
||||
* Fixes and improvements
|
||||
|
||||
_The macOS standalone versions of sing-box (>=1.9.5/<1.10.0-beta.11) now silently fail and require manual granting of the **Full Disk Access** permission to system extension to start, probably due to Apple's changed security policy. We will prompt users about this in feature versions._
|
||||
|
||||
### 1.9.6
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
@@ -23,9 +47,7 @@ icon: material/alert-decagram
|
||||
|
||||
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
|
||||
We are still working on getting all sing-box apps back on the App Store, which should be completed within a week
|
||||
(SFI on the App Store and others on TestFlight are already available).
|
||||
|
||||
#### 1.10.0-beta.8
|
||||
|
||||
@@ -40,6 +40,7 @@ SFA provides an unprivileged TUN implementation through Android VpnService.
|
||||
|-----------------------|------------------|-----------------------------------|
|
||||
| `process_name` | :material-close: | No permission |
|
||||
| `process_path` | :material-close: | No permission |
|
||||
| `process_path_regex` | :material-close: | No permission |
|
||||
| `package_name` | :material-check: | / |
|
||||
| `user` | :material-close: | Use `package_name` instead |
|
||||
| `user_id` | :material-close: | Use `package_name` instead |
|
||||
|
||||
@@ -42,6 +42,7 @@ SFI/SFM/SFT provides an unprivileged TUN implementation through NetworkExtension
|
||||
|-----------------------|------------------|-----------------------|
|
||||
| `process_name` | :material-close: | No permission |
|
||||
| `process_path` | :material-close: | No permission |
|
||||
| `process_path_regex` | :material-close: | No permission |
|
||||
| `package_name` | :material-close: | / |
|
||||
| `user` | :material-close: | No permission |
|
||||
| `user_id` | :material-close: | No permission |
|
||||
|
||||
@@ -7,12 +7,6 @@ icon: material/apple
|
||||
SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides
|
||||
platform-specific function implementation, such as TUN transparent proxy implementation.
|
||||
|
||||
!!! failure "Unavailable"
|
||||
|
||||
Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
||||
|
||||
We are working on getting sing-box apps back on the App Store, which should be completed within a week (SFI on the App Store and others on TestFlight are already available).
|
||||
|
||||
## :material-graph: Requirements
|
||||
|
||||
* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+
|
||||
|
||||
@@ -6,7 +6,8 @@ icon: material/new-box
|
||||
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
@@ -103,6 +104,9 @@ icon: material/new-box
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -268,6 +272,16 @@ Match process name.
|
||||
|
||||
Match process path.
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
Match process path using regular expression.
|
||||
|
||||
#### package_name
|
||||
|
||||
Match android package name.
|
||||
|
||||
@@ -6,7 +6,8 @@ icon: material/new-box
|
||||
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
@@ -103,6 +104,9 @@ icon: material/new-box
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -266,6 +270,16 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
匹配进程路径。
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS.
|
||||
|
||||
使用正则表达式匹配进程路径。
|
||||
|
||||
#### package_name
|
||||
|
||||
匹配 Android 应用包名。
|
||||
|
||||
@@ -47,7 +47,7 @@ TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
||||
|
||||
#### fallback
|
||||
|
||||
!!! quote ""
|
||||
!!! failure ""
|
||||
|
||||
There is no evidence that GFW detects and blocks Trojan servers based on HTTP responses, and opening the standard http/s port on the server is a much bigger signature.
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ icon: material/alert-decagram
|
||||
|
||||
!!! quote "Changes in sing-box 1.10.0"
|
||||
|
||||
:material-plus: [client](#client)
|
||||
:material-plus: [client](#client)
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
@@ -101,6 +102,9 @@ icon: material/alert-decagram
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -277,6 +281,16 @@ Match process name.
|
||||
|
||||
Match process path.
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
Match process path using regular expression.
|
||||
|
||||
#### package_name
|
||||
|
||||
Match android package name.
|
||||
|
||||
@@ -6,7 +6,8 @@ icon: material/alert-decagram
|
||||
|
||||
:material-plus: [client](#client)
|
||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
|
||||
:material-plus: [process_path_regex](#process_path_regex)
|
||||
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
@@ -99,6 +100,9 @@ icon: material/alert-decagram
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -275,6 +279,16 @@ icon: material/alert-decagram
|
||||
|
||||
匹配进程路径。
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "自 sing-box 1.10.0 起"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅支持 Linux、Windows 和 macOS.
|
||||
|
||||
使用正则表达式匹配进程路径。
|
||||
|
||||
#### package_name
|
||||
|
||||
匹配 Android 应用包名。
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
"process_path": [
|
||||
"/usr/bin/curl"
|
||||
],
|
||||
"process_path_regex": [
|
||||
"^/usr/bin/.+"
|
||||
],
|
||||
"package_name": [
|
||||
"com.termux"
|
||||
],
|
||||
@@ -160,6 +163,16 @@ Match process name.
|
||||
|
||||
Match process path.
|
||||
|
||||
#### process_path_regex
|
||||
|
||||
!!! question "Since sing-box 1.10.0"
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported on Linux, Windows, and macOS.
|
||||
|
||||
Match process path using regular expression.
|
||||
|
||||
#### package_name
|
||||
|
||||
Match android package name.
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.10.0"
|
||||
|
||||
:material-alert-decagram: [utls](#utls)
|
||||
|
||||
@@ -210,28 +214,25 @@ The path to the server private key, in PEM format.
|
||||
|
||||
==Client only==
|
||||
|
||||
!!! note ""
|
||||
|
||||
uTLS is poorly maintained and the effect may be unproven, use at your own risk.
|
||||
!!! failure ""
|
||||
|
||||
There is no evidence that GFW detects and blocks servers based on TLS client fingerprinting, and using an imperfect emulation that has not been security reviewed could pose security risks.
|
||||
|
||||
uTLS is a fork of "crypto/tls", which provides ClientHello fingerprinting resistance.
|
||||
|
||||
Available fingerprint values:
|
||||
|
||||
!!! question "Since sing-box 1.8.0"
|
||||
!!! warning "Removed since sing-box 1.10.0"
|
||||
|
||||
:material-plus: chrome_psk
|
||||
:material-plus: chrome_psk_shuffle
|
||||
:material-plus: chrome_padding_psk_shuffle
|
||||
:material-plus: chrome_pq
|
||||
:material-plus: chrome_pq_psk
|
||||
Some legacy chrome fingerprints have been removed and will fallback to chrome:
|
||||
|
||||
:material-close: chrome_psk
|
||||
:material-close: chrome_psk_shuffle
|
||||
:material-close: chrome_padding_psk_shuffle
|
||||
:material-close: chrome_pq
|
||||
:material-close: chrome_pq_psk
|
||||
|
||||
* chrome
|
||||
* chrome_psk
|
||||
* chrome_psk_shuffle
|
||||
* chrome_padding_psk_shuffle
|
||||
* chrome_pq
|
||||
* chrome_pq_psk
|
||||
* firefox
|
||||
* edge
|
||||
* safari
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.10.0 中的更改"
|
||||
|
||||
:material-alert-decagram: [utls](#utls)
|
||||
|
||||
@@ -44,8 +48,8 @@
|
||||
"handshake": {
|
||||
"server": "google.com",
|
||||
"server_port": 443,
|
||||
|
||||
... // 拨号字段
|
||||
...
|
||||
// 拨号字段
|
||||
},
|
||||
"private_key": "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc",
|
||||
"short_id": [
|
||||
@@ -202,28 +206,25 @@ TLS 版本值:
|
||||
|
||||
==仅客户端==
|
||||
|
||||
!!! note ""
|
||||
!!! failure ""
|
||||
|
||||
uTLS 维护不善且其效果可能未经证实,使用风险自负。
|
||||
没有证据表明 GFW 根据 TLS 客户端指纹检测并阻止服务器,并且,使用一个未经安全审查的不完美模拟可能带来安全隐患。
|
||||
|
||||
uTLS 是 "crypto/tls" 的一个分支,它提供了 ClientHello 指纹识别阻力。
|
||||
|
||||
可用的指纹值:
|
||||
|
||||
!!! question "自 sing-box 1.8.0 起"
|
||||
!!! warning "已在 sing-box 1.10.0 移除"
|
||||
|
||||
:material-plus: chrome_psk
|
||||
:material-plus: chrome_psk_shuffle
|
||||
:material-plus: chrome_padding_psk_shuffle
|
||||
:material-plus: chrome_pq
|
||||
:material-plus: chrome_pq_psk
|
||||
一些旧 chrome 指纹已被删除,并将会退到 chrome:
|
||||
|
||||
:material-close: chrome_psk
|
||||
:material-close: chrome_psk_shuffle
|
||||
:material-close: chrome_padding_psk_shuffle
|
||||
:material-close: chrome_pq
|
||||
:material-close: chrome_pq_psk
|
||||
|
||||
* chrome
|
||||
* chrome_psk
|
||||
* chrome_psk_shuffle
|
||||
* chrome_padding_psk_shuffle
|
||||
* chrome_pq
|
||||
* chrome_pq_psk
|
||||
* firefox
|
||||
* edge
|
||||
* safari
|
||||
|
||||
@@ -87,12 +87,12 @@ icon: material/package
|
||||
|
||||
## :material-alert: Problematic Sources
|
||||
|
||||
| Type | Platform | Link | Promblem(s) |
|
||||
|------------|----------|-------------------------------------------------------------------------------------------|------------------------------------------------------------------|
|
||||
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | Problematic build tag list modification; Not actively maintained |
|
||||
| Homebrew | / | [homebrew-core][brew] | Problematic build tag list modification |
|
||||
| Termux | Android | [termux-packages][termux] | Problematic build tag list modification |
|
||||
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | Old Go (go1.20) |
|
||||
| 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:
|
||||
|
||||
|
||||
@@ -85,15 +85,14 @@ icon: material/package
|
||||
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
|
||||
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||
|
||||
|
||||
## :material-alert: 存在问题的源
|
||||
|
||||
| 类型 | 平台 | 链接 | 原因 |
|
||||
|------------|---------|-------------------------------------------------------------------------------------------|-----------------------|
|
||||
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改; 没有活跃维护 |
|
||||
| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 |
|
||||
| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 |
|
||||
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) |
|
||||
| 类型 | 平台 | 链接 | 原因 |
|
||||
|------------|---------|-------------------------------------------------------------------------------------------|-----------------|
|
||||
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改 |
|
||||
| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 |
|
||||
| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 |
|
||||
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) |
|
||||
|
||||
如果您是其用户,请向他们报告问题:
|
||||
|
||||
|
||||
3
go.mod
3
go.mod
@@ -37,7 +37,7 @@ require (
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.16
|
||||
github.com/sagernet/sing-vmess v0.1.12
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||
github.com/sagernet/utls v1.5.4
|
||||
github.com/sagernet/utls v1.6.7
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||
github.com/spf13/cobra v1.8.0
|
||||
@@ -61,7 +61,6 @@ require (
|
||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gaukas/godicttls v0.0.4 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@@ -17,8 +17,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
|
||||
github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
|
||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
@@ -137,8 +135,8 @@ github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEY
|
||||
github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
|
||||
github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co=
|
||||
github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s=
|
||||
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
|
||||
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8/go.mod h1:K4J7/npM+VAMUeUmTa2JaA02JmyheP0GpRBOUvn3ecc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
|
||||
@@ -88,6 +88,7 @@ type _DefaultRule struct {
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
User Listable[string] `json:"user,omitempty"`
|
||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
||||
|
||||
@@ -88,6 +88,7 @@ type _DefaultDNSRule struct {
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
User Listable[string] `json:"user,omitempty"`
|
||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
||||
|
||||
@@ -144,24 +144,25 @@ func (r HeadlessRule) IsValid() bool {
|
||||
}
|
||||
|
||||
type DefaultHeadlessRule struct {
|
||||
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||
Network Listable[string] `json:"network,omitempty"`
|
||||
Domain Listable[string] `json:"domain,omitempty"`
|
||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
||||
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
|
||||
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
|
||||
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
|
||||
SourcePort Listable[uint16] `json:"source_port,omitempty"`
|
||||
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
|
||||
Port Listable[uint16] `json:"port,omitempty"`
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||
Network Listable[string] `json:"network,omitempty"`
|
||||
Domain Listable[string] `json:"domain,omitempty"`
|
||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
||||
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
|
||||
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
|
||||
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
|
||||
SourcePort Listable[uint16] `json:"source_port,omitempty"`
|
||||
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
|
||||
Port Listable[uint16] `json:"port,omitempty"`
|
||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
|
||||
DomainMatcher *domain.Matcher `json:"-"`
|
||||
SourceIPSet *netipx.IPSet `json:"-"`
|
||||
|
||||
@@ -120,7 +120,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||
var group task.Group
|
||||
group.Append0(func(ctx context.Context) error {
|
||||
group.Append0(func(_ context.Context) error {
|
||||
for {
|
||||
var message mDNS.Msg
|
||||
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 {
|
||||
ctx = adapter.WithContext(ctx, &metadata)
|
||||
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||
var group task.Group
|
||||
group.Append0(func(ctx context.Context) error {
|
||||
group.Append0(func(_ context.Context) error {
|
||||
for {
|
||||
var (
|
||||
message mDNS.Msg
|
||||
|
||||
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 $?
|
||||
}
|
||||
@@ -1021,16 +1021,14 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
)
|
||||
} else {
|
||||
err = sniff.PeekPacket(
|
||||
ctx,
|
||||
&metadata,
|
||||
ctx, &metadata,
|
||||
buffer.Bytes(),
|
||||
sniff.DomainNameQuery,
|
||||
sniff.QUICClientHello,
|
||||
sniff.STUNMessage,
|
||||
sniff.UTP,
|
||||
sniff.UDPTracker,
|
||||
sniff.DTLSRecord,
|
||||
)
|
||||
sniff.DTLSRecord)
|
||||
}
|
||||
if E.IsMulti(err, sniff.ErrClientHelloFragmented) && len(bufferList) == 0 {
|
||||
bufferList = append(bufferList, buffer)
|
||||
@@ -1055,8 +1053,6 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
|
||||
}
|
||||
for _, cachedBuffer := range common.Reverse(bufferList) {
|
||||
|
||||
@@ -179,6 +179,14 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.ProcessPathRegex) > 0 {
|
||||
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "process_path_regex")
|
||||
}
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.PackageName) > 0 {
|
||||
item := NewPackageNameItem(options.PackageName)
|
||||
rule.items = append(rule.items, item)
|
||||
|
||||
@@ -183,6 +183,14 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.ProcessPathRegex) > 0 {
|
||||
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "process_path_regex")
|
||||
}
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.PackageName) > 0 {
|
||||
item := NewPackageNameItem(options.PackageName)
|
||||
rule.items = append(rule.items, item)
|
||||
|
||||
@@ -123,6 +123,14 @@ func NewDefaultHeadlessRule(router adapter.Router, options option.DefaultHeadles
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.ProcessPathRegex) > 0 {
|
||||
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "process_path_regex")
|
||||
}
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.PackageName) > 0 {
|
||||
item := NewPackageNameItem(options.PackageName)
|
||||
rule.items = append(rule.items, item)
|
||||
|
||||
54
route/rule_item_process_path_regex.go
Normal file
54
route/rule_item_process_path_regex.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
var _ RuleItem = (*ProcessPathRegexItem)(nil)
|
||||
|
||||
type ProcessPathRegexItem struct {
|
||||
matchers []*regexp.Regexp
|
||||
description string
|
||||
}
|
||||
|
||||
func NewProcessPathRegexItem(expressions []string) (*ProcessPathRegexItem, error) {
|
||||
matchers := make([]*regexp.Regexp, 0, len(expressions))
|
||||
for i, regex := range expressions {
|
||||
matcher, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "parse expression ", i)
|
||||
}
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
description := "process_path_regex="
|
||||
eLen := len(expressions)
|
||||
if eLen == 1 {
|
||||
description += expressions[0]
|
||||
} else if eLen > 3 {
|
||||
description += F.ToString("[", strings.Join(expressions[:3], " "), "]")
|
||||
} else {
|
||||
description += F.ToString("[", strings.Join(expressions, " "), "]")
|
||||
}
|
||||
return &ProcessPathRegexItem{matchers, description}, nil
|
||||
}
|
||||
|
||||
func (r *ProcessPathRegexItem) Match(metadata *adapter.InboundContext) bool {
|
||||
if metadata.ProcessInfo == nil || metadata.ProcessInfo.ProcessPath == "" {
|
||||
return false
|
||||
}
|
||||
for _, matcher := range r.matchers {
|
||||
if matcher.MatchString(metadata.ProcessInfo.ProcessPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *ProcessPathRegexItem) String() string {
|
||||
return r.description
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
func NewRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) (adapter.RuleSet, error) {
|
||||
switch options.Type {
|
||||
case C.RuleSetTypeInline, C.RuleSetTypeLocal, "":
|
||||
return NewLocalRuleSet(router, logger, options)
|
||||
return NewLocalRuleSet(ctx, router, logger, options)
|
||||
case C.RuleSetTypeRemote:
|
||||
return NewRemoteRuleSet(ctx, router, logger, options), nil
|
||||
default:
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
@@ -35,7 +36,7 @@ type LocalRuleSet struct {
|
||||
refs atomic.Int32
|
||||
}
|
||||
|
||||
func NewLocalRuleSet(router adapter.Router, logger logger.Logger, options option.RuleSet) (*LocalRuleSet, error) {
|
||||
func NewLocalRuleSet(ctx context.Context, router adapter.Router, logger logger.Logger, options option.RuleSet) (*LocalRuleSet, error) {
|
||||
ruleSet := &LocalRuleSet{
|
||||
router: router,
|
||||
logger: logger,
|
||||
@@ -51,7 +52,7 @@ func NewLocalRuleSet(router adapter.Router, logger logger.Logger, options option
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
err := ruleSet.reloadFile(options.LocalOptions.Path)
|
||||
err := ruleSet.reloadFile(filemanager.BasePath(ctx, options.LocalOptions.Path))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func NewSystemDevice(router adapter.Router, interfaceName string, localPrefixes
|
||||
inet4Addresses: inet4Addresses,
|
||||
inet6Addresses: inet6Addresses,
|
||||
gso: gso,
|
||||
events: make(chan wgTun.Event),
|
||||
events: make(chan wgTun.Event, 1),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user