mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-12 01:57:18 +10:00
Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3066dfe3b3 | ||
|
|
1128fdd8c7 | ||
|
|
cfd9879b17 | ||
|
|
9ceb660c57 | ||
|
|
7d00d7df28 | ||
|
|
21b1ac26b9 | ||
|
|
7fec8d842e | ||
|
|
07c678fb85 | ||
|
|
baecfc7778 | ||
|
|
07de36ecdb | ||
|
|
2c8a8303cd | ||
|
|
e5991cae0b | ||
|
|
1349acfd5a | ||
|
|
98ff897f35 | ||
|
|
6144c8e340 | ||
|
|
c8caac9f67 | ||
|
|
81e9eda357 | ||
|
|
7cba3da108 | ||
|
|
82d06b43e7 | ||
|
|
a7ac91f573 | ||
|
|
0540a95a43 | ||
|
|
94707dfcdd | ||
|
|
8a17043502 | ||
|
|
b0aaa86806 | ||
|
|
8a2d3fbb28 | ||
|
|
4652019608 | ||
|
|
06fa5abf63 | ||
|
|
996fbbf0c3 | ||
|
|
142ff1b455 | ||
|
|
74d662f7a3 | ||
|
|
085f603377 | ||
|
|
460fae83dc | ||
|
|
bb9bd9bff6 | ||
|
|
c2354ebf25 | ||
|
|
c1f4755c4e | ||
|
|
0ca5909b06 | ||
|
|
e77a8114c5 | ||
|
|
f1393235ff | ||
|
|
bdba2365de | ||
|
|
ce0da5b557 | ||
|
|
3853201412 | ||
|
|
7003ef40a3 | ||
|
|
59ec92228c | ||
|
|
0eeb2da323 | ||
|
|
977b0fac02 | ||
|
|
51964801ff | ||
|
|
e08c052fc9 | ||
|
|
53927d8bbd | ||
|
|
968b9bc217 | ||
|
|
69dc87aa6d | ||
|
|
4193df375f | ||
|
|
5ff7006326 | ||
|
|
a89107ea9d | ||
|
|
9ffdbba2ed | ||
|
|
65c71049ea | ||
|
|
7d4e6a7f4e | ||
|
|
d612620c5d | ||
|
|
8a9a77a438 | ||
|
|
a2098c18e1 | ||
|
|
cf2181dd3a | ||
|
|
5899e95ff1 | ||
|
|
d7160c19cf | ||
|
|
da9e22b4e6 | ||
|
|
0e120f8a44 | ||
|
|
d918863ac5 | ||
|
|
2ae192305c | ||
|
|
71d1879bd6 | ||
|
|
917514e09f | ||
|
|
5327aeaea4 | ||
|
|
93ae3f7a1e | ||
|
|
f24a2aed7d | ||
|
|
0517ceef76 | ||
|
|
830ea46932 | ||
|
|
cd0fcd5ddc | ||
|
|
003176f069 | ||
|
|
71d92518c1 | ||
|
|
b5dcd6bf59 | ||
|
|
11c7b4a866 | ||
|
|
ee14135298 | ||
|
|
cbcf005f37 | ||
|
|
daee0b154e | ||
|
|
d530c724c0 | ||
|
|
7f698c1104 | ||
|
|
7a4a44c6d2 | ||
|
|
44277e5dd2 | ||
|
|
1f470c69c4 |
8
.github/workflows/debug.yml
vendored
8
.github/workflows/debug.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -208,7 +208,7 @@ jobs:
|
||||
TAGS: with_clash_api,with_quic
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
33
.github/workflows/docker.yml
vendored
33
.github/workflows/docker.yml
vendored
@@ -4,13 +4,35 @@ on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "The tag version you want to build"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get commit to build
|
||||
id: ref
|
||||
run: |-
|
||||
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
|
||||
ref="${{ github.ref_name }}"
|
||||
else
|
||||
ref="${{ github.event.inputs.tag }}"
|
||||
fi
|
||||
echo "ref=$ref"
|
||||
echo "ref=$ref" >> $GITHUB_OUTPUT
|
||||
if [[ $ref == *"-"* ]]; then
|
||||
latest=latest-beta
|
||||
else
|
||||
latest=latest
|
||||
fi
|
||||
echo "latest=$latest"
|
||||
echo "latest=$latest" >> $GITHUB_OUTPUT
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
ref: ${{ steps.ref.outputs.ref }}
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Setup QEMU for Docker Buildx
|
||||
@@ -27,13 +49,14 @@ jobs:
|
||||
with:
|
||||
images: ghcr.io/sagernet/sing-box
|
||||
- name: Build and release Docker images
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/386,linux/amd64,linux/arm64,linux/s390x
|
||||
context: .
|
||||
target: dist
|
||||
build-args: |
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||
tags: |
|
||||
ghcr.io/sagernet/sing-box:latest
|
||||
ghcr.io/sagernet/sing-box:${{ github.ref_name }}
|
||||
ghcr.io/sagernet/sing-box:${{ steps.ref.outputs.latest }}
|
||||
ghcr.io/sagernet/sing-box:${{ steps.ref.outputs.ref }}
|
||||
push: true
|
||||
|
||||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
with:
|
||||
go-version: ^1.22
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v5
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=30m
|
||||
|
||||
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
EOF
|
||||
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||
- name: Publish release
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
with:
|
||||
distribution: goreleaser-pro
|
||||
version: latest
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,3 +14,5 @@
|
||||
/*.xcframework/
|
||||
.DS_Store
|
||||
/config.d/
|
||||
/venv/
|
||||
|
||||
|
||||
@@ -6,14 +6,7 @@ linters:
|
||||
- gci
|
||||
- staticcheck
|
||||
- paralleltest
|
||||
|
||||
run:
|
||||
skip-dirs:
|
||||
- transport/simple-obfs
|
||||
- transport/clashssr
|
||||
- transport/cloudflaretls
|
||||
- transport/shadowtls/tls
|
||||
- transport/shadowtls/tls_go119
|
||||
- ineffassign
|
||||
|
||||
linters-settings:
|
||||
gci:
|
||||
@@ -23,4 +16,13 @@ linters-settings:
|
||||
- prefix(github.com/sagernet/)
|
||||
- default
|
||||
staticcheck:
|
||||
go: '1.20'
|
||||
checks:
|
||||
- all
|
||||
- -SA1003
|
||||
|
||||
run:
|
||||
go: "1.23"
|
||||
|
||||
issues:
|
||||
exclude-dirs:
|
||||
- transport/simple-obfs
|
||||
|
||||
@@ -36,7 +36,6 @@ nfpms:
|
||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
builds:
|
||||
- main
|
||||
vendor: sagernet
|
||||
homepage: https://sing-box.sagernet.org/
|
||||
maintainer: nekohasekai <contact-git@sekai.icu>
|
||||
description: The universal proxy platform.
|
||||
|
||||
@@ -113,7 +113,6 @@ nfpms:
|
||||
file_name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
builds:
|
||||
- main
|
||||
vendor: sagernet
|
||||
homepage: https://sing-box.sagernet.org/
|
||||
maintainer: nekohasekai <contact-git@sekai.icu>
|
||||
description: The universal proxy platform.
|
||||
|
||||
8
Makefile
8
Makefile
@@ -197,13 +197,15 @@ lib_install:
|
||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.3
|
||||
|
||||
docs:
|
||||
mkdocs serve
|
||||
venv/bin/mkdocs serve
|
||||
|
||||
publish_docs:
|
||||
mkdocs gh-deploy -m "Update" --force --ignore-version --no-history
|
||||
venv/bin/mkdocs gh-deploy -m "Update" --force --ignore-version --no-history
|
||||
|
||||
docs_install:
|
||||
pip install --force-reinstall mkdocs-material=="9.*" mkdocs-static-i18n=="1.2.*"
|
||||
python -m venv venv
|
||||
source ./venv/bin/activate && pip install --force-reinstall mkdocs-material=="9.*" mkdocs-static-i18n=="1.2.*"
|
||||
|
||||
clean:
|
||||
rm -rf bin dist sing-box
|
||||
rm -f $(shell go env GOPATH)/sing-box
|
||||
|
||||
@@ -4,10 +4,6 @@ The universal proxy platform.
|
||||
|
||||
[](https://repology.org/project/sing-box/versions)
|
||||
|
||||
## Documentation
|
||||
|
||||
https://sing-box.sagernet.org
|
||||
|
||||
## Support
|
||||
|
||||
https://community.sagernet.org/c/sing-box/
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/common/urltest"
|
||||
"github.com/sagernet/sing-dns"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/rw"
|
||||
)
|
||||
@@ -30,6 +31,9 @@ type CacheFile interface {
|
||||
StoreFakeIP() bool
|
||||
FakeIPStorage
|
||||
|
||||
StoreRDRC() bool
|
||||
dns.RDRCStore
|
||||
|
||||
LoadMode() string
|
||||
StoreMode(mode string) error
|
||||
LoadSelected(group string) string
|
||||
|
||||
@@ -51,11 +51,13 @@ type InboundContext struct {
|
||||
|
||||
// rule cache
|
||||
|
||||
IPCIDRMatchSource bool
|
||||
SourceAddressMatch bool
|
||||
SourcePortMatch bool
|
||||
DestinationAddressMatch bool
|
||||
DestinationPortMatch bool
|
||||
IPCIDRMatchSource bool
|
||||
SourceAddressMatch bool
|
||||
SourcePortMatch bool
|
||||
DestinationAddressMatch bool
|
||||
DestinationPortMatch bool
|
||||
DidMatch bool
|
||||
IgnoreDestinationIPCIDRMatch bool
|
||||
}
|
||||
|
||||
func (c *InboundContext) ResetRuleCache() {
|
||||
@@ -64,6 +66,7 @@ func (c *InboundContext) ResetRuleCache() {
|
||||
c.SourcePortMatch = false
|
||||
c.DestinationAddressMatch = false
|
||||
c.DestinationPortMatch = false
|
||||
c.DidMatch = false
|
||||
}
|
||||
|
||||
type inboundContextKey struct{}
|
||||
|
||||
@@ -71,6 +71,7 @@ func RouterFromContext(ctx context.Context) Router {
|
||||
|
||||
type HeadlessRule interface {
|
||||
Match(metadata *InboundContext) bool
|
||||
String() string
|
||||
}
|
||||
|
||||
type Rule interface {
|
||||
@@ -79,18 +80,19 @@ type Rule interface {
|
||||
Type() string
|
||||
UpdateGeosite() error
|
||||
Outbound() string
|
||||
String() string
|
||||
}
|
||||
|
||||
type DNSRule interface {
|
||||
Rule
|
||||
DisableCache() bool
|
||||
RewriteTTL() *uint32
|
||||
ClientSubnet() *netip.Prefix
|
||||
WithAddressLimit() bool
|
||||
MatchAddressLimit(metadata *InboundContext) bool
|
||||
}
|
||||
|
||||
type RuleSet interface {
|
||||
StartContext(ctx context.Context, startContext RuleSetStartContext) error
|
||||
PostStart() error
|
||||
Metadata() RuleSetMetadata
|
||||
Close() error
|
||||
HeadlessRule
|
||||
@@ -99,6 +101,7 @@ type RuleSet interface {
|
||||
type RuleSetMetadata struct {
|
||||
ContainsProcessRule bool
|
||||
ContainsWIFIRule bool
|
||||
ContainsIPCIDRRule bool
|
||||
}
|
||||
|
||||
type RuleSetStartContext interface {
|
||||
|
||||
@@ -22,4 +22,5 @@ type V2RayServerTransportHandler interface {
|
||||
|
||||
type V2RayClientTransport interface {
|
||||
DialContext(ctx context.Context) (net.Conn, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
6
box.go
6
box.go
@@ -203,7 +203,7 @@ func (s *Box) PreStart() error {
|
||||
defer func() {
|
||||
v := recover()
|
||||
if v != nil {
|
||||
log.Error(E.Cause(err, "origin error"))
|
||||
println(err.Error())
|
||||
debug.PrintStack()
|
||||
panic("panic on early close: " + fmt.Sprint(v))
|
||||
}
|
||||
@@ -222,9 +222,9 @@ func (s *Box) Start() error {
|
||||
defer func() {
|
||||
v := recover()
|
||||
if v != nil {
|
||||
log.Error(E.Cause(err, "origin error"))
|
||||
println(err.Error())
|
||||
debug.PrintStack()
|
||||
panic("panic on early close: " + fmt.Sprint(v))
|
||||
println("panic on early start: " + fmt.Sprint(v))
|
||||
}
|
||||
}()
|
||||
s.Close()
|
||||
|
||||
Submodule clients/android updated: c0ce4cc97d...440aaa9a1a
Submodule clients/apple updated: 17eec08615...aa4ce98421
87
cmd/sing-box/cmd_rule_set_match.go
Normal file
87
cmd/sing-box/cmd_rule_set_match.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/srs"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/route"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var flagRuleSetMatchFormat string
|
||||
|
||||
var commandRuleSetMatch = &cobra.Command{
|
||||
Use: "match <rule-set path> <domain>",
|
||||
Short: "Check if a domain matches the rule set",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := ruleSetMatch(args[0], args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
commandRuleSetMatch.Flags().StringVarP(&flagRuleSetMatchFormat, "format", "f", "source", "rule-set format")
|
||||
commandRuleSet.AddCommand(commandRuleSetMatch)
|
||||
}
|
||||
|
||||
func ruleSetMatch(sourcePath string, domain string) error {
|
||||
var (
|
||||
reader io.Reader
|
||||
err error
|
||||
)
|
||||
if sourcePath == "stdin" {
|
||||
reader = os.Stdin
|
||||
} else {
|
||||
reader, err = os.Open(sourcePath)
|
||||
if err != nil {
|
||||
return E.Cause(err, "read rule-set")
|
||||
}
|
||||
}
|
||||
content, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return E.Cause(err, "read rule-set")
|
||||
}
|
||||
var plainRuleSet option.PlainRuleSet
|
||||
switch flagRuleSetMatchFormat {
|
||||
case C.RuleSetFormatSource:
|
||||
var compat option.PlainRuleSetCompat
|
||||
compat, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plainRuleSet = compat.Upgrade()
|
||||
case C.RuleSetFormatBinary:
|
||||
plainRuleSet, err = srs.Read(bytes.NewReader(content), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return E.New("unknown rule set format: ", flagRuleSetMatchFormat)
|
||||
}
|
||||
for i, ruleOptions := range plainRuleSet.Rules {
|
||||
var currentRule adapter.HeadlessRule
|
||||
currentRule, err = route.NewHeadlessRule(nil, ruleOptions)
|
||||
if err != nil {
|
||||
return E.Cause(err, "parse rule_set.rules.[", i, "]")
|
||||
}
|
||||
if currentRule.Match(&adapter.InboundContext{
|
||||
Domain: domain,
|
||||
}) {
|
||||
println(F.ToString("match rules.[", i, "]: ", currentRule))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -4,6 +4,8 @@ package badtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
@@ -18,20 +20,32 @@ import (
|
||||
var _ N.ReadWaiter = (*ReadWaitConn)(nil)
|
||||
|
||||
type ReadWaitConn struct {
|
||||
*tls.STDConn
|
||||
halfAccess *sync.Mutex
|
||||
rawInput *bytes.Buffer
|
||||
input *bytes.Reader
|
||||
hand *bytes.Buffer
|
||||
readWaitOptions N.ReadWaitOptions
|
||||
tls.Conn
|
||||
halfAccess *sync.Mutex
|
||||
rawInput *bytes.Buffer
|
||||
input *bytes.Reader
|
||||
hand *bytes.Buffer
|
||||
readWaitOptions N.ReadWaitOptions
|
||||
tlsReadRecord func() error
|
||||
tlsHandlePostHandshakeMessage func() error
|
||||
}
|
||||
|
||||
func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) {
|
||||
stdConn, isSTDConn := conn.(*tls.STDConn)
|
||||
if !isSTDConn {
|
||||
var (
|
||||
loaded bool
|
||||
tlsReadRecord func() error
|
||||
tlsHandlePostHandshakeMessage func() error
|
||||
)
|
||||
for _, tlsCreator := range tlsRegistry {
|
||||
loaded, tlsReadRecord, tlsHandlePostHandshakeMessage = tlsCreator(conn)
|
||||
if loaded {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !loaded {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
rawConn := reflect.Indirect(reflect.ValueOf(stdConn))
|
||||
rawConn := reflect.Indirect(reflect.ValueOf(conn))
|
||||
rawHalfConn := rawConn.FieldByName("in")
|
||||
if !rawHalfConn.IsValid() || rawHalfConn.Kind() != reflect.Struct {
|
||||
return nil, E.New("badtls: invalid half conn")
|
||||
@@ -57,11 +71,13 @@ func NewReadWaitConn(conn tls.Conn) (tls.Conn, error) {
|
||||
}
|
||||
hand := (*bytes.Buffer)(unsafe.Pointer(rawHand.UnsafeAddr()))
|
||||
return &ReadWaitConn{
|
||||
STDConn: stdConn,
|
||||
halfAccess: halfAccess,
|
||||
rawInput: rawInput,
|
||||
input: input,
|
||||
hand: hand,
|
||||
Conn: conn,
|
||||
halfAccess: halfAccess,
|
||||
rawInput: rawInput,
|
||||
input: input,
|
||||
hand: hand,
|
||||
tlsReadRecord: tlsReadRecord,
|
||||
tlsHandlePostHandshakeMessage: tlsHandlePostHandshakeMessage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -71,19 +87,19 @@ func (c *ReadWaitConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy
|
||||
}
|
||||
|
||||
func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
||||
err = c.Handshake()
|
||||
err = c.HandshakeContext(context.Background())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.halfAccess.Lock()
|
||||
defer c.halfAccess.Unlock()
|
||||
for c.input.Len() == 0 {
|
||||
err = tlsReadRecord(c.STDConn)
|
||||
err = c.tlsReadRecord()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for c.hand.Len() > 0 {
|
||||
err = tlsHandlePostHandshakeMessage(c.STDConn)
|
||||
err = c.tlsHandlePostHandshakeMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -100,7 +116,7 @@ func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
||||
if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
|
||||
// recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
|
||||
c.rawInput.Bytes()[0] == 21 {
|
||||
_ = tlsReadRecord(c.STDConn)
|
||||
_ = c.tlsReadRecord()
|
||||
// return n, err // will be io.EOF on closeNotify
|
||||
}
|
||||
|
||||
@@ -109,11 +125,27 @@ func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
||||
}
|
||||
|
||||
func (c *ReadWaitConn) Upstream() any {
|
||||
return c.STDConn
|
||||
return c.Conn
|
||||
}
|
||||
|
||||
//go:linkname tlsReadRecord crypto/tls.(*Conn).readRecord
|
||||
func tlsReadRecord(c *tls.STDConn) error
|
||||
var tlsRegistry []func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error)
|
||||
|
||||
//go:linkname tlsHandlePostHandshakeMessage crypto/tls.(*Conn).handlePostHandshakeMessage
|
||||
func tlsHandlePostHandshakeMessage(c *tls.STDConn) error
|
||||
func init() {
|
||||
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
|
||||
tlsConn, loaded := conn.(*tls.STDConn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
return true, func() error {
|
||||
return stdTLSReadRecord(tlsConn)
|
||||
}, func() error {
|
||||
return stdTLSHandlePostHandshakeMessage(tlsConn)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//go:linkname stdTLSReadRecord crypto/tls.(*Conn).readRecord
|
||||
func stdTLSReadRecord(c *tls.STDConn) error
|
||||
|
||||
//go:linkname stdTLSHandlePostHandshakeMessage crypto/tls.(*Conn).handlePostHandshakeMessage
|
||||
func stdTLSHandlePostHandshakeMessage(c *tls.STDConn) error
|
||||
|
||||
31
common/badtls/read_wait_ech.go
Normal file
31
common/badtls/read_wait_ech.go
Normal file
@@ -0,0 +1,31 @@
|
||||
//go:build go1.21 && !without_badtls && with_ech
|
||||
|
||||
package badtls
|
||||
|
||||
import (
|
||||
"net"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/sagernet/cloudflare-tls"
|
||||
"github.com/sagernet/sing/common"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
|
||||
tlsConn, loaded := common.Cast[*tls.Conn](conn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
return true, func() error {
|
||||
return echReadRecord(tlsConn)
|
||||
}, func() error {
|
||||
return echHandlePostHandshakeMessage(tlsConn)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//go:linkname echReadRecord github.com/sagernet/cloudflare-tls.(*Conn).readRecord
|
||||
func echReadRecord(c *tls.Conn) error
|
||||
|
||||
//go:linkname echHandlePostHandshakeMessage github.com/sagernet/cloudflare-tls.(*Conn).handlePostHandshakeMessage
|
||||
func echHandlePostHandshakeMessage(c *tls.Conn) error
|
||||
31
common/badtls/read_wait_utls.go
Normal file
31
common/badtls/read_wait_utls.go
Normal file
@@ -0,0 +1,31 @@
|
||||
//go:build go1.21 && !without_badtls && with_utls
|
||||
|
||||
package badtls
|
||||
|
||||
import (
|
||||
"net"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/utls"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, tlsReadRecord func() error, tlsHandlePostHandshakeMessage func() error) {
|
||||
tlsConn, loaded := common.Cast[*tls.UConn](conn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
return true, func() error {
|
||||
return utlsReadRecord(tlsConn.Conn)
|
||||
}, func() error {
|
||||
return utlsHandlePostHandshakeMessage(tlsConn.Conn)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//go:linkname utlsReadRecord github.com/sagernet/utls.(*Conn).readRecord
|
||||
func utlsReadRecord(c *tls.Conn) error
|
||||
|
||||
//go:linkname utlsHandlePostHandshakeMessage github.com/sagernet/utls.(*Conn).handlePostHandshakeMessage
|
||||
func utlsHandlePostHandshakeMessage(c *tls.Conn) error
|
||||
@@ -32,14 +32,20 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||
var dialer net.Dialer
|
||||
var listener net.ListenConfig
|
||||
if options.BindInterface != "" {
|
||||
bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
|
||||
var interfaceFinder control.InterfaceFinder
|
||||
if router != nil {
|
||||
interfaceFinder = router.InterfaceFinder()
|
||||
} else {
|
||||
interfaceFinder = control.NewDefaultInterfaceFinder()
|
||||
}
|
||||
bindFunc := control.BindToInterface(interfaceFinder, options.BindInterface, -1)
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else if router.AutoDetectInterface() {
|
||||
} else if router != nil && router.AutoDetectInterface() {
|
||||
bindFunc := router.AutoDetectInterfaceFunc()
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else if router.DefaultInterface() != "" {
|
||||
} else if router != nil && router.DefaultInterface() != "" {
|
||||
bindFunc := control.BindToInterface(router.InterfaceFinder(), router.DefaultInterface(), -1)
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
@@ -47,7 +53,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||
if options.RoutingMark != 0 {
|
||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
||||
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
|
||||
} else if router.DefaultMark() != 0 {
|
||||
} else if router != nil && router.DefaultMark() != 0 {
|
||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(router.DefaultMark()))
|
||||
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
|
||||
}
|
||||
@@ -63,6 +69,9 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||
} else {
|
||||
dialer.Timeout = C.TCPTimeout
|
||||
}
|
||||
// TODO: Add an option to customize the keep alive period
|
||||
dialer.KeepAlive = C.TCPKeepAliveInitial
|
||||
dialer.Control = control.Append(dialer.Control, control.SetKeepAlivePeriod(C.TCPKeepAliveInitial, C.TCPKeepAliveInterval))
|
||||
var udpFragment bool
|
||||
if options.UDPFragment != nil {
|
||||
udpFragment = *options.UDPFragment
|
||||
|
||||
@@ -13,6 +13,9 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
|
||||
if options.IsWireGuardListener {
|
||||
return NewDefault(router, options)
|
||||
}
|
||||
if router == nil {
|
||||
return NewDefault(nil, options)
|
||||
}
|
||||
var (
|
||||
dialer N.Dialer
|
||||
err error
|
||||
|
||||
@@ -60,12 +60,12 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
|
||||
|
||||
isIPv4 := ip.Is4()
|
||||
|
||||
value, err := syscall.Sysctl(spath)
|
||||
value, err := unix.SysctlRaw(spath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := []byte(value)
|
||||
buf := value
|
||||
|
||||
// from darwin-xnu/bsd/netinet/in_pcblist.c:get_pcblist_n
|
||||
// size/offset are round up (aligned) to 8 bytes in darwin
|
||||
|
||||
@@ -223,7 +223,7 @@ func getExecPathFromPID(pid uint32) (string, error) {
|
||||
r1, _, err := syscall.SyscallN(
|
||||
procQueryFullProcessImageNameW.Addr(),
|
||||
uintptr(h),
|
||||
uintptr(1),
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&size)),
|
||||
)
|
||||
|
||||
@@ -16,30 +16,40 @@ import (
|
||||
)
|
||||
|
||||
type LinuxSystemProxy struct {
|
||||
hasGSettings bool
|
||||
hasKWriteConfig5 bool
|
||||
sudoUser string
|
||||
serverAddr M.Socksaddr
|
||||
supportSOCKS bool
|
||||
isEnabled bool
|
||||
hasGSettings bool
|
||||
kWriteConfigCmd string
|
||||
sudoUser string
|
||||
serverAddr M.Socksaddr
|
||||
supportSOCKS bool
|
||||
isEnabled bool
|
||||
}
|
||||
|
||||
func NewSystemProxy(ctx context.Context, serverAddr M.Socksaddr, supportSOCKS bool) (*LinuxSystemProxy, error) {
|
||||
hasGSettings := common.Error(exec.LookPath("gsettings")) == nil
|
||||
hasKWriteConfig5 := common.Error(exec.LookPath("kwriteconfig5")) == nil
|
||||
kWriteConfigCmds := []string{
|
||||
"kwriteconfig5",
|
||||
"kwriteconfig6",
|
||||
}
|
||||
var kWriteConfigCmd string
|
||||
for _, cmd := range kWriteConfigCmds {
|
||||
if common.Error(exec.LookPath(cmd)) == nil {
|
||||
kWriteConfigCmd = cmd
|
||||
break
|
||||
}
|
||||
}
|
||||
var sudoUser string
|
||||
if os.Getuid() == 0 {
|
||||
sudoUser = os.Getenv("SUDO_USER")
|
||||
}
|
||||
if !hasGSettings && !hasKWriteConfig5 {
|
||||
if !hasGSettings && kWriteConfigCmd == "" {
|
||||
return nil, E.New("unsupported desktop environment")
|
||||
}
|
||||
return &LinuxSystemProxy{
|
||||
hasGSettings: hasGSettings,
|
||||
hasKWriteConfig5: hasKWriteConfig5,
|
||||
sudoUser: sudoUser,
|
||||
serverAddr: serverAddr,
|
||||
supportSOCKS: supportSOCKS,
|
||||
hasGSettings: hasGSettings,
|
||||
kWriteConfigCmd: kWriteConfigCmd,
|
||||
sudoUser: sudoUser,
|
||||
serverAddr: serverAddr,
|
||||
supportSOCKS: supportSOCKS,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -70,8 +80,8 @@ func (p *LinuxSystemProxy) Enable() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if p.hasKWriteConfig5 {
|
||||
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
|
||||
if p.kWriteConfigCmd != "" {
|
||||
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -83,7 +93,7 @@ func (p *LinuxSystemProxy) Enable() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
|
||||
err = p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "Authmode", "0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -103,8 +113,8 @@ func (p *LinuxSystemProxy) Disable() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if p.hasKWriteConfig5 {
|
||||
err := p.runAsUser("kwriteconfig5", "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
|
||||
if p.kWriteConfigCmd != "" {
|
||||
err := p.runAsUser(p.kWriteConfigCmd, "--file", "kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -150,7 +160,7 @@ func (p *LinuxSystemProxy) setKDEProxy(proxyTypes ...string) error {
|
||||
proxyUrl = "http://" + p.serverAddr.String()
|
||||
}
|
||||
err := p.runAsUser(
|
||||
"kwriteconfig5",
|
||||
p.kWriteConfigCmd,
|
||||
"--file",
|
||||
"kioslaverc",
|
||||
"--group",
|
||||
|
||||
@@ -27,11 +27,10 @@ func (c *echClientConfig) DialEarly(ctx context.Context, conn net.PacketConn, ad
|
||||
return quic.DialEarly(ctx, conn, addr, c.config, config)
|
||||
}
|
||||
|
||||
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config, enableDatagrams bool) http.RoundTripper {
|
||||
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config) http.RoundTripper {
|
||||
return &http3.RoundTripper{
|
||||
TLSClientConfig: c.config,
|
||||
QuicConfig: quicConfig,
|
||||
EnableDatagrams: enableDatagrams,
|
||||
QUICConfig: quicConfig,
|
||||
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||
quicConn, err := quic.DialEarly(ctx, conn, serverAddr.UDPAddr(), tlsCfg, cfg)
|
||||
if err != nil {
|
||||
|
||||
5
constant/quic.go
Normal file
5
constant/quic.go
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build with_quic
|
||||
|
||||
package constant
|
||||
|
||||
const WithQUIC = true
|
||||
5
constant/quic_stub.go
Normal file
5
constant/quic_stub.go
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build !with_quic
|
||||
|
||||
package constant
|
||||
|
||||
const WithQUIC = false
|
||||
@@ -3,6 +3,8 @@ package constant
|
||||
import "time"
|
||||
|
||||
const (
|
||||
TCPKeepAliveInitial = 10 * time.Minute
|
||||
TCPKeepAliveInterval = 75 * time.Second
|
||||
TCPTimeout = 5 * time.Second
|
||||
ReadPayloadTimeout = 300 * time.Millisecond
|
||||
DNSTimeout = 10 * time.Second
|
||||
|
||||
@@ -2,11 +2,152 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! failure "Help needed"
|
||||
|
||||
Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
||||
|
||||
If your company or organization is willing to help us return to the App Store, please [contact us](mailto:contact@sagernet.org).
|
||||
|
||||
### 1.9.4
|
||||
|
||||
* Update quic-go to v0.46.0
|
||||
* Update Hysteria2 BBR congestion control
|
||||
* Filter HTTPS ipv4hint/ipv6hint with domain strategy
|
||||
* Fix crash on Android when using process rules
|
||||
* Fix non-IP queries accepted by address filter rules
|
||||
* Fix UDP server for shadowsocks AEAD multi-user inbounds
|
||||
* Fix default next protos for v2ray QUIC transport
|
||||
* Fix default end value of port range configuration options
|
||||
* Fix reset v2ray transports
|
||||
* Fix panic caused by rule-set generation of duplicate keys for `domain_suffix`
|
||||
* Fix UDP connnection leak when sniffing
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.9.3
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.9.2
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.9.1
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.9.0
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
Important changes since 1.8:
|
||||
|
||||
* `domain_suffix` behavior update **1**
|
||||
* `process_path` format update on Windows **2**
|
||||
* Add address filter DNS rule items **3**
|
||||
* Add support for `client-subnet` DNS options **4**
|
||||
* Add rejected DNS response cache support **5**
|
||||
* Add `bypass_domain` and `search_domain` platform HTTP proxy options **6**
|
||||
* Fix missing `rule_set_ipcidr_match_source` item in DNS rules **7**
|
||||
* Handle Windows power events
|
||||
* Always disable cache for fake-ip DNS transport if `dns.independent_cache` disabled
|
||||
* Improve DNS truncate behavior
|
||||
* Update Hysteria protocol
|
||||
* Update quic-go to v0.43.1
|
||||
* Update gVisor to 20240422.0
|
||||
* Mitigating TunnelVision attacks **8**
|
||||
|
||||
**1**:
|
||||
|
||||
See [Migration](/migration/#domain_suffix-behavior-update).
|
||||
|
||||
**2**:
|
||||
|
||||
See [Migration](/migration/#process_path-format-update-on-windows).
|
||||
|
||||
**3**:
|
||||
|
||||
The new DNS feature allows you to more precisely bypass Chinese websites via **DNS leaks**. Do not use plain local DNS
|
||||
if using this method.
|
||||
|
||||
See [Address Filter Fields](/configuration/dns/rule#address-filter-fields).
|
||||
|
||||
[Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) updated.
|
||||
|
||||
**4**:
|
||||
|
||||
See [DNS](/configuration/dns), [DNS Server](/configuration/dns/server) and [DNS Rules](/configuration/dns/rule).
|
||||
|
||||
Since this feature makes the scenario mentioned in `alpha.1` no longer leak DNS requests,
|
||||
the [Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) has been updated.
|
||||
|
||||
**5**:
|
||||
|
||||
The new feature allows you to cache the check results of
|
||||
[Address filter DNS rule items](/configuration/dns/rule/#address-filter-fields) until expiration.
|
||||
|
||||
**6**:
|
||||
|
||||
See [TUN](/configuration/inbound/tun) inbound.
|
||||
|
||||
**7**:
|
||||
|
||||
See [DNS Rule](/configuration/dns/rule/).
|
||||
|
||||
**8**:
|
||||
|
||||
See [TunnelVision](/manual/misc/tunnelvision).
|
||||
|
||||
#### 1.9.0-rc.22
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.20
|
||||
|
||||
* Prioritize `*_route_address` in linux auto-route
|
||||
* Fix `*_route_address` in darwin auto-route
|
||||
|
||||
#### 1.8.14
|
||||
|
||||
* Fix hysteria2 panic
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.18
|
||||
|
||||
* Add custom prefix support in EDNS0 client subnet options
|
||||
* Fix hysteria2 crash
|
||||
* Fix `store_rdrc` corrupted
|
||||
* Update quic-go to v0.43.1
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.16
|
||||
|
||||
* Mitigating TunnelVision attacks **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
See [TunnelVision](/manual/misc/tunnelvision).
|
||||
|
||||
#### 1.9.0-rc.15
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.13
|
||||
|
||||
* Fix fake-ip mapping
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.14
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.13
|
||||
|
||||
* Update Hysteria protocol
|
||||
* Update quic-go to v0.43.0
|
||||
* Update gVisor to 20240422.0
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.12
|
||||
|
||||
* Now we have official APT and DNF repositories **1**
|
||||
@@ -17,6 +158,10 @@ icon: material/alert-decagram
|
||||
|
||||
Including stable and beta versions, see https://sing-box.sagernet.org/installation/package-manager/
|
||||
|
||||
#### 1.9.0-rc.11
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.11
|
||||
|
||||
* Fixes and improvements
|
||||
@@ -25,6 +170,24 @@ Including stable and beta versions, see https://sing-box.sagernet.org/installati
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-beta.17
|
||||
|
||||
* Update `quic-go` to v0.42.0
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-beta.16
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
_Our Testflight distribution has been temporarily blocked by Apple (possibly due to too many beta versions)
|
||||
and you cannot join the test, install or update the sing-box beta app right now.
|
||||
Please wait patiently for processing._
|
||||
|
||||
#### 1.9.0-beta.14
|
||||
|
||||
* Update gVisor to 20240212.0-65-g71212d503
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.9
|
||||
|
||||
* Fixes and improvements
|
||||
@@ -33,14 +196,125 @@ Including stable and beta versions, see https://sing-box.sagernet.org/installati
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-beta.7
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-beta.6
|
||||
|
||||
* Fix address filter DNS rule items **1**
|
||||
* Fix DNS outbound responding with wrong data
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
Fixed an issue where address filter DNS rule was incorrectly rejected under certain circumstances.
|
||||
If you have enabled `store_rdrc` to save results, consider clearing the cache file.
|
||||
|
||||
#### 1.8.7
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.15
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.14
|
||||
|
||||
* Improve DNS truncate behavior
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.13
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.6
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.12
|
||||
|
||||
* Handle Windows power events
|
||||
* Always disable cache for fake-ip DNS transport if `dns.independent_cache` disabled
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.11
|
||||
|
||||
* Fix missing `rule_set_ipcidr_match_source` item in DNS rules **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
See [DNS Rule](/configuration/dns/rule/).
|
||||
|
||||
#### 1.9.0-alpha.10
|
||||
|
||||
* Add `bypass_domain` and `search_domain` platform HTTP proxy options **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
See [TUN](/configuration/inbound/tun) inbound.
|
||||
|
||||
#### 1.9.0-alpha.8
|
||||
|
||||
* Add rejected DNS response cache support **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
The new feature allows you to cache the check results of
|
||||
[Address filter DNS rule items](/configuration/dns/rule/#address-filter-fields) until expiration.
|
||||
|
||||
#### 1.9.0-alpha.7
|
||||
|
||||
* Update gVisor to 20240206.0
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.6
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.3
|
||||
|
||||
* Update `quic-go` to v0.41.0
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-alpha.2
|
||||
|
||||
* Add support for `client-subnet` DNS options **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
See [DNS](/configuration/dns), [DNS Server](/configuration/dns/server) and [DNS Rules](/configuration/dns/rule).
|
||||
|
||||
Since this feature makes the scenario mentioned in `alpha.1` no longer leak DNS requests,
|
||||
the [Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) has been updated.
|
||||
|
||||
#### 1.9.0-alpha.1
|
||||
|
||||
* `domain_suffix` behavior update **1**
|
||||
* `process_path` format update on Windows **2**
|
||||
* Add address filter DNS rule items **3**
|
||||
|
||||
**1**:
|
||||
|
||||
See [Migration](/migration/#domain_suffix-behavior-update).
|
||||
|
||||
**2**:
|
||||
|
||||
See [Migration](/migration/#process_path-format-update-on-windows).
|
||||
|
||||
**3**:
|
||||
|
||||
The new DNS feature allows you to more precisely bypass Chinese websites via **DNS leaks**. Do not use plain local DNS
|
||||
if using this method.
|
||||
|
||||
See [Address Filter Fields](/configuration/dns/rule#address-filter-fields).
|
||||
|
||||
[Client example](/manual/proxy/client#traffic-bypass-usage-for-chinese-users) updated.
|
||||
|
||||
#### 1.8.5
|
||||
|
||||
* Fixes and improvements
|
||||
@@ -57,7 +331,7 @@ Including stable and beta versions, see https://sing-box.sagernet.org/installati
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.0
|
||||
### 1.8.0
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
@@ -348,7 +622,7 @@ New commands manage GeoIP, Geosite and rule set resources, and help you migrate
|
||||
|
||||
Logical rules in route rules, DNS rules, and the new headless rule now allow nesting of logical rules.
|
||||
|
||||
#### 1.7.0
|
||||
### 1.7.0
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
@@ -390,7 +664,7 @@ see [TCP Brutal](/configuration/shared/tcp-brutal/) for details.
|
||||
|
||||
**5**:
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
#### 1.7.0-rc.3
|
||||
|
||||
@@ -427,7 +701,7 @@ Only supported in graphical clients on Android and iOS.
|
||||
|
||||
**1**:
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
#### 1.7.0-beta.3
|
||||
|
||||
@@ -508,7 +782,7 @@ Introduced in V2Ray 5.10.0.
|
||||
|
||||
The new HTTPUpgrade transport has better performance than WebSocket and is better suited for CDN abuse.
|
||||
|
||||
#### 1.6.0
|
||||
### 1.6.0
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
@@ -687,7 +961,7 @@ introduce new issues.
|
||||
None of the existing Golang BBR congestion control implementations have been reviewed or unit tested.
|
||||
This update is intended to address the multi-send defects of the old implementation and may introduce new issues.
|
||||
|
||||
#### 1.5.0
|
||||
### 1.5.0
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
@@ -881,7 +1155,7 @@ All inbounds and outbounds are supported, including `Naiveproxy`, `Hysteria`, `T
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.4.0
|
||||
### 1.4.0
|
||||
|
||||
* Fix bugs and update dependencies
|
||||
|
||||
@@ -1023,7 +1297,7 @@ The old testflight link and app are no longer valid.
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.3.0
|
||||
### 1.3.0
|
||||
|
||||
* Fix bugs and update dependencies
|
||||
|
||||
@@ -1215,7 +1489,7 @@ to `domain` rule.
|
||||
* Flush DNS cache for macOS when tun start/close
|
||||
* Fix tun's DNS hijacking compatibility with systemd-resolved
|
||||
|
||||
#### 1.2.0
|
||||
### 1.2.0
|
||||
|
||||
* Fix bugs and update dependencies
|
||||
|
||||
|
||||
@@ -7,6 +7,13 @@ icon: material/apple
|
||||
SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides
|
||||
platform-specific function implementation, such as TUN transparent proxy implementation.
|
||||
|
||||
!!! failure "Unavailable"
|
||||
|
||||
Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
||||
|
||||
If your company or organization is willing to help us return to the App Store, please [contact us](mailto:contact@sagernet.org).
|
||||
|
||||
|
||||
## :material-graph: Requirements
|
||||
|
||||
* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
Maintained by Project S to provide a unified experience and platform-specific functionality.
|
||||
|
||||
| Platform | Client |
|
||||
|---------------------------------------|------------------------------------------|
|
||||
| ------------------------------------- | ---------------------------------------- |
|
||||
| :material-android: Android | [sing-box for Android](./android/) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [Unavailable](./apple/) |
|
||||
| :material-laptop: Desktop | Working in progress |
|
||||
|
||||
Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
由 Project S 维护,提供统一的体验与平台特定的功能。
|
||||
|
||||
| 平台 | 客户端 |
|
||||
|---------------------------------------|-----------------------------------------|
|
||||
| :material-android: Android | [sing-box for Android](./android/) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
|
||||
| :material-laptop: Desktop | 施工中 |
|
||||
| 平台 | 客户端 |
|
||||
| ------------------------------------- | ----------------------------------- |
|
||||
| :material-android: Android | [sing-box for Android](./android/) |
|
||||
| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [不可用](./apple/) |
|
||||
| :material-laptop: Desktop | 施工中 |
|
||||
|
||||
此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业
|
||||
VPN 客户端功能, 但代码质量很差且包含广告。
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
:material-plus: [client_subnet](#client_subnet)
|
||||
|
||||
# DNS
|
||||
|
||||
### Structure
|
||||
@@ -13,6 +21,7 @@
|
||||
"disable_expire": false,
|
||||
"independent_cache": false,
|
||||
"reverse_mapping": false,
|
||||
"client_subnet": "",
|
||||
"fakeip": {}
|
||||
}
|
||||
}
|
||||
@@ -21,8 +30,8 @@
|
||||
|
||||
### Fields
|
||||
|
||||
| Key | Format |
|
||||
|----------|--------------------------------|
|
||||
| Key | Format |
|
||||
|----------|---------------------------------|
|
||||
| `server` | List of [DNS Server](./server/) |
|
||||
| `rules` | List of [DNS Rule](./rule/) |
|
||||
| `fakeip` | [FakeIP](./fakeip/) |
|
||||
@@ -60,6 +69,12 @@ Stores a reverse mapping of IP addresses after responding to a DNS query in orde
|
||||
Since this process relies on the act of resolving domain names by an application before making a request, it can be
|
||||
problematic in environments such as macOS, where DNS is proxied and cached by the system.
|
||||
|
||||
#### fakeip
|
||||
#### client_subnet
|
||||
|
||||
[FakeIP](./fakeip/) settings.
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||
|
||||
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||
|
||||
Can be overrides by `servers.[].client_subnet` or `rules.[].client_subnet`.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
:material-plus: [client_subnet](#client_subnet)
|
||||
|
||||
# DNS
|
||||
|
||||
### 结构
|
||||
@@ -13,6 +21,7 @@
|
||||
"disable_expire": false,
|
||||
"independent_cache": false,
|
||||
"reverse_mapping": false,
|
||||
"client_subnet": "",
|
||||
"fakeip": {}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +67,16 @@
|
||||
|
||||
由于此过程依赖于应用程序在发出请求之前解析域名的行为,因此在 macOS 等 DNS 由系统代理和缓存的环境中可能会出现问题。
|
||||
|
||||
#### client_subnet
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
|
||||
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||
|
||||
可以被 `servers.[].client_subnet` 或 `rules.[].client_subnet` 覆盖。
|
||||
|
||||
#### fakeip
|
||||
|
||||
[FakeIP](./fakeip/) 设置。
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
:material-plus: [geoip](#geoip)
|
||||
:material-plus: [ip_cidr](#ip_cidr)
|
||||
:material-plus: [ip_is_private](#ip_is_private)
|
||||
:material-plus: [client_subnet](#client_subnet)
|
||||
:material-plus: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
:material-plus: [rule_set](#rule_set)
|
||||
@@ -53,11 +61,19 @@ icon: material/alert-decagram
|
||||
"source_geoip": [
|
||||
"private"
|
||||
],
|
||||
"geoip": [
|
||||
"cn"
|
||||
],
|
||||
"source_ip_cidr": [
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"source_ip_is_private": false,
|
||||
"ip_cidr": [
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"ip_is_private": false,
|
||||
"source_port": [
|
||||
12345
|
||||
],
|
||||
@@ -101,13 +117,15 @@ icon: material/alert-decagram
|
||||
"geoip-cn",
|
||||
"geosite-cn"
|
||||
],
|
||||
"rule_set_ipcidr_match_source": false,
|
||||
"invert": false,
|
||||
"outbound": [
|
||||
"direct"
|
||||
],
|
||||
"server": "local",
|
||||
"disable_cache": false,
|
||||
"rewrite_ttl": 100
|
||||
"rewrite_ttl": 100,
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
@@ -115,7 +133,8 @@ icon: material/alert-decagram
|
||||
"rules": [],
|
||||
"server": "local",
|
||||
"disable_cache": false,
|
||||
"rewrite_ttl": 100
|
||||
"rewrite_ttl": 100,
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -266,11 +285,9 @@ Match Clash mode.
|
||||
|
||||
#### wifi_ssid
|
||||
|
||||
<!-- md:version 1.7.0-beta.4 -->
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
Match WiFi SSID.
|
||||
|
||||
@@ -278,7 +295,7 @@ Match WiFi SSID.
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
Match WiFi BSSID.
|
||||
|
||||
@@ -288,6 +305,12 @@ Match WiFi BSSID.
|
||||
|
||||
Match [Rule Set](/configuration/route/#rule_set).
|
||||
|
||||
#### rule_set_ipcidr_match_source
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Make `ipcidr` in rule sets match the source IP.
|
||||
|
||||
#### invert
|
||||
|
||||
Invert match result.
|
||||
@@ -312,6 +335,46 @@ Disable cache and save cache in this query.
|
||||
|
||||
Rewrite TTL in DNS responses.
|
||||
|
||||
#### client_subnet
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||
|
||||
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||
|
||||
Will overrides `dns.client_subnet` and `servers.[].client_subnet`.
|
||||
|
||||
### Address Filter Fields
|
||||
|
||||
Only takes effect for IP address requests. When the query results do not match the address filtering rule items, the current rule will be skipped.
|
||||
|
||||
!!! info ""
|
||||
|
||||
`ip_cidr` items in included rule sets also takes effect as an address filtering field.
|
||||
|
||||
!!! note ""
|
||||
|
||||
Enable `experimental.cache_file.store_rdrc` to cache results.
|
||||
|
||||
#### geoip
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Match GeoIP with query response.
|
||||
|
||||
#### ip_cidr
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Match IP CIDR with query response.
|
||||
|
||||
#### ip_is_private
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Match private IP with query response.
|
||||
|
||||
### Logical Fields
|
||||
|
||||
#### type
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
:material-plus: [geoip](#geoip)
|
||||
:material-plus: [ip_cidr](#ip_cidr)
|
||||
:material-plus: [ip_is_private](#ip_is_private)
|
||||
:material-plus: [client_subnet](#client_subnet)
|
||||
:material-plus: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
:material-plus: [rule_set](#rule_set)
|
||||
@@ -53,10 +61,19 @@ icon: material/alert-decagram
|
||||
"source_geoip": [
|
||||
"private"
|
||||
],
|
||||
"geoip": [
|
||||
"cn"
|
||||
],
|
||||
"source_ip_cidr": [
|
||||
"10.0.0.0/24"
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"source_ip_is_private": false,
|
||||
"ip_cidr": [
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"ip_is_private": false,
|
||||
"source_port": [
|
||||
12345
|
||||
],
|
||||
@@ -100,19 +117,22 @@ icon: material/alert-decagram
|
||||
"geoip-cn",
|
||||
"geosite-cn"
|
||||
],
|
||||
"rule_set_ipcidr_match_source": false,
|
||||
"invert": false,
|
||||
"outbound": [
|
||||
"direct"
|
||||
],
|
||||
"server": "local",
|
||||
"disable_cache": false
|
||||
"disable_cache": false,
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [],
|
||||
"server": "local",
|
||||
"disable_cache": false
|
||||
"disable_cache": false,
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -265,7 +285,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||
|
||||
匹配 WiFi SSID。
|
||||
|
||||
@@ -273,7 +293,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||
|
||||
匹配 WiFi BSSID。
|
||||
|
||||
@@ -283,6 +303,12 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
匹配[规则集](/zh/configuration/route/#rule_set)。
|
||||
|
||||
#### rule_set_ipcidr_match_source
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
使规则集中的 `ipcidr` 规则匹配源 IP。
|
||||
|
||||
#### invert
|
||||
|
||||
反选匹配结果。
|
||||
@@ -307,6 +333,46 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
重写 DNS 回应中的 TTL。
|
||||
|
||||
#### client_subnet
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
|
||||
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||
|
||||
将覆盖 `dns.client_subnet` 与 `servers.[].client_subnet`。
|
||||
|
||||
### 地址筛选字段
|
||||
|
||||
仅对IP地址请求生效。 当查询结果与地址筛选规则项不匹配时,将跳过当前规则。
|
||||
|
||||
!!! info ""
|
||||
|
||||
引用的规则集中的 `ip_cidr` 项也作为地址筛选字段生效。
|
||||
|
||||
!!! note ""
|
||||
|
||||
启用 `experimental.cache_file.store_rdrc` 以缓存结果。
|
||||
|
||||
#### geoip
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
与查询响应匹配 GeoIP。
|
||||
|
||||
#### ip_cidr
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
与查询相应匹配 IP CIDR。
|
||||
|
||||
#### ip_is_private
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
与查询响应匹配非公开 IP。
|
||||
|
||||
### 逻辑字段
|
||||
|
||||
#### type
|
||||
@@ -319,4 +385,4 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
#### rules
|
||||
|
||||
包括的规则。
|
||||
包括的规则。
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
:material-plus: [client_subnet](#client_subnet)
|
||||
|
||||
### Structure
|
||||
|
||||
```json
|
||||
@@ -5,17 +13,17 @@
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://dns.google",
|
||||
"address_resolver": "local",
|
||||
"address_strategy": "prefer_ipv4",
|
||||
"strategy": "ipv4_only",
|
||||
"detour": "direct"
|
||||
"tag": "",
|
||||
"address": "",
|
||||
"address_resolver": "",
|
||||
"address_strategy": "",
|
||||
"strategy": "",
|
||||
"detour": "",
|
||||
"client_subnet": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Fields
|
||||
@@ -80,10 +88,22 @@ Default domain strategy for resolving the domain names.
|
||||
|
||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
||||
|
||||
Take no effect if override by other settings.
|
||||
Take no effect if overridden by other settings.
|
||||
|
||||
#### detour
|
||||
|
||||
Tag of an outbound for connecting to the dns server.
|
||||
|
||||
Default outbound will be used if empty.
|
||||
|
||||
#### client_subnet
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||
|
||||
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||
|
||||
Can be overrides by `rules.[].client_subnet`.
|
||||
|
||||
Will overrides `dns.client_subnet`.
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
:material-plus: [client_subnet](#client_subnet)
|
||||
|
||||
### 结构
|
||||
|
||||
```json
|
||||
@@ -5,17 +13,17 @@
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://dns.google",
|
||||
"address_resolver": "local",
|
||||
"address_strategy": "prefer_ipv4",
|
||||
"strategy": "ipv4_only",
|
||||
"detour": "direct"
|
||||
"tag": "",
|
||||
"address": "",
|
||||
"address_resolver": "",
|
||||
"address_strategy": "",
|
||||
"strategy": "",
|
||||
"detour": "",
|
||||
"client_subnet": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 字段
|
||||
@@ -87,3 +95,15 @@ DNS 服务器的地址。
|
||||
用于连接到 DNS 服务器的出站的标签。
|
||||
|
||||
如果为空,将使用默认出站。
|
||||
|
||||
#### client_subnet
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
|
||||
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||
|
||||
可以被 `rules.[].client_subnet` 覆盖。
|
||||
|
||||
将覆盖 `dns.client_subnet`。
|
||||
|
||||
@@ -4,6 +4,11 @@ icon: material/new-box
|
||||
|
||||
!!! question "Since sing-box 1.8.0"
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
:material-plus: [store_rdrc](#store_rdrc)
|
||||
:material-plus: [rdrc_timeout](#rdrc_timeout)
|
||||
|
||||
### Structure
|
||||
|
||||
```json
|
||||
@@ -11,7 +16,9 @@ icon: material/new-box
|
||||
"enabled": true,
|
||||
"path": "",
|
||||
"cache_id": "",
|
||||
"store_fakeip": false
|
||||
"store_fakeip": false,
|
||||
"store_rdrc": false,
|
||||
"rdrc_timeout": ""
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,6 +36,23 @@ Path to the cache file.
|
||||
|
||||
#### cache_id
|
||||
|
||||
Identifier in cache file.
|
||||
Identifier in the cache file
|
||||
|
||||
If not empty, configuration specified data will use a separate store keyed by it.
|
||||
|
||||
#### store_fakeip
|
||||
|
||||
Store fakeip in the cache file
|
||||
|
||||
#### store_rdrc
|
||||
|
||||
Store rejected DNS response cache in the cache file
|
||||
|
||||
The check results of [Address filter DNS rule items](/configuration/dns/rule/#address-filter-fields)
|
||||
will be cached until expiration.
|
||||
|
||||
#### rdrc_timeout
|
||||
|
||||
Timeout of rejected DNS response cache.
|
||||
|
||||
`7d` is used by default.
|
||||
|
||||
@@ -4,6 +4,11 @@ icon: material/new-box
|
||||
|
||||
!!! question "自 sing-box 1.8.0 起"
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
:material-plus: [store_rdrc](#store_rdrc)
|
||||
:material-plus: [rdrc_timeout](#rdrc_timeout)
|
||||
|
||||
### 结构
|
||||
|
||||
```json
|
||||
@@ -11,7 +16,9 @@ icon: material/new-box
|
||||
"enabled": true,
|
||||
"path": "",
|
||||
"cache_id": "",
|
||||
"store_fakeip": false
|
||||
"store_fakeip": false,
|
||||
"store_rdrc": false,
|
||||
"rdrc_timeout": ""
|
||||
}
|
||||
```
|
||||
|
||||
@@ -30,3 +37,19 @@ icon: material/new-box
|
||||
缓存文件中的标识符。
|
||||
|
||||
如果不为空,配置特定的数据将使用由其键控的单独存储。
|
||||
|
||||
#### store_fakeip
|
||||
|
||||
将 fakeip 存储在缓存文件中。
|
||||
|
||||
#### store_rdrc
|
||||
|
||||
将拒绝的 DNS 响应缓存存储在缓存文件中。
|
||||
|
||||
[地址筛选 DNS 规则项](/zh/configuration/dns/rule/#_3) 的检查结果将被缓存至过期。
|
||||
|
||||
#### rdrc_timeout
|
||||
|
||||
拒绝的 DNS 响应缓存超时。
|
||||
|
||||
默认使用 `7d`。
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
:material-delete-alert: [store_mode](#store_mode)
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
:material-delete-alert: [store_mode](#store_mode)
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
# Experimental
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
# 实验性
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
@@ -42,6 +42,6 @@ No authentication required if empty.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
To work on Android and iOS without privileges, use tun.platform.http_proxy instead.
|
||||
To work on Android and Apple platforms without privileges, use tun.platform.http_proxy instead.
|
||||
|
||||
Automatically set system proxy configuration when start and clean up when stop.
|
||||
|
||||
@@ -15,24 +15,24 @@
|
||||
|
||||
### Fields
|
||||
|
||||
| Type | Format | Injectable |
|
||||
|---------------|-------------------------------|------------|
|
||||
| `direct` | [Direct](./direct/) | X |
|
||||
| `mixed` | [Mixed](./mixed/) | TCP |
|
||||
| `socks` | [SOCKS](./socks/) | TCP |
|
||||
| `http` | [HTTP](./http/) | TCP |
|
||||
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
||||
| `vmess` | [VMess](./vmess/) | TCP |
|
||||
| `trojan` | [Trojan](./trojan/) | TCP |
|
||||
| `naive` | [Naive](./naive/) | X |
|
||||
| `hysteria` | [Hysteria](./hysteria/) | X |
|
||||
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
||||
| `tuic` | [TUIC](./tuic/) | X |
|
||||
| `hysteria2` | [Hysteria2](./hysteria2/) | X |
|
||||
| `vless` | [VLESS](./vless/) | TCP |
|
||||
| `tun` | [Tun](./tun/) | X |
|
||||
| `redirect` | [Redirect](./redirect/) | X |
|
||||
| `tproxy` | [TProxy](./tproxy/) | X |
|
||||
| Type | Format | Injectable |
|
||||
|---------------|-------------------------------|------------------|
|
||||
| `direct` | [Direct](./direct/) | :material-close: |
|
||||
| `mixed` | [Mixed](./mixed/) | TCP |
|
||||
| `socks` | [SOCKS](./socks/) | TCP |
|
||||
| `http` | [HTTP](./http/) | TCP |
|
||||
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
||||
| `vmess` | [VMess](./vmess/) | TCP |
|
||||
| `trojan` | [Trojan](./trojan/) | TCP |
|
||||
| `naive` | [Naive](./naive/) | :material-close: |
|
||||
| `hysteria` | [Hysteria](./hysteria/) | :material-close: |
|
||||
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
||||
| `tuic` | [TUIC](./tuic/) | :material-close: |
|
||||
| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: |
|
||||
| `vless` | [VLESS](./vless/) | TCP |
|
||||
| `tun` | [Tun](./tun/) | :material-close: |
|
||||
| `redirect` | [Redirect](./redirect/) | :material-close: |
|
||||
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
|
||||
|
||||
#### tag
|
||||
|
||||
|
||||
@@ -15,24 +15,24 @@
|
||||
|
||||
### 字段
|
||||
|
||||
| 类型 | 格式 | 注入支持 |
|
||||
|---------------|------------------------------|------|
|
||||
| `direct` | [Direct](./direct/) | X |
|
||||
| `mixed` | [Mixed](./mixed/) | TCP |
|
||||
| `socks` | [SOCKS](./socks/) | TCP |
|
||||
| `http` | [HTTP](./http/) | TCP |
|
||||
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
||||
| `vmess` | [VMess](./vmess/) | TCP |
|
||||
| `trojan` | [Trojan](./trojan/) | TCP |
|
||||
| `naive` | [Naive](./naive/) | X |
|
||||
| `hysteria` | [Hysteria](./hysteria/) | X |
|
||||
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
||||
| `tuic` | [TUIC](./tuic/) | X |
|
||||
| `hysteria2` | [Hysteria2](./hysteria2/) | X |
|
||||
| `vless` | [VLESS](./vless/) | TCP |
|
||||
| `tun` | [Tun](./tun/) | X |
|
||||
| `redirect` | [Redirect](./redirect/) | X |
|
||||
| `tproxy` | [TProxy](./tproxy/) | X |
|
||||
| 类型 | 格式 | 注入支持 |
|
||||
|---------------|-------------------------------|------------------|
|
||||
| `direct` | [Direct](./direct/) | :material-close: |
|
||||
| `mixed` | [Mixed](./mixed/) | TCP |
|
||||
| `socks` | [SOCKS](./socks/) | TCP |
|
||||
| `http` | [HTTP](./http/) | TCP |
|
||||
| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP |
|
||||
| `vmess` | [VMess](./vmess/) | TCP |
|
||||
| `trojan` | [Trojan](./trojan/) | TCP |
|
||||
| `naive` | [Naive](./naive/) | :material-close: |
|
||||
| `hysteria` | [Hysteria](./hysteria/) | :material-close: |
|
||||
| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP |
|
||||
| `tuic` | [TUIC](./tuic/) | :material-close: |
|
||||
| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: |
|
||||
| `vless` | [VLESS](./vless/) | TCP |
|
||||
| `tun` | [Tun](./tun/) | :material-close: |
|
||||
| `redirect` | [Redirect](./redirect/) | :material-close: |
|
||||
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
|
||||
|
||||
#### tag
|
||||
|
||||
|
||||
@@ -39,6 +39,6 @@ No authentication required if empty.
|
||||
|
||||
!!! warning ""
|
||||
|
||||
To work on Android and iOS without privileges, use tun.platform.http_proxy instead.
|
||||
To work on Android and Apple platforms without privileges, use tun.platform.http_proxy instead.
|
||||
|
||||
Automatically set system proxy configuration when start and clean up when stop.
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.9.0"
|
||||
|
||||
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
|
||||
:material-plus: [platform.http_proxy.match_domain](#platformhttp_proxymatch_domain)
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
:material-plus: [gso](#gso)
|
||||
@@ -73,7 +78,9 @@ icon: material/alert-decagram
|
||||
"http_proxy": {
|
||||
"enabled": false,
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080
|
||||
"server_port": 8080,
|
||||
"bypass_domain": [],
|
||||
"match_domain": []
|
||||
}
|
||||
},
|
||||
|
||||
@@ -260,6 +267,38 @@ Platform-specific settings, provided by client applications.
|
||||
|
||||
System HTTP proxy settings.
|
||||
|
||||
#### platform.http_proxy.enabled
|
||||
|
||||
Enable system HTTP proxy.
|
||||
|
||||
#### platform.http_proxy.server
|
||||
|
||||
==Required==
|
||||
|
||||
HTTP proxy server address.
|
||||
|
||||
#### platform.http_proxy.server_port
|
||||
|
||||
==Required==
|
||||
|
||||
HTTP proxy server port.
|
||||
|
||||
#### platform.http_proxy.bypass_domain
|
||||
|
||||
!!! note ""
|
||||
|
||||
On Apple platforms, `bypass_domain` items matches hostname **suffixes**.
|
||||
|
||||
Hostnames that bypass the HTTP proxy.
|
||||
|
||||
#### platform.http_proxy.match_domain
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Apple platforms.
|
||||
|
||||
Hostnames that use the HTTP proxy.
|
||||
|
||||
### Listen Fields
|
||||
|
||||
See [Listen Fields](/configuration/shared/listen/) for details.
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.9.0 中的更改"
|
||||
|
||||
:material-plus: [platform.http_proxy.bypass_domain](#platformhttp_proxybypass_domain)
|
||||
:material-plus: [platform.http_proxy.match_domain](#platformhttp_proxymatch_domain)
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
:material-plus: [gso](#gso)
|
||||
@@ -73,7 +78,9 @@ icon: material/alert-decagram
|
||||
"http_proxy": {
|
||||
"enabled": false,
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080
|
||||
"server_port": 8080,
|
||||
"bypass_domain": [],
|
||||
"match_domain": []
|
||||
}
|
||||
},
|
||||
|
||||
@@ -257,6 +264,38 @@ TCP/IP 栈。
|
||||
|
||||
系统 HTTP 代理设置。
|
||||
|
||||
##### platform.http_proxy.enabled
|
||||
|
||||
启用系统 HTTP 代理。
|
||||
|
||||
##### platform.http_proxy.server
|
||||
|
||||
==必填==
|
||||
|
||||
系统 HTTP 代理服务器地址。
|
||||
|
||||
##### platform.http_proxy.server_port
|
||||
|
||||
==必填==
|
||||
|
||||
系统 HTTP 代理服务器端口。
|
||||
|
||||
##### platform.http_proxy.bypass_domain
|
||||
|
||||
!!! note ""
|
||||
|
||||
在 Apple 平台,`bypass_domain` 项匹配主机名 **后缀**.
|
||||
|
||||
绕过代理的主机名列表。
|
||||
|
||||
##### platform.http_proxy.match_domain
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Apple 平台图形客户端中支持。
|
||||
|
||||
代理的主机名列表。
|
||||
|
||||
### 监听字段
|
||||
|
||||
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
}
|
||||
```
|
||||
|
||||
### 字段
|
||||
### Fields
|
||||
|
||||
No fields.
|
||||
No fields.
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
:material-plus: [gso](#gso)
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
:material-plus: [gso](#gso)
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
# Route
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
# 路由
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
:material-plus: [rule_set](#rule_set)
|
||||
@@ -109,6 +105,7 @@ icon: material/alert-decagram
|
||||
"geoip-cn",
|
||||
"geosite-cn"
|
||||
],
|
||||
"rule_set_ipcidr_match_source": false,
|
||||
"invert": false,
|
||||
"outbound": "direct"
|
||||
},
|
||||
@@ -284,7 +281,7 @@ Match Clash mode.
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
Match WiFi SSID.
|
||||
|
||||
@@ -292,7 +289,7 @@ Match WiFi SSID.
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
Match WiFi BSSID.
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
:material-plus: [rule_set](#rule_set)
|
||||
@@ -107,6 +103,7 @@ icon: material/alert-decagram
|
||||
"geoip-cn",
|
||||
"geosite-cn"
|
||||
],
|
||||
"rule_set_ipcidr_match_source": false,
|
||||
"invert": false,
|
||||
"outbound": "direct"
|
||||
},
|
||||
@@ -282,7 +279,7 @@ icon: material/alert-decagram
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||
|
||||
匹配 WiFi SSID。
|
||||
|
||||
@@ -290,7 +287,7 @@ icon: material/alert-decagram
|
||||
|
||||
!!! quote ""
|
||||
|
||||
仅在 Android 与 iOS 的图形客户端中支持。
|
||||
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||
|
||||
匹配 WiFi BSSID。
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
### Structure
|
||||
|
||||
!!! question "Since sing-box 1.8.0"
|
||||
@@ -128,7 +124,7 @@ Match source IP CIDR.
|
||||
|
||||
!!! info ""
|
||||
|
||||
`ip_cidr` is an alias for `source_ip_cidr` when the Rule Set is used in DNS rules or `rule_set_ipcidr_match_source` enabled in route rules.
|
||||
`ip_cidr` is an alias for `source_ip_cidr` when `rule_set_ipcidr_match_source` enabled in route/DNS rules.
|
||||
|
||||
Match IP CIDR.
|
||||
|
||||
@@ -172,7 +168,7 @@ Match android package name.
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
Match WiFi SSID.
|
||||
|
||||
@@ -180,7 +176,7 @@ Match WiFi SSID.
|
||||
|
||||
!!! quote ""
|
||||
|
||||
Only supported in graphical clients on Android and iOS.
|
||||
Only supported in graphical clients on Android and Apple platforms.
|
||||
|
||||
Match WiFi BSSID.
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
# Rule Set
|
||||
|
||||
!!! question "Since sing-box 1.8.0"
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
# Source Format
|
||||
|
||||
!!! question "Since sing-box 1.8.0"
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
|
||||
!!! quote "Changes in sing-box 1.8.0"
|
||||
|
||||
:material-alert-decagram: [utls](#utls)
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.8.0 中的更改"
|
||||
|
||||
:material-alert-decagram: [utls](#utls)
|
||||
|
||||
@@ -4,6 +4,12 @@ description: Welcome to the wiki page for the sing-box project.
|
||||
|
||||
# :material-home: Home
|
||||
|
||||
!!! failure "Help needed"
|
||||
|
||||
Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update.
|
||||
|
||||
If your company or organization is willing to help us return to the App Store, please [contact us](mailto:contact@sagernet.org).
|
||||
|
||||
Welcome to the wiki page for the sing-box project.
|
||||
|
||||
The universal proxy platform.
|
||||
|
||||
38
docs/manual/misc/tunnelvision.md
Normal file
38
docs/manual/misc/tunnelvision.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
icon: material/book-lock-open
|
||||
---
|
||||
|
||||
# TunnelVision
|
||||
|
||||
TunnelVision is an attack that uses DHCP option 121 to set higher priority routes
|
||||
so that traffic does not go through the VPN.
|
||||
|
||||
Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-3661
|
||||
|
||||
## Status
|
||||
|
||||
### Android
|
||||
|
||||
Android does not handle DHCP option 121 and is not affected.
|
||||
|
||||
### Apple platforms
|
||||
|
||||
Update [sing-box graphical client](/clients/apple/#download) to `1.9.0-rc.16` or newer,
|
||||
then enable `includeAllNetworks` in `Settings` — `Packet Tunnel` and you will be unaffected.
|
||||
|
||||
Note: when `includeAllNetworks` is enabled, the default TUN stack is changed to `gvisor`,
|
||||
and the `system` and `mixed` stacks are not available.
|
||||
|
||||
### Linux
|
||||
|
||||
Update sing-box to `1.9.0-rc.16` or newer, rules generated by `auto-route` are unaffected.
|
||||
|
||||
### Windows
|
||||
|
||||
No solution yet.
|
||||
|
||||
## Workarounds
|
||||
|
||||
* Don't connect to untrusted networks
|
||||
* Relay untrusted network through another device
|
||||
* Just ignore it
|
||||
@@ -1,208 +0,0 @@
|
||||
---
|
||||
icon: material/alpha-t-box
|
||||
---
|
||||
|
||||
# TUIC
|
||||
|
||||
A recently popular Chinese-made simple protocol based on QUIC, the selling point is the BBR congestion control algorithm.
|
||||
|
||||
!!! warning
|
||||
|
||||
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies.
|
||||
|
||||
| Specification | Binary Characteristics | Active Detect Hiddenness |
|
||||
|-----------------------------------------------------------|------------------------|--------------------------|
|
||||
| [GitHub](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: |
|
||||
|
||||
## Password Generator
|
||||
|
||||
| Generated UUID | Generated Password | Action |
|
||||
|------------------------|----------------------------|-----------------------------------------------------------------|
|
||||
| <code id="uuid"><code> | <code id="password"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
|
||||
|
||||
<script>
|
||||
function generateUUID() {
|
||||
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16 | 0,
|
||||
v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
document.getElementById("uuid").textContent = uuid;
|
||||
}
|
||||
function generatePassword() {
|
||||
const array = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(array);
|
||||
document.getElementById("password").textContent = btoa(String.fromCharCode.apply(null, array));
|
||||
}
|
||||
function generate() {
|
||||
generateUUID();
|
||||
generatePassword();
|
||||
}
|
||||
generate();
|
||||
</script>
|
||||
|
||||
## :material-server: Server Example
|
||||
|
||||
=== ":material-harddisk: With local certificate"
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"listen": "::",
|
||||
"listen_port": 8080,
|
||||
"users": [
|
||||
{
|
||||
"name": "sekai",
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>"
|
||||
}
|
||||
],
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"key_path": "/path/to/key.pem",
|
||||
"certificate_path": "/path/to/certificate.pem"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-auto-fix: With ACME"
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"listen": "::",
|
||||
"listen_port": 8080,
|
||||
"users": [
|
||||
{
|
||||
"name": "sekai",
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>"
|
||||
}
|
||||
],
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"acme": {
|
||||
"domain": "example.org",
|
||||
"email": "admin@example.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-cloud: With ACME and Cloudflare API"
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"listen": "::",
|
||||
"listen_port": 8080,
|
||||
"users": [
|
||||
{
|
||||
"name": "sekai",
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>"
|
||||
}
|
||||
],
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"acme": {
|
||||
"domain": "example.org",
|
||||
"email": "admin@example.org",
|
||||
"dns01_challenge": {
|
||||
"provider": "cloudflare",
|
||||
"api_token": "my_token"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## :material-cellphone-link: Client Example
|
||||
|
||||
=== ":material-web-check: With valid certificate"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080,
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>",
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-check: With self-sign certificate"
|
||||
|
||||
!!! info "Tip"
|
||||
|
||||
Use `sing-box merge` command to merge configuration and certificate into one file.
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080,
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>",
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"certificate_path": "/path/to/certificate.pem"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-alert: Ignore certificate verification"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080,
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>",
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"insecure": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -290,52 +290,6 @@ flowchart TB
|
||||
|
||||
=== ":material-dns: DNS rules"
|
||||
|
||||
!!! info
|
||||
|
||||
DNS rules are optional if FakeIP is used.
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "223.5.5.5",
|
||||
"detour": "direct"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"outbound": "any",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Direct",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Global",
|
||||
"server": "google"
|
||||
},
|
||||
{
|
||||
"geosite": "geolocation-cn",
|
||||
"server": "local"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-dns: DNS rules (1.8.0+)"
|
||||
|
||||
!!! info
|
||||
|
||||
DNS rules are optional if FakeIP is used.
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
@@ -382,74 +336,180 @@ flowchart TB
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-router-network: Route rules"
|
||||
=== ":material-dns: DNS rules (Enhanced, but slower) (1.9.0+)"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
=== ":material-shield-off: With DNS leaks"
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "or",
|
||||
"rules": [
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"protocol": "dns"
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"port": 53
|
||||
"tag": "local",
|
||||
"address": "https://223.5.5.5/dns-query",
|
||||
"detour": "direct"
|
||||
}
|
||||
],
|
||||
"outbound": "dns"
|
||||
},
|
||||
{
|
||||
"geoip": "private",
|
||||
"outbound": "direct"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Direct",
|
||||
"outbound": "direct"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Global",
|
||||
"outbound": "default"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "or",
|
||||
"rules": [
|
||||
{
|
||||
"port": 853
|
||||
"outbound": "any",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"network": "udp",
|
||||
"port": 443
|
||||
"clash_mode": "Direct",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"protocol": "stun"
|
||||
"clash_mode": "Global",
|
||||
"server": "google"
|
||||
},
|
||||
{
|
||||
"rule_set": "geosite-geolocation-cn",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Default",
|
||||
"server": "google"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": "geoip-cn"
|
||||
}
|
||||
],
|
||||
"server": "local"
|
||||
}
|
||||
],
|
||||
"outbound": "block"
|
||||
]
|
||||
},
|
||||
{
|
||||
"geosite": "geolocation-cn",
|
||||
"outbound": "direct"
|
||||
"route": {
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-geolocation-cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-geolocation-!cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geoip-cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"store_rdrc": true
|
||||
},
|
||||
"clash_api": {
|
||||
"default_mode": "Enhanced"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-router-network: Route rules (1.8.0+)"
|
||||
=== ":material-security: Without DNS leaks, but slower (1.9.0-alpha.2+)"
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "https://223.5.5.5/dns-query",
|
||||
"detour": "direct"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"outbound": "any",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Direct",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"clash_mode": "Global",
|
||||
"server": "google"
|
||||
},
|
||||
{
|
||||
"rule_set": "geosite-geolocation-cn",
|
||||
"server": "local"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": "geoip-cn"
|
||||
}
|
||||
],
|
||||
"server": "google",
|
||||
"client_subnet": "114.114.114.114/24" // Any China client IP address
|
||||
}
|
||||
]
|
||||
},
|
||||
"route": {
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-geolocation-cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-geolocation-!cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geoip-cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"experimental": {
|
||||
"cache_file": {
|
||||
"enabled": true,
|
||||
"store_rdrc": true
|
||||
},
|
||||
"clash_api": {
|
||||
"default_mode": "Enhanced"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-router-network: Route rules"
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@@ -2,6 +2,24 @@
|
||||
icon: material/arrange-bring-forward
|
||||
---
|
||||
|
||||
## 1.9.0
|
||||
|
||||
### `domain_suffix` behavior update
|
||||
|
||||
For historical reasons, sing-box's `domain_suffix` rule matches literal prefixes instead of the same as other projects.
|
||||
|
||||
sing-box 1.9.0 modifies the behavior of `domain_suffix`: If the rule value is prefixed with `.`,
|
||||
the behavior is unchanged, otherwise it matches `(domain|.+\.domain)` instead.
|
||||
|
||||
### `process_path` format update on Windows
|
||||
|
||||
The `process_path` rule of sing-box is inherited from Clash,
|
||||
the original code uses the local system's path format (e.g. `\Device\HarddiskVolume1\folder\program.exe`),
|
||||
but when the device has multiple disks, the HarddiskVolume serial number is not stable.
|
||||
|
||||
sing-box 1.9.0 make QueryFullProcessImageNameW output a Win32 path (such as `C:\folder\program.exe`),
|
||||
which will disrupt the existing `process_path` use cases in Windows.
|
||||
|
||||
## 1.8.0
|
||||
|
||||
### :material-close-box: Migrate cache file from Clash API to independent options
|
||||
|
||||
@@ -2,6 +2,23 @@
|
||||
icon: material/arrange-bring-forward
|
||||
---
|
||||
|
||||
## 1.9.0
|
||||
|
||||
### `domain_suffix` 行为更新
|
||||
|
||||
由于历史原因,sing-box 的 `domain_suffix` 规则匹配字面前缀,而不与其他项目相同。
|
||||
|
||||
sing-box 1.9.0 修改了 `domain_suffix` 的行为:如果规则值以 `.` 为前缀则行为不变,否则改为匹配 `(domain|.+\.domain)`。
|
||||
|
||||
### 对 Windows 上 `process_path` 格式的更新
|
||||
|
||||
sing-box 的 `process_path` 规则继承自Clash,
|
||||
原始代码使用本地系统的路径格式(例如 `\Device\HarddiskVolume1\folder\program.exe`),
|
||||
但是当设备有多个硬盘时,该 HarddiskVolume 系列号并不稳定。
|
||||
|
||||
sing-box 1.9.0 使 QueryFullProcessImageNameW 输出 Win32 路径(如 `C:\folder\program.exe`),
|
||||
这将会破坏现有的 Windows `process_path` 用例。
|
||||
|
||||
## 1.8.0
|
||||
|
||||
### :material-close-box: 将缓存文件从 Clash API 迁移到独立选项
|
||||
|
||||
@@ -5,8 +5,7 @@ icon: material/forum
|
||||
# Support
|
||||
|
||||
| Channel | Link |
|
||||
|:------------------------------|:--------------------------------------------|
|
||||
| Community | https://community.sagernet.org |
|
||||
| :---------------------------- | :------------------------------------------ |
|
||||
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
||||
| Telegram notification channel | https://t.me/yapnc |
|
||||
| Telegram user group | https://t.me/yapug |
|
||||
|
||||
@@ -4,11 +4,10 @@ icon: material/forum
|
||||
|
||||
# 支持
|
||||
|
||||
| 通道 | 链接 |
|
||||
|:--------------|:--------------------------------------------|
|
||||
| 社区 | https://community.sagernet.org |
|
||||
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
||||
| 通道 | 链接 |
|
||||
| :---------------- | :------------------------------------------ |
|
||||
| GitHub Issues | https://github.com/SagerNet/sing-box/issues |
|
||||
| Telegram 通知频道 | https://t.me/yapnc |
|
||||
| Telegram 用户组 | https://t.me/yapug |
|
||||
| 邮件 | contact@sagernet.org |
|
||||
| Telegram 用户组 | https://t.me/yapug |
|
||||
| 邮件 | contact@sagernet.org |
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ var (
|
||||
string(bucketExpand),
|
||||
string(bucketMode),
|
||||
string(bucketRuleSet),
|
||||
string(bucketRDRC),
|
||||
}
|
||||
|
||||
cacheIDDefault = []byte("default")
|
||||
@@ -37,17 +38,26 @@ var (
|
||||
var _ adapter.CacheFile = (*CacheFile)(nil)
|
||||
|
||||
type CacheFile struct {
|
||||
ctx context.Context
|
||||
path string
|
||||
cacheID []byte
|
||||
storeFakeIP bool
|
||||
|
||||
ctx context.Context
|
||||
path string
|
||||
cacheID []byte
|
||||
storeFakeIP bool
|
||||
storeRDRC bool
|
||||
rdrcTimeout time.Duration
|
||||
DB *bbolt.DB
|
||||
saveAccess sync.RWMutex
|
||||
saveMetadataTimer *time.Timer
|
||||
saveFakeIPAccess sync.RWMutex
|
||||
saveDomain map[netip.Addr]string
|
||||
saveAddress4 map[string]netip.Addr
|
||||
saveAddress6 map[string]netip.Addr
|
||||
saveMetadataTimer *time.Timer
|
||||
saveRDRCAccess sync.RWMutex
|
||||
saveRDRC map[saveRDRCCacheKey]bool
|
||||
}
|
||||
|
||||
type saveRDRCCacheKey struct {
|
||||
TransportName string
|
||||
QuestionName string
|
||||
QType uint16
|
||||
}
|
||||
|
||||
func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
|
||||
@@ -61,14 +71,25 @@ func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
|
||||
if options.CacheID != "" {
|
||||
cacheIDBytes = append([]byte{0}, []byte(options.CacheID)...)
|
||||
}
|
||||
var rdrcTimeout time.Duration
|
||||
if options.StoreRDRC {
|
||||
if options.RDRCTimeout > 0 {
|
||||
rdrcTimeout = time.Duration(options.RDRCTimeout)
|
||||
} else {
|
||||
rdrcTimeout = 7 * 24 * time.Hour
|
||||
}
|
||||
}
|
||||
return &CacheFile{
|
||||
ctx: ctx,
|
||||
path: filemanager.BasePath(ctx, path),
|
||||
cacheID: cacheIDBytes,
|
||||
storeFakeIP: options.StoreFakeIP,
|
||||
storeRDRC: options.StoreRDRC,
|
||||
rdrcTimeout: rdrcTimeout,
|
||||
saveDomain: make(map[netip.Addr]string),
|
||||
saveAddress4: make(map[string]netip.Addr),
|
||||
saveAddress6: make(map[string]netip.Addr),
|
||||
saveRDRC: make(map[saveRDRCCacheKey]bool),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
|
||||
}
|
||||
|
||||
func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
|
||||
c.saveAccess.Lock()
|
||||
c.saveFakeIPAccess.Lock()
|
||||
if oldDomain, loaded := c.saveDomain[address]; loaded {
|
||||
if address.Is4() {
|
||||
delete(c.saveAddress4, oldDomain)
|
||||
@@ -111,27 +111,27 @@ func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger l
|
||||
} else {
|
||||
c.saveAddress6[domain] = address
|
||||
}
|
||||
c.saveAccess.Unlock()
|
||||
c.saveFakeIPAccess.Unlock()
|
||||
go func() {
|
||||
err := c.FakeIPStore(address, domain)
|
||||
if err != nil {
|
||||
logger.Warn("save FakeIP address pair: ", err)
|
||||
logger.Warn("save FakeIP cache: ", err)
|
||||
}
|
||||
c.saveAccess.Lock()
|
||||
c.saveFakeIPAccess.Lock()
|
||||
delete(c.saveDomain, address)
|
||||
if address.Is4() {
|
||||
delete(c.saveAddress4, domain)
|
||||
} else {
|
||||
delete(c.saveAddress6, domain)
|
||||
}
|
||||
c.saveAccess.Unlock()
|
||||
c.saveFakeIPAccess.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *CacheFile) FakeIPLoad(address netip.Addr) (string, bool) {
|
||||
c.saveAccess.RLock()
|
||||
c.saveFakeIPAccess.RLock()
|
||||
cachedDomain, cached := c.saveDomain[address]
|
||||
c.saveAccess.RUnlock()
|
||||
c.saveFakeIPAccess.RUnlock()
|
||||
if cached {
|
||||
return cachedDomain, true
|
||||
}
|
||||
@@ -152,13 +152,13 @@ func (c *CacheFile) FakeIPLoadDomain(domain string, isIPv6 bool) (netip.Addr, bo
|
||||
cachedAddress netip.Addr
|
||||
cached bool
|
||||
)
|
||||
c.saveAccess.RLock()
|
||||
c.saveFakeIPAccess.RLock()
|
||||
if !isIPv6 {
|
||||
cachedAddress, cached = c.saveAddress4[domain]
|
||||
} else {
|
||||
cachedAddress, cached = c.saveAddress6[domain]
|
||||
}
|
||||
c.saveAccess.RUnlock()
|
||||
c.saveFakeIPAccess.RUnlock()
|
||||
if cached {
|
||||
return cachedAddress, true
|
||||
}
|
||||
|
||||
109
experimental/cachefile/rdrc.go
Normal file
109
experimental/cachefile/rdrc.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package cachefile
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/bbolt"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
)
|
||||
|
||||
var bucketRDRC = []byte("rdrc2")
|
||||
|
||||
func (c *CacheFile) StoreRDRC() bool {
|
||||
return c.storeRDRC
|
||||
}
|
||||
|
||||
func (c *CacheFile) RDRCTimeout() time.Duration {
|
||||
return c.rdrcTimeout
|
||||
}
|
||||
|
||||
func (c *CacheFile) LoadRDRC(transportName string, qName string, qType uint16) (rejected bool) {
|
||||
c.saveRDRCAccess.RLock()
|
||||
rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName, qType}]
|
||||
c.saveRDRCAccess.RUnlock()
|
||||
if cached {
|
||||
return
|
||||
}
|
||||
key := buf.Get(2 + len(qName))
|
||||
binary.BigEndian.PutUint16(key, qType)
|
||||
copy(key[2:], qName)
|
||||
defer buf.Put(key)
|
||||
var deleteCache bool
|
||||
err := c.DB.View(func(tx *bbolt.Tx) error {
|
||||
bucket := c.bucket(tx, bucketRDRC)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
bucket = bucket.Bucket([]byte(transportName))
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
content := bucket.Get(key)
|
||||
if content == nil {
|
||||
return nil
|
||||
}
|
||||
expiresAt := time.Unix(int64(binary.BigEndian.Uint64(content)), 0)
|
||||
if time.Now().After(expiresAt) {
|
||||
deleteCache = true
|
||||
return nil
|
||||
}
|
||||
rejected = true
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if deleteCache {
|
||||
c.DB.Update(func(tx *bbolt.Tx) error {
|
||||
bucket := c.bucket(tx, bucketRDRC)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
bucket = bucket.Bucket([]byte(transportName))
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
return bucket.Delete(key)
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) error {
|
||||
return c.DB.Batch(func(tx *bbolt.Tx) error {
|
||||
bucket, err := c.createBucket(tx, bucketRDRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bucket, err = bucket.CreateBucketIfNotExists([]byte(transportName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := buf.Get(2 + len(qName))
|
||||
binary.BigEndian.PutUint16(key, qType)
|
||||
copy(key[2:], qName)
|
||||
defer buf.Put(key)
|
||||
expiresAt := buf.Get(8)
|
||||
defer buf.Put(expiresAt)
|
||||
binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix()))
|
||||
return bucket.Put(key, expiresAt)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger) {
|
||||
saveKey := saveRDRCCacheKey{transportName, qName, qType}
|
||||
c.saveRDRCAccess.Lock()
|
||||
c.saveRDRC[saveKey] = true
|
||||
c.saveRDRCAccess.Unlock()
|
||||
go func() {
|
||||
err := c.SaveRDRC(transportName, qName, qType)
|
||||
if err != nil {
|
||||
logger.Warn("save RDRC: ", err)
|
||||
}
|
||||
c.saveRDRCAccess.Lock()
|
||||
delete(c.saveRDRC, saveKey)
|
||||
c.saveRDRCAccess.Unlock()
|
||||
}()
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package experimental
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
@@ -27,11 +28,26 @@ func NewClashServer(ctx context.Context, router adapter.Router, logFactory log.O
|
||||
}
|
||||
|
||||
func CalculateClashModeList(options option.Options) []string {
|
||||
var clashMode []string
|
||||
clashMode = append(clashMode, extraClashModeFromRule(common.PtrValueOrDefault(options.Route).Rules)...)
|
||||
clashMode = append(clashMode, extraClashModeFromDNSRule(common.PtrValueOrDefault(options.DNS).Rules)...)
|
||||
clashMode = common.FilterNotDefault(common.Uniq(clashMode))
|
||||
return clashMode
|
||||
var clashModes []string
|
||||
clashModes = append(clashModes, extraClashModeFromRule(common.PtrValueOrDefault(options.Route).Rules)...)
|
||||
clashModes = append(clashModes, extraClashModeFromDNSRule(common.PtrValueOrDefault(options.DNS).Rules)...)
|
||||
clashModes = common.FilterNotDefault(common.Uniq(clashModes))
|
||||
predefinedOrder := []string{
|
||||
"Rule", "Global", "Direct",
|
||||
}
|
||||
var newClashModes []string
|
||||
for _, mode := range clashModes {
|
||||
if !common.Contains(predefinedOrder, mode) {
|
||||
newClashModes = append(newClashModes, mode)
|
||||
}
|
||||
}
|
||||
sort.Strings(newClashModes)
|
||||
for _, mode := range predefinedOrder {
|
||||
if common.Contains(clashModes, mode) {
|
||||
newClashModes = append(newClashModes, mode)
|
||||
}
|
||||
}
|
||||
return newClashModes
|
||||
}
|
||||
|
||||
func extraClashModeFromRule(rules []option.Rule) []string {
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/sagernet/sing-box"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/process"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
@@ -75,7 +74,7 @@ func (s *platformInterfaceStub) UsePlatformInterfaceGetter() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) Interfaces() ([]platform.NetworkInterface, error) {
|
||||
func (s *platformInterfaceStub) Interfaces() ([]control.Interface, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
@@ -83,6 +82,10 @@ func (s *platformInterfaceStub) UnderNetworkExtension() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) IncludeAllNetworks() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) ClearDNSCache() {
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@ import (
|
||||
"github.com/sagernet/sing-dns"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/task"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
@@ -25,9 +23,11 @@ type LocalDNSTransport interface {
|
||||
|
||||
func RegisterLocalDNSTransport(transport LocalDNSTransport) {
|
||||
if transport == nil {
|
||||
dns.RegisterTransport([]string{"local"}, dns.CreateLocalTransport)
|
||||
dns.RegisterTransport([]string{"local"}, func(options dns.TransportOptions) (dns.Transport, error) {
|
||||
return dns.NewLocalTransport(options), nil
|
||||
})
|
||||
} else {
|
||||
dns.RegisterTransport([]string{"local"}, func(name string, ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
||||
dns.RegisterTransport([]string{"local"}, func(options dns.TransportOptions) (dns.Transport, error) {
|
||||
return &platformLocalDNSTransport{
|
||||
iif: transport,
|
||||
}, nil
|
||||
|
||||
@@ -19,6 +19,7 @@ type PlatformInterface interface {
|
||||
UsePlatformInterfaceGetter() bool
|
||||
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||
UnderNetworkExtension() bool
|
||||
IncludeAllNetworks() bool
|
||||
ReadWIFIState() *WIFIState
|
||||
ClearDNSCache()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package platform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/process"
|
||||
@@ -20,16 +19,10 @@ type Interface interface {
|
||||
UsePlatformDefaultInterfaceMonitor() bool
|
||||
CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
|
||||
UsePlatformInterfaceGetter() bool
|
||||
Interfaces() ([]NetworkInterface, error)
|
||||
Interfaces() ([]control.Interface, error)
|
||||
UnderNetworkExtension() bool
|
||||
IncludeAllNetworks() bool
|
||||
ClearDNSCache()
|
||||
ReadWIFIState() adapter.WIFIState
|
||||
process.Searcher
|
||||
}
|
||||
|
||||
type NetworkInterface struct {
|
||||
Index int
|
||||
MTU int
|
||||
Name string
|
||||
Addresses []netip.Prefix
|
||||
}
|
||||
|
||||
@@ -192,14 +192,14 @@ func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
|
||||
return w.iif.UsePlatformInterfaceGetter()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) Interfaces() ([]platform.NetworkInterface, error) {
|
||||
func (w *platformInterfaceWrapper) Interfaces() ([]control.Interface, error) {
|
||||
interfaceIterator, err := w.iif.GetInterfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var interfaces []platform.NetworkInterface
|
||||
var interfaces []control.Interface
|
||||
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
|
||||
interfaces = append(interfaces, platform.NetworkInterface{
|
||||
interfaces = append(interfaces, control.Interface{
|
||||
Index: int(netInterface.Index),
|
||||
MTU: int(netInterface.MTU),
|
||||
Name: netInterface.Name,
|
||||
@@ -213,6 +213,10 @@ func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
|
||||
return w.iif.UnderNetworkExtension()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) IncludeAllNetworks() bool {
|
||||
return w.iif.IncludeAllNetworks()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) ClearDNSCache() {
|
||||
w.iif.ClearDNSCache()
|
||||
}
|
||||
|
||||
@@ -16,25 +16,18 @@ func (s *BoxService) Pause() {
|
||||
if s.pauseTimer != nil {
|
||||
s.pauseTimer.Stop()
|
||||
}
|
||||
s.pauseTimer = time.AfterFunc(time.Minute, s.pause)
|
||||
}
|
||||
|
||||
func (s *BoxService) pause() {
|
||||
s.pauseAccess.Lock()
|
||||
defer s.pauseAccess.Unlock()
|
||||
s.pauseManager.DevicePause()
|
||||
_ = s.instance.Router().ResetNetwork()
|
||||
s.pauseTimer = nil
|
||||
s.pauseTimer = time.AfterFunc(3*time.Second, s.ResetNetwork)
|
||||
}
|
||||
|
||||
func (s *BoxService) Wake() {
|
||||
_ = s.instance.Router().ResetNetwork()
|
||||
s.pauseAccess.Lock()
|
||||
defer s.pauseAccess.Unlock()
|
||||
if s.pauseTimer != nil {
|
||||
s.pauseTimer.Stop()
|
||||
s.pauseTimer = nil
|
||||
return
|
||||
}
|
||||
s.pauseManager.DeviceWake()
|
||||
s.pauseTimer = time.AfterFunc(3*time.Minute, s.ResetNetwork)
|
||||
}
|
||||
|
||||
func (s *BoxService) ResetNetwork() {
|
||||
_ = s.instance.Router().ResetNetwork()
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/sagernet/sing-box/common/humanize"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
_ "github.com/sagernet/sing-box/include"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -28,6 +28,8 @@ type TunOptions interface {
|
||||
IsHTTPProxyEnabled() bool
|
||||
GetHTTPProxyServer() string
|
||||
GetHTTPProxyServerPort() int32
|
||||
GetHTTPProxyBypassDomain() StringIterator
|
||||
GetHTTPProxyMatchDomain() StringIterator
|
||||
}
|
||||
|
||||
type RoutePrefix struct {
|
||||
@@ -156,3 +158,11 @@ func (o *tunOptions) GetHTTPProxyServer() string {
|
||||
func (o *tunOptions) GetHTTPProxyServerPort() int32 {
|
||||
return int32(o.TunPlatformOptions.HTTPProxy.ServerPort)
|
||||
}
|
||||
|
||||
func (o *tunOptions) GetHTTPProxyBypassDomain() StringIterator {
|
||||
return newIterator(o.TunPlatformOptions.HTTPProxy.BypassDomain)
|
||||
}
|
||||
|
||||
func (o *tunOptions) GetHTTPProxyMatchDomain() StringIterator {
|
||||
return newIterator(o.TunPlatformOptions.HTTPProxy.MatchDomain)
|
||||
}
|
||||
|
||||
34
go.mod
34
go.mod
@@ -11,7 +11,7 @@ require (
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/gofrs/uuid/v5 v5.1.0
|
||||
github.com/gofrs/uuid/v5 v5.2.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2
|
||||
github.com/libdns/alidns v1.0.3
|
||||
github.com/libdns/cloudflare v0.1.1
|
||||
@@ -23,18 +23,18 @@ require (
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1
|
||||
github.com/sagernet/gomobile v0.1.3
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e
|
||||
github.com/sagernet/quic-go v0.40.1
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
||||
github.com/sagernet/quic-go v0.46.0-beta.4
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.3.8
|
||||
github.com/sagernet/sing-dns v0.1.14
|
||||
github.com/sagernet/sing v0.4.2
|
||||
github.com/sagernet/sing-dns v0.2.3
|
||||
github.com/sagernet/sing-mux v0.2.0
|
||||
github.com/sagernet/sing-quic v0.1.12
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6
|
||||
github.com/sagernet/sing-quic v0.2.2
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.2.7
|
||||
github.com/sagernet/sing-vmess v0.1.8
|
||||
github.com/sagernet/sing-tun v0.3.2
|
||||
github.com/sagernet/sing-vmess v0.1.12
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6
|
||||
github.com/sagernet/utls v1.5.4
|
||||
@@ -44,9 +44,9 @@ require (
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.uber.org/zap v1.27.0
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/sys v0.19.0
|
||||
golang.org/x/crypto v0.23.0
|
||||
golang.org/x/net v0.25.0
|
||||
golang.org/x/sys v0.21.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
google.golang.org/grpc v1.63.2
|
||||
google.golang.org/protobuf v1.33.0
|
||||
@@ -78,20 +78,20 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.20.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
)
|
||||
|
||||
70
go.sum
70
go.sum
@@ -34,8 +34,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gofrs/uuid/v5 v5.1.0 h1:S5rqVKIigghZTCBKPCw0Y+bXkn26K3TB5mvQq2Ix8dk=
|
||||
github.com/gofrs/uuid/v5 v5.1.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM=
|
||||
github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
@@ -97,33 +97,33 @@ github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQ
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k=
|
||||
github.com/sagernet/gomobile v0.1.3 h1:ohjIb1Ou2+1558PnZour3od69suSuvkdSVOlO1tC4B8=
|
||||
github.com/sagernet/gomobile v0.1.3/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e h1:DOkjByVeAR56dkszjnMZke4wr7yM/1xHaJF3G9olkEE=
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e/go.mod h1:fLxq/gtp0qzkaEwywlRRiGmjOK5ES/xUzyIKIFP2Asw=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.40.1 h1:qLeTIJR0d0JWRmDWo346nLsVN6EWihd1kalJYPEd0TM=
|
||||
github.com/sagernet/quic-go v0.40.1/go.mod h1:CcKTpzTAISxrM4PA5M20/wYuz9Tj6Tx4DwGbNl9UQrU=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.46.0-beta.4 h1:k9f7VSKaM47AY6MPND0Qf1KRN7HwimPg9zdOFTXTiCk=
|
||||
github.com/sagernet/quic-go v0.46.0-beta.4/go.mod h1:zJmVdJUNqEDXfubf4KtIOUHHerggjBduiGRLNzJspcM=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.3.8 h1:gm4JKalPhydMYX2zFOTnnd4TXtM/16WFRqSjMepYQQk=
|
||||
github.com/sagernet/sing v0.3.8/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI=
|
||||
github.com/sagernet/sing-dns v0.1.14 h1:kxE/Ik3jMXmD3sXsdt9MgrNzLFWt64mghV+MQqzyf40=
|
||||
github.com/sagernet/sing-dns v0.1.14/go.mod h1:AA+vZMNovuPN5i/sPnfF6756Nq94nzb5nXodMWbta5w=
|
||||
github.com/sagernet/sing v0.4.2 h1:jzGNJdZVRI0xlAfFugsIQUPvyB9SuWvbJK7zQCXc4QM=
|
||||
github.com/sagernet/sing v0.4.2/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
|
||||
github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
|
||||
github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
|
||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
|
||||
github.com/sagernet/sing-quic v0.1.12 h1:4KjG7LASZck0svGDfzf3aVNidRRQRC/w2HUMk/PHiNE=
|
||||
github.com/sagernet/sing-quic v0.1.12/go.mod h1:L+VtzvuPbf8VW8F4R7KiygqpXY4lO7t2wwcQuHjh8Ew=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
|
||||
github.com/sagernet/sing-quic v0.2.2 h1:Ryp02zMhHh/ZDrG7MdLsmhuBU8+BEpOdJonFQiqIopo=
|
||||
github.com/sagernet/sing-quic v0.2.2/go.mod h1:YLV1dUDv8Eyp/8e55O/EvfsrwxOgEDVgDCIoPqmDREE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.2.7 h1:6QtJkeSj6BTTQPGxbbiuV8eh7GdV46w2G0N8CmISwdc=
|
||||
github.com/sagernet/sing-tun v0.2.7/go.mod h1:MKAAHUzVfj7d9zos4lsz6wjXu86/mJyd/gejiAnWj/w=
|
||||
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
|
||||
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
|
||||
github.com/sagernet/sing-tun v0.3.2 h1:z0bLUT/YXH9RrJS9DsIpB0Bb9afl2hVJOmHd0zA3HJY=
|
||||
github.com/sagernet/sing-tun v0.3.2/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ=
|
||||
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
|
||||
github.com/sagernet/sing-vmess v0.1.12/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/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26Wn/UByW6b7q8QKB0ZkPqsyqcz2PI=
|
||||
@@ -163,16 +163,16 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -184,19 +184,19 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
|
||||
@@ -214,5 +214,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
|
||||
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
|
||||
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -16,6 +18,9 @@ func (a *myInboundAdapter) ListenTCP() (net.Listener, error) {
|
||||
bindAddr := M.SocksaddrFrom(a.listenOptions.Listen.Build(), a.listenOptions.ListenPort)
|
||||
var tcpListener net.Listener
|
||||
var listenConfig net.ListenConfig
|
||||
// TODO: Add an option to customize the keep alive period
|
||||
listenConfig.KeepAlive = C.TCPKeepAliveInitial
|
||||
listenConfig.Control = control.Append(listenConfig.Control, control.SetKeepAlivePeriod(C.TCPKeepAliveInitial, C.TCPKeepAliveInterval))
|
||||
if a.listenOptions.TCPMultiPath {
|
||||
if !go121Available {
|
||||
return nil, E.New("MultiPath TCP requires go1.21, please recompile your binary.")
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/sagernet/sing-box/common/tls"
|
||||
"github.com/sagernet/sing-box/common/uot"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/include"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
@@ -109,8 +108,8 @@ func (n *Naive) Start() error {
|
||||
|
||||
if common.Contains(n.network, N.NetworkUDP) {
|
||||
err := n.configureHTTP3Listener()
|
||||
if !include.WithQUIC && len(n.network) > 1 {
|
||||
log.Warn(E.Cause(err, "naive http3 disabled"))
|
||||
if !C.WithQUIC && len(n.network) > 1 {
|
||||
n.logger.Warn(E.Cause(err, "naive http3 disabled"))
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -166,7 +166,15 @@ func (t *Tun) Start() error {
|
||||
}
|
||||
t.logger.Trace("creating stack")
|
||||
t.tunIf = tunInterface
|
||||
t.tunStack, err = tun.NewStack(t.stack, tun.StackOptions{
|
||||
var (
|
||||
forwarderBindInterface bool
|
||||
includeAllNetworks bool
|
||||
)
|
||||
if t.platformInterface != nil {
|
||||
forwarderBindInterface = true
|
||||
includeAllNetworks = t.platformInterface.IncludeAllNetworks()
|
||||
}
|
||||
tunStack, err := tun.NewStack(t.stack, tun.StackOptions{
|
||||
Context: t.ctx,
|
||||
Tun: tunInterface,
|
||||
TunOptions: t.tunOptions,
|
||||
@@ -174,15 +182,17 @@ func (t *Tun) Start() error {
|
||||
UDPTimeout: t.udpTimeout,
|
||||
Handler: t,
|
||||
Logger: t.logger,
|
||||
ForwarderBindInterface: t.platformInterface != nil,
|
||||
ForwarderBindInterface: forwarderBindInterface,
|
||||
InterfaceFinder: t.router.InterfaceFinder(),
|
||||
IncludeAllNetworks: includeAllNetworks,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
monitor.Start("initiating tun stack")
|
||||
err = t.tunStack.Start()
|
||||
err = tunStack.Start()
|
||||
monitor.Finish()
|
||||
t.tunStack = tunStack
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/transport/v2ray"
|
||||
"github.com/sagernet/sing-box/transport/vless"
|
||||
"github.com/sagernet/sing-vmess"
|
||||
"github.com/sagernet/sing-vmess/packetaddr"
|
||||
"github.com/sagernet/sing-vmess/vless"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
@@ -3,16 +3,12 @@
|
||||
package include
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-dns"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dns.RegisterTransport([]string{"dhcp"}, func(name string, ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
||||
dns.RegisterTransport([]string{"dhcp"}, func(options dns.TransportOptions) (dns.Transport, error) {
|
||||
return nil, E.New(`DHCP is not included in this build, rebuild with -tags with_dhcp`)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,5 +6,3 @@ import (
|
||||
_ "github.com/sagernet/sing-box/transport/v2rayquic"
|
||||
_ "github.com/sagernet/sing-dns/quic"
|
||||
)
|
||||
|
||||
const WithQUIC = true
|
||||
|
||||
@@ -11,15 +11,12 @@ import (
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/transport/v2ray"
|
||||
"github.com/sagernet/sing-dns"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
const WithQUIC = false
|
||||
|
||||
func init() {
|
||||
dns.RegisterTransport([]string{"quic", "h3"}, func(name string, ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
||||
dns.RegisterTransport([]string{"quic", "h3"}, func(options dns.TransportOptions) (dns.Transport, error) {
|
||||
return nil, C.ErrQUICNotIncluded
|
||||
})
|
||||
v2ray.RegisterQUICConstructor(
|
||||
|
||||
21
include/tz_android.go
Normal file
21
include/tz_android.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// kanged from https://github.com/golang/mobile/blob/c713f31d574bb632a93f169b2cc99c9e753fef0e/app/android.go#L89
|
||||
|
||||
package include
|
||||
|
||||
// #include <time.h>
|
||||
import "C"
|
||||
import "time"
|
||||
|
||||
func init() {
|
||||
var currentT C.time_t
|
||||
var currentTM C.struct_tm
|
||||
C.time(¤tT)
|
||||
C.localtime_r(¤tT, ¤tTM)
|
||||
tzOffset := int(currentTM.tm_gmtoff)
|
||||
tz := C.GoString(currentTM.tm_zone)
|
||||
time.Local = time.FixedZone(tz, tzOffset)
|
||||
}
|
||||
30
include/tz_ios.go
Normal file
30
include/tz_ios.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package include
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation
|
||||
#import <Foundation/Foundation.h>
|
||||
const char* getSystemTimeZone() {
|
||||
NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
|
||||
NSString *timeZoneName = [timeZone description];
|
||||
return [timeZoneName UTF8String];
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tzDescription := C.GoString(C.getSystemTimeZone())
|
||||
if len(tzDescription) == 0 {
|
||||
return
|
||||
}
|
||||
location, err := time.LoadLocation(strings.Split(tzDescription, " ")[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
time.Local = location
|
||||
}
|
||||
@@ -66,8 +66,9 @@ nav:
|
||||
- Proxy Protocol:
|
||||
- Shadowsocks: manual/proxy-protocol/shadowsocks.md
|
||||
- Trojan: manual/proxy-protocol/trojan.md
|
||||
- TUIC: manual/proxy-protocol/tuic.md
|
||||
- Hysteria 2: manual/proxy-protocol/hysteria2.md
|
||||
- Misc:
|
||||
- TunnelVision: manual/misc/tunnelvision.md
|
||||
- Configuration:
|
||||
- configuration/index.md
|
||||
- Log:
|
||||
|
||||
112
ntp/service.go
112
ntp/service.go
@@ -1,112 +0,0 @@
|
||||
package ntp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
"github.com/sagernet/sing-box/common/settings"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/ntp"
|
||||
)
|
||||
|
||||
var _ ntp.TimeService = (*Service)(nil)
|
||||
|
||||
type Service struct {
|
||||
ctx context.Context
|
||||
cancel common.ContextCancelCauseFunc
|
||||
server M.Socksaddr
|
||||
writeToSystem bool
|
||||
dialer N.Dialer
|
||||
logger logger.Logger
|
||||
ticker *time.Ticker
|
||||
clockOffset time.Duration
|
||||
}
|
||||
|
||||
func NewService(ctx context.Context, router adapter.Router, logger logger.Logger, options option.NTPOptions) (*Service, error) {
|
||||
ctx, cancel := common.ContextWithCancelCause(ctx)
|
||||
server := M.ParseSocksaddrHostPort(options.Server, options.ServerPort)
|
||||
if server.Port == 0 {
|
||||
server.Port = 123
|
||||
}
|
||||
var interval time.Duration
|
||||
if options.Interval > 0 {
|
||||
interval = time.Duration(options.Interval)
|
||||
} else {
|
||||
interval = 30 * time.Minute
|
||||
}
|
||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Service{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
server: server,
|
||||
writeToSystem: options.WriteToSystem,
|
||||
dialer: outboundDialer,
|
||||
logger: logger,
|
||||
ticker: time.NewTicker(interval),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Service) Start() error {
|
||||
err := s.update()
|
||||
if err != nil {
|
||||
return E.Cause(err, "initialize time")
|
||||
}
|
||||
s.logger.Info("updated time: ", s.TimeFunc()().Local().Format(C.TimeLayout))
|
||||
go s.loopUpdate()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) Close() error {
|
||||
s.ticker.Stop()
|
||||
s.cancel(os.ErrClosed)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) TimeFunc() func() time.Time {
|
||||
return func() time.Time {
|
||||
return time.Now().Add(s.clockOffset)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) loopUpdate() {
|
||||
for {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case <-s.ticker.C:
|
||||
}
|
||||
err := s.update()
|
||||
if err == nil {
|
||||
s.logger.Debug("updated time: ", s.TimeFunc()().Local().Format(C.TimeLayout))
|
||||
} else {
|
||||
s.logger.Warn("update time: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) update() error {
|
||||
response, err := ntp.Exchange(s.ctx, s.dialer, s.server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.clockOffset = response.ClockOffset
|
||||
if s.writeToSystem {
|
||||
writeErr := settings.SetSystemTime(s.TimeFunc()())
|
||||
if writeErr != nil {
|
||||
s.logger.Warn("write time to system: ", writeErr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -19,6 +19,7 @@ type DNSServerOptions struct {
|
||||
AddressFallbackDelay Duration `json:"address_fallback_delay,omitempty"`
|
||||
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||
Detour string `json:"detour,omitempty"`
|
||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
||||
}
|
||||
|
||||
type DNSClientOptions struct {
|
||||
@@ -26,6 +27,7 @@ type DNSClientOptions struct {
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
DisableExpire bool `json:"disable_expire,omitempty"`
|
||||
IndependentCache bool `json:"independent_cache,omitempty"`
|
||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
||||
}
|
||||
|
||||
type DNSFakeIPOptions struct {
|
||||
|
||||
@@ -8,10 +8,12 @@ type ExperimentalOptions struct {
|
||||
}
|
||||
|
||||
type CacheFileOptions struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
CacheID string `json:"cache_id,omitempty"`
|
||||
StoreFakeIP bool `json:"store_fakeip,omitempty"`
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
CacheID string `json:"cache_id,omitempty"`
|
||||
StoreFakeIP bool `json:"store_fakeip,omitempty"`
|
||||
StoreRDRC bool `json:"store_rdrc,omitempty"`
|
||||
RDRCTimeout Duration `json:"rdrc_timeout,omitempty"`
|
||||
}
|
||||
|
||||
type ClashAPIOptions struct {
|
||||
|
||||
@@ -2,9 +2,8 @@ package option
|
||||
|
||||
type NTPOptions struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
ServerPort uint16 `json:"server_port,omitempty"`
|
||||
Interval Duration `json:"interval,omitempty"`
|
||||
WriteToSystem bool `json:"write_to_system,omitempty"`
|
||||
ServerOptions
|
||||
DialerOptions
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user