Compare commits

..

42 Commits

Author SHA1 Message Date
renovate[bot]
05a431d203 [dependencies] Update actions/checkout digest to eef6144 2024-10-07 18:49:40 +00:00
世界
e68a9e623f documentation: Bump version 2024-10-07 04:58:58 +08:00
世界
a9bb07db4a Update utls to v1.6.7 2024-10-07 04:58:58 +08:00
srk24
a07219d16d Add process_path_regex rule type 2024-10-07 04:58:58 +08:00
世界
6362b778c9 clash-api: Add PNA support 2024-10-07 04:58:57 +08:00
世界
cb46b648d7 Add RDP sniffer 2024-10-07 04:58:57 +08:00
世界
04613c27e2 Add SSH sniffer 2024-10-07 04:58:57 +08:00
世界
795e1cf2f0 Write close error to log 2024-10-07 04:58:56 +08:00
世界
1e36c75336 Add AdGuard DNS filter support 2024-10-07 04:58:56 +08:00
世界
5a2c7037fe Improve QUIC sniffer 2024-10-07 04:58:56 +08:00
世界
852c07c050 Add inline rule-set & Add reload for local rule-set 2024-10-07 04:58:56 +08:00
世界
c2ab497ff4 Unique rule-set names 2024-10-07 04:58:54 +08:00
世界
1e3c136440 Add accept empty DNS rule option 2024-10-07 04:58:54 +08:00
世界
7a2cd77798 Add custom options for TUN auto-route and auto-redirect 2024-10-07 04:58:54 +08:00
世界
1cdaea49b6 Improve base DNS transports & Minor fixes 2024-10-07 04:58:53 +08:00
世界
a50b0bc1a9 Add auto-redirect & Improve auto-route 2024-10-07 04:58:53 +08:00
世界
00e6210928 Add rule-set decompile command 2024-10-07 04:58:53 +08:00
世界
2dbeb63b4e Add IP address support for rule-set match match 2024-10-07 04:58:52 +08:00
世界
744cc985ba Improve usages of json.Unmarshal 2024-10-07 04:58:52 +08:00
世界
bd122478fc Bump rule-set version 2024-10-07 04:58:51 +08:00
世界
a18179ad24 Implement read deadline for QUIC based UDP inbounds 2024-10-07 04:58:50 +08:00
世界
388c75a815 WTF is this 2024-10-07 04:58:50 +08:00
世界
8d0d49c388 platform: Fix clash server reload on android 2024-10-07 04:58:50 +08:00
世界
03f5d6e4f2 platform: Add log update interval 2024-10-07 04:58:50 +08:00
世界
25065d766a platform: Prepare connections list 2024-10-07 04:58:49 +08:00
世界
d44e7d9834 Drop support for go1.18 and go1.19 2024-10-07 04:58:48 +08:00
世界
369bc7cea3 Add DTLS sniffer 2024-10-07 04:58:48 +08:00
iosmanthus
4b7a83da16 Introduce bittorrent related protocol sniffers
* Introduce bittorrent related protocol sniffers

including, sniffers of
1. BitTorrent Protocol (TCP)
2. uTorrent Transport Protocol (UDP)

Signed-off-by: iosmanthus <myosmanthustree@gmail.com>
Co-authored-by: 世界 <i@sekai.icu>
2024-10-07 04:58:48 +08:00
世界
0f7154afbd Update workflow to go1.23 2024-10-07 04:58:47 +08:00
世界
a06d10c3bc Bump version 2024-10-07 04:34:48 +08:00
世界
63cc6cc76c Fix Makefile 2024-10-07 04:34:48 +08:00
世界
d55c5b5cab documentation: Update package status 2024-10-07 04:34:48 +08:00
世界
b624c2dcc7 Fix context used by DNS outbounds 2024-10-07 04:34:48 +08:00
世界
9415444ebd Fix base path not applied to local rule-sets 2024-10-07 04:34:48 +08:00
世界
95606191d8 Add completions for linux packages 2024-10-07 04:34:48 +08:00
世界
e586d9e9bc Bump version 2024-09-20 23:37:06 +08:00
世界
8c7eaa4477 Fix docker build 2024-09-20 23:37:06 +08:00
世界
8464c8cb7c Fix version script 2024-09-20 21:10:15 +08:00
世界
39d7127651 Revert "Fix stream sniffer" 2024-09-20 20:40:02 +08:00
世界
e2077009c4 documentation: Update client status 2024-09-20 20:13:55 +08:00
世界
700a8eb425 Minor fixes 2024-09-20 20:13:14 +08:00
世界
3b0cba0852 Fix wireguard start 2024-09-20 20:12:52 +08:00
50 changed files with 2513 additions and 212 deletions

View File

@@ -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

View File

@@ -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 }}

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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'

View File

@@ -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

View File

@@ -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
View 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")
}
}

View 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
}

View File

@@ -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")
}
}

View File

@@ -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...)
}

View File

@@ -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 {

View File

@@ -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":

View File

@@ -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

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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+

View File

@@ -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.

View File

@@ -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 应用包名。

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 应用包名。

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -85,15 +85,14 @@ icon: material/package
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
| FreshPorts | FreeBSD | `pkg install sing-box` | [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/sing-box.svg)][ports] |
## :material-alert: 存在问题的源
| 类型 | 平台 | 链接 | 原因 |
|------------|---------|-------------------------------------------------------------------------------------------|-----------------------|
| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改; 没有活跃维护 |
| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 |
| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 |
| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) |
| 类型 | 平台 | 链接 | 原因 |
|------------|---------|-------------------------------------------------------------------------------------------|-----------------|
| 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
View File

@@ -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
View File

@@ -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=

View File

@@ -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"`

View File

@@ -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"`

View File

@@ -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:"-"`

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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'

View 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

View 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'

View 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"
}

View 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 $?
}

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View 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
}

View File

@@ -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:

View File

@@ -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
}

View File

@@ -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
}