mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-13 20:28:32 +10:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ce4e31fc8 | ||
|
|
d2d4faf520 | ||
|
|
438de36749 | ||
|
|
df0eef770e | ||
|
|
bbdd495ed5 | ||
|
|
d686172854 | ||
|
|
e1d96cb64e | ||
|
|
d5f94b65b7 | ||
|
|
ec2d0b6b3c | ||
|
|
3a92bf993d | ||
|
|
ec13965fd0 | ||
|
|
ddf747006e | ||
|
|
4382093868 | ||
|
|
a5322850b3 | ||
|
|
407b08975c | ||
|
|
c7067ff5e8 | ||
|
|
9b2384b296 | ||
|
|
b498a22972 | ||
|
|
20e9da5c67 | ||
|
|
ec8974673b | ||
|
|
5e6e7923e4 | ||
|
|
de1b5971e1 | ||
|
|
5c20d0b4d5 | ||
|
|
9df96ac7f1 | ||
|
|
87cd925144 | ||
|
|
fecb796000 | ||
|
|
cfb6c804aa | ||
|
|
11c50c7558 | ||
|
|
34cc7f176e | ||
|
|
b54da9c6af | ||
|
|
f44f86b832 | ||
|
|
4ebf40f582 | ||
|
|
53e4302143 | ||
|
|
cf778eda4f | ||
|
|
bb63429079 | ||
|
|
f7f9a7ae20 | ||
|
|
8699412a4c | ||
|
|
0d7aa19cd1 | ||
|
|
50a7295360 | ||
|
|
e57b6ae98d | ||
|
|
6843970536 | ||
|
|
62425ad3e4 | ||
|
|
e1e217854e | ||
|
|
5bf177b021 | ||
|
|
72dbf2e2b4 | ||
|
|
46c318c6fe | ||
|
|
05bb1b88c3 | ||
|
|
5176ea9fe0 | ||
|
|
36d349acd2 | ||
|
|
4feee983b5 | ||
|
|
9b12e3e389 | ||
|
|
afd3464216 | ||
|
|
8b64446274 | ||
|
|
28aa4c4d1f | ||
|
|
0be3cdc8fb | ||
|
|
f8be484019 | ||
|
|
35f03f092d | ||
|
|
c3d7401ead | ||
|
|
4db7eb9d9e | ||
|
|
fd4efd6104 | ||
|
|
19a35ec6a4 | ||
|
|
2012c0ca1e | ||
|
|
187421c754 | ||
|
|
b3fb86d415 | ||
|
|
88fafd4e30 |
12
.github/workflows/debug.yml
vendored
12
.github/workflows/debug.yml
vendored
@@ -31,12 +31,6 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ steps.version.outputs.go_version }}
|
go-version: ${{ steps.version.outputs.go_version }}
|
||||||
- name: Cache go module
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: go-${{ hashFiles('**/go.sum') }}
|
|
||||||
- name: Add cache to Go proxy
|
- name: Add cache to Go proxy
|
||||||
run: |
|
run: |
|
||||||
version=`git rev-parse HEAD`
|
version=`git rev-parse HEAD`
|
||||||
@@ -196,12 +190,6 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ steps.version.outputs.go_version }}
|
go-version: ${{ steps.version.outputs.go_version }}
|
||||||
- name: Cache go module
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: go-${{ hashFiles('**/go.sum') }}
|
|
||||||
- name: Build
|
- name: Build
|
||||||
id: build
|
id: build
|
||||||
run: make
|
run: make
|
||||||
|
|||||||
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
@@ -31,12 +31,6 @@ jobs:
|
|||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: ${{ steps.version.outputs.go_version }}
|
go-version: ${{ steps.version.outputs.go_version }}
|
||||||
- name: Cache go module
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/go/pkg/mod
|
|
||||||
key: go-${{ hashFiles('**/go.sum') }}
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -117,9 +117,6 @@ nfpms:
|
|||||||
dst: /etc/systemd/system/sing-box@.service
|
dst: /etc/systemd/system/sing-box@.service
|
||||||
- src: LICENSE
|
- src: LICENSE
|
||||||
dst: /usr/share/licenses/sing-box/LICENSE
|
dst: /usr/share/licenses/sing-box/LICENSE
|
||||||
scripts:
|
|
||||||
postinstall: release/config/postinstall.sh
|
|
||||||
postremove: release/config/postremove.sh
|
|
||||||
source:
|
source:
|
||||||
enabled: false
|
enabled: false
|
||||||
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
|
name_template: '{{ .ProjectName }}-{{ .Version }}.source'
|
||||||
|
|||||||
13
Makefile
13
Makefile
@@ -77,13 +77,20 @@ test_stdio:
|
|||||||
go mod tidy && \
|
go mod tidy && \
|
||||||
go test -v -tags "$(TAGS_TEST),force_stdio" .
|
go test -v -tags "$(TAGS_TEST),force_stdio" .
|
||||||
|
|
||||||
|
android:
|
||||||
|
go run ./cmd/internal/build_libbox -target android
|
||||||
|
|
||||||
|
ios:
|
||||||
|
go run ./cmd/internal/build_libbox -target ios
|
||||||
|
|
||||||
lib:
|
lib:
|
||||||
go run ./cmd/internal/build_libbox
|
go run ./cmd/internal/build_libbox -target android
|
||||||
|
go run ./cmd/internal/build_libbox -target ios
|
||||||
|
|
||||||
lib_install:
|
lib_install:
|
||||||
go get -v -d
|
go get -v -d
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.0.0-20221130124640-349ebaa752ca
|
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.0.0-20230413023804-244d7ff07035
|
||||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.0.0-20221130124640-349ebaa752ca
|
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.0.0-20230413023804-244d7ff07035
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin dist sing-box
|
rm -rf bin dist sing-box
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ The universal proxy platform.
|
|||||||
|
|
||||||
https://sing-box.sagernet.org
|
https://sing-box.sagernet.org
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
https://community.sagernet.org/c/sing-box/
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ type Router interface {
|
|||||||
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
|
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
|
||||||
|
|
||||||
InterfaceFinder() control.InterfaceFinder
|
InterfaceFinder() control.InterfaceFinder
|
||||||
|
UpdateInterfaces() error
|
||||||
DefaultInterface() string
|
DefaultInterface() string
|
||||||
AutoDetectInterface() bool
|
AutoDetectInterface() bool
|
||||||
AutoDetectInterfaceFunc() control.Func
|
AutoDetectInterfaceFunc() control.Func
|
||||||
|
|||||||
142
box.go
142
box.go
@@ -9,7 +9,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/experimental"
|
"github.com/sagernet/sing-box/experimental"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||||
"github.com/sagernet/sing-box/inbound"
|
"github.com/sagernet/sing-box/inbound"
|
||||||
@@ -31,18 +30,25 @@ type Box struct {
|
|||||||
outbounds []adapter.Outbound
|
outbounds []adapter.Outbound
|
||||||
logFactory log.Factory
|
logFactory log.Factory
|
||||||
logger log.ContextLogger
|
logger log.ContextLogger
|
||||||
logFile *os.File
|
|
||||||
preServices map[string]adapter.Service
|
preServices map[string]adapter.Service
|
||||||
postServices map[string]adapter.Service
|
postServices map[string]adapter.Service
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, options option.Options, platformInterface platform.Interface) (*Box, error) {
|
type Options struct {
|
||||||
createdAt := time.Now()
|
option.Options
|
||||||
|
Context context.Context
|
||||||
|
PlatformInterface platform.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(options Options) (*Box, error) {
|
||||||
|
ctx := options.Context
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
createdAt := time.Now()
|
||||||
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
|
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
|
||||||
applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
|
applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
|
||||||
|
|
||||||
var needClashAPI bool
|
var needClashAPI bool
|
||||||
var needV2RayAPI bool
|
var needV2RayAPI bool
|
||||||
if experimentalOptions.ClashAPI != nil && experimentalOptions.ClashAPI.ExternalController != "" {
|
if experimentalOptions.ClashAPI != nil && experimentalOptions.ClashAPI.ExternalController != "" {
|
||||||
@@ -51,60 +57,20 @@ func New(ctx context.Context, options option.Options, platformInterface platform
|
|||||||
if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" {
|
if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" {
|
||||||
needV2RayAPI = true
|
needV2RayAPI = true
|
||||||
}
|
}
|
||||||
|
var defaultLogWriter io.Writer
|
||||||
logOptions := common.PtrValueOrDefault(options.Log)
|
if options.PlatformInterface != nil {
|
||||||
|
defaultLogWriter = io.Discard
|
||||||
var logFactory log.Factory
|
}
|
||||||
var observableLogFactory log.ObservableFactory
|
logFactory, err := log.New(log.Options{
|
||||||
var logFile *os.File
|
Options: common.PtrValueOrDefault(options.Log),
|
||||||
var logWriter io.Writer
|
Observable: needClashAPI,
|
||||||
if logOptions.Disabled {
|
DefaultWriter: defaultLogWriter,
|
||||||
observableLogFactory = log.NewNOPFactory()
|
BaseTime: createdAt,
|
||||||
logFactory = observableLogFactory
|
PlatformWriter: options.PlatformInterface,
|
||||||
} else {
|
})
|
||||||
switch logOptions.Output {
|
if err != nil {
|
||||||
case "":
|
return nil, E.Cause(err, "create log factory")
|
||||||
if platformInterface != nil {
|
|
||||||
logWriter = io.Discard
|
|
||||||
} else {
|
|
||||||
logWriter = os.Stdout
|
|
||||||
}
|
|
||||||
case "stderr":
|
|
||||||
logWriter = os.Stderr
|
|
||||||
case "stdout":
|
|
||||||
logWriter = os.Stdout
|
|
||||||
default:
|
|
||||||
var err error
|
|
||||||
logFile, err = os.OpenFile(C.BasePath(logOptions.Output), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
logWriter = logFile
|
|
||||||
}
|
|
||||||
logFormatter := log.Formatter{
|
|
||||||
BaseTime: createdAt,
|
|
||||||
DisableColors: logOptions.DisableColor || logFile != nil,
|
|
||||||
DisableTimestamp: !logOptions.Timestamp && logFile != nil,
|
|
||||||
FullTimestamp: logOptions.Timestamp,
|
|
||||||
TimestampFormat: "-0700 2006-01-02 15:04:05",
|
|
||||||
}
|
|
||||||
if needClashAPI {
|
|
||||||
observableLogFactory = log.NewObservableFactory(logFormatter, logWriter, platformInterface)
|
|
||||||
logFactory = observableLogFactory
|
|
||||||
} else {
|
|
||||||
logFactory = log.NewFactory(logFormatter, logWriter, platformInterface)
|
|
||||||
}
|
|
||||||
if logOptions.Level != "" {
|
|
||||||
logLevel, err := log.ParseLevel(logOptions.Level)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "parse log level")
|
|
||||||
}
|
|
||||||
logFactory.SetLevel(logLevel)
|
|
||||||
} else {
|
|
||||||
logFactory.SetLevel(log.LevelTrace)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
router, err := route.NewRouter(
|
router, err := route.NewRouter(
|
||||||
ctx,
|
ctx,
|
||||||
logFactory,
|
logFactory,
|
||||||
@@ -112,7 +78,7 @@ func New(ctx context.Context, options option.Options, platformInterface platform
|
|||||||
common.PtrValueOrDefault(options.DNS),
|
common.PtrValueOrDefault(options.DNS),
|
||||||
common.PtrValueOrDefault(options.NTP),
|
common.PtrValueOrDefault(options.NTP),
|
||||||
options.Inbounds,
|
options.Inbounds,
|
||||||
platformInterface,
|
options.PlatformInterface,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse route options")
|
return nil, E.Cause(err, "parse route options")
|
||||||
@@ -132,7 +98,7 @@ func New(ctx context.Context, options option.Options, platformInterface platform
|
|||||||
router,
|
router,
|
||||||
logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
|
logFactory.NewLogger(F.ToString("inbound/", inboundOptions.Type, "[", tag, "]")),
|
||||||
inboundOptions,
|
inboundOptions,
|
||||||
platformInterface,
|
options.PlatformInterface,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse inbound[", i, "]")
|
return nil, E.Cause(err, "parse inbound[", i, "]")
|
||||||
@@ -151,6 +117,7 @@ func New(ctx context.Context, options option.Options, platformInterface platform
|
|||||||
ctx,
|
ctx,
|
||||||
router,
|
router,
|
||||||
logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
|
logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
|
||||||
|
tag,
|
||||||
outboundOptions)
|
outboundOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse outbound[", i, "]")
|
return nil, E.Cause(err, "parse outbound[", i, "]")
|
||||||
@@ -158,7 +125,7 @@ func New(ctx context.Context, options option.Options, platformInterface platform
|
|||||||
outbounds = append(outbounds, out)
|
outbounds = append(outbounds, out)
|
||||||
}
|
}
|
||||||
err = router.Initialize(inbounds, outbounds, func() adapter.Outbound {
|
err = router.Initialize(inbounds, outbounds, func() adapter.Outbound {
|
||||||
out, oErr := outbound.New(ctx, router, logFactory.NewLogger("outbound/direct"), option.Outbound{Type: "direct", Tag: "default"})
|
out, oErr := outbound.New(ctx, router, logFactory.NewLogger("outbound/direct"), "direct", option.Outbound{Type: "direct", Tag: "default"})
|
||||||
common.Must(oErr)
|
common.Must(oErr)
|
||||||
outbounds = append(outbounds, out)
|
outbounds = append(outbounds, out)
|
||||||
return out
|
return out
|
||||||
@@ -166,10 +133,16 @@ func New(ctx context.Context, options option.Options, platformInterface platform
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if options.PlatformInterface != nil {
|
||||||
|
err = options.PlatformInterface.Initialize(ctx, router)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "initialize platform interface")
|
||||||
|
}
|
||||||
|
}
|
||||||
preServices := make(map[string]adapter.Service)
|
preServices := make(map[string]adapter.Service)
|
||||||
postServices := make(map[string]adapter.Service)
|
postServices := make(map[string]adapter.Service)
|
||||||
if needClashAPI {
|
if needClashAPI {
|
||||||
clashServer, err := experimental.NewClashServer(router, observableLogFactory, common.PtrValueOrDefault(options.Experimental.ClashAPI))
|
clashServer, err := experimental.NewClashServer(router, logFactory.(log.ObservableFactory), common.PtrValueOrDefault(options.Experimental.ClashAPI))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "create clash api server")
|
return nil, E.Cause(err, "create clash api server")
|
||||||
}
|
}
|
||||||
@@ -191,7 +164,6 @@ func New(ctx context.Context, options option.Options, platformInterface platform
|
|||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
logFactory: logFactory,
|
logFactory: logFactory,
|
||||||
logger: logFactory.Logger(),
|
logger: logFactory.Logger(),
|
||||||
logFile: logFile,
|
|
||||||
preServices: preServices,
|
preServices: preServices,
|
||||||
postServices: postServices,
|
postServices: postServices,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
@@ -238,21 +210,23 @@ func (s *Box) Start() error {
|
|||||||
|
|
||||||
func (s *Box) preStart() error {
|
func (s *Box) preStart() error {
|
||||||
for serviceName, service := range s.preServices {
|
for serviceName, service := range s.preServices {
|
||||||
|
s.logger.Trace("pre-start ", serviceName)
|
||||||
err := adapter.PreStart(service)
|
err := adapter.PreStart(service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "pre-start ", serviceName)
|
return E.Cause(err, "pre-starting ", serviceName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, out := range s.outbounds {
|
for i, out := range s.outbounds {
|
||||||
|
var tag string
|
||||||
|
if out.Tag() == "" {
|
||||||
|
tag = F.ToString(i)
|
||||||
|
} else {
|
||||||
|
tag = out.Tag()
|
||||||
|
}
|
||||||
if starter, isStarter := out.(common.Starter); isStarter {
|
if starter, isStarter := out.(common.Starter); isStarter {
|
||||||
|
s.logger.Trace("initializing outbound/", out.Type(), "[", tag, "]")
|
||||||
err := starter.Start()
|
err := starter.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var tag string
|
|
||||||
if out.Tag() == "" {
|
|
||||||
tag = F.ToString(i)
|
|
||||||
} else {
|
|
||||||
tag = out.Tag()
|
|
||||||
}
|
|
||||||
return E.Cause(err, "initialize outbound/", out.Type(), "[", tag, "]")
|
return E.Cause(err, "initialize outbound/", out.Type(), "[", tag, "]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,24 +240,27 @@ func (s *Box) start() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for serviceName, service := range s.preServices {
|
for serviceName, service := range s.preServices {
|
||||||
|
s.logger.Trace("starting ", serviceName)
|
||||||
err = service.Start()
|
err = service.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "start ", serviceName)
|
return E.Cause(err, "start ", serviceName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, in := range s.inbounds {
|
for i, in := range s.inbounds {
|
||||||
|
var tag string
|
||||||
|
if in.Tag() == "" {
|
||||||
|
tag = F.ToString(i)
|
||||||
|
} else {
|
||||||
|
tag = in.Tag()
|
||||||
|
}
|
||||||
|
s.logger.Trace("initializing inbound/", in.Type(), "[", tag, "]")
|
||||||
err = in.Start()
|
err = in.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var tag string
|
|
||||||
if in.Tag() == "" {
|
|
||||||
tag = F.ToString(i)
|
|
||||||
} else {
|
|
||||||
tag = in.Tag()
|
|
||||||
}
|
|
||||||
return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
|
return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for serviceName, service := range s.postServices {
|
for serviceName, service := range s.postServices {
|
||||||
|
s.logger.Trace("starting ", service)
|
||||||
err = service.Start()
|
err = service.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "start ", serviceName)
|
return E.Cause(err, "start ", serviceName)
|
||||||
@@ -301,40 +278,41 @@ func (s *Box) Close() error {
|
|||||||
}
|
}
|
||||||
var errors error
|
var errors error
|
||||||
for serviceName, service := range s.postServices {
|
for serviceName, service := range s.postServices {
|
||||||
|
s.logger.Trace("closing ", serviceName)
|
||||||
errors = E.Append(errors, service.Close(), func(err error) error {
|
errors = E.Append(errors, service.Close(), func(err error) error {
|
||||||
return E.Cause(err, "close ", serviceName)
|
return E.Cause(err, "close ", serviceName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for i, in := range s.inbounds {
|
for i, in := range s.inbounds {
|
||||||
|
s.logger.Trace("closing inbound/", in.Type(), "[", i, "]")
|
||||||
errors = E.Append(errors, in.Close(), func(err error) error {
|
errors = E.Append(errors, in.Close(), func(err error) error {
|
||||||
return E.Cause(err, "close inbound/", in.Type(), "[", i, "]")
|
return E.Cause(err, "close inbound/", in.Type(), "[", i, "]")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for i, out := range s.outbounds {
|
for i, out := range s.outbounds {
|
||||||
|
s.logger.Trace("closing outbound/", out.Type(), "[", i, "]")
|
||||||
errors = E.Append(errors, common.Close(out), func(err error) error {
|
errors = E.Append(errors, common.Close(out), func(err error) error {
|
||||||
return E.Cause(err, "close inbound/", out.Type(), "[", i, "]")
|
return E.Cause(err, "close outbound/", out.Type(), "[", i, "]")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
s.logger.Trace("closing router")
|
||||||
if err := common.Close(s.router); err != nil {
|
if err := common.Close(s.router); err != nil {
|
||||||
errors = E.Append(errors, err, func(err error) error {
|
errors = E.Append(errors, err, func(err error) error {
|
||||||
return E.Cause(err, "close router")
|
return E.Cause(err, "close router")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for serviceName, service := range s.preServices {
|
for serviceName, service := range s.preServices {
|
||||||
|
s.logger.Trace("closing ", serviceName)
|
||||||
errors = E.Append(errors, service.Close(), func(err error) error {
|
errors = E.Append(errors, service.Close(), func(err error) error {
|
||||||
return E.Cause(err, "close ", serviceName)
|
return E.Cause(err, "close ", serviceName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
s.logger.Trace("closing log factory")
|
||||||
if err := common.Close(s.logFactory); err != nil {
|
if err := common.Close(s.logFactory); err != nil {
|
||||||
errors = E.Append(errors, err, func(err error) error {
|
errors = E.Append(errors, err, func(err error) error {
|
||||||
return E.Cause(err, "close log factory")
|
return E.Cause(err, "close log factory")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if s.logFile != nil {
|
|
||||||
errors = E.Append(errors, s.logFile.Close(), func(err error) error {
|
|
||||||
return E.Cause(err, "close log file")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ func check() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
instance, err := box.New(ctx, options, nil)
|
instance, err := box.New(box.Options{
|
||||||
|
Context: ctx,
|
||||||
|
Options: options,
|
||||||
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
instance.Close()
|
instance.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
|
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid/v5"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
"github.com/sagernet/sing-box/common/badjsonmerge"
|
"github.com/sagernet/sing-box/common/badjsonmerge"
|
||||||
@@ -127,7 +128,10 @@ func create() (*box.Box, context.CancelFunc, error) {
|
|||||||
options.Log.DisableColor = true
|
options.Log.DisableColor = true
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
instance, err := box.New(ctx, options, nil)
|
instance, err := box.New(box.Options{
|
||||||
|
Context: ctx,
|
||||||
|
Options: options,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
return nil, nil, E.Cause(err, "create service")
|
return nil, nil, E.Cause(err, "create service")
|
||||||
@@ -174,7 +178,10 @@ func run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cancel()
|
cancel()
|
||||||
|
closeCtx, closed := context.WithCancel(context.Background())
|
||||||
|
go closeMonitor(closeCtx)
|
||||||
instance.Close()
|
instance.Close()
|
||||||
|
closed()
|
||||||
if osSignal != syscall.SIGHUP {
|
if osSignal != syscall.SIGHUP {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -182,3 +189,13 @@ func run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func closeMonitor(ctx context.Context) {
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
log.Fatal("sing-box did not close!")
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
@@ -27,7 +25,7 @@ func createPreStartedClient() (*box.Box, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
instance, err := box.New(context.Background(), options, nil)
|
instance, err := box.New(box.Options{Options: options})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "create service")
|
return nil, E.Cause(err, "create service")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type Conn struct {
|
|||||||
element *list.Element[io.Closer]
|
element *list.Element[io.Closer]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConn(conn net.Conn) (*Conn, error) {
|
func NewConn(conn net.Conn) (net.Conn, error) {
|
||||||
connAccess.Lock()
|
connAccess.Lock()
|
||||||
element := openConnection.PushBack(conn)
|
element := openConnection.PushBack(conn)
|
||||||
connAccess.Unlock()
|
connAccess.Unlock()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ type PacketConn struct {
|
|||||||
element *list.Element[io.Closer]
|
element *list.Element[io.Closer]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketConn(conn net.PacketConn) (*PacketConn, error) {
|
func NewPacketConn(conn net.PacketConn) (net.PacketConn, error) {
|
||||||
connAccess.Lock()
|
connAccess.Lock()
|
||||||
element := openConnection.PushBack(conn)
|
element := openConnection.PushBack(conn)
|
||||||
connAccess.Unlock()
|
connAccess.Unlock()
|
||||||
|
|||||||
@@ -14,10 +14,16 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Count() int {
|
func Count() int {
|
||||||
|
if !Enabled {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
return openConnection.Len()
|
return openConnection.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
func List() []io.Closer {
|
func List() []io.Closer {
|
||||||
|
if !Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
connAccess.RLock()
|
connAccess.RLock()
|
||||||
defer connAccess.RUnlock()
|
defer connAccess.RUnlock()
|
||||||
connList := make([]io.Closer, 0, openConnection.Len())
|
connList := make([]io.Closer, 0, openConnection.Len())
|
||||||
@@ -28,6 +34,9 @@ func List() []io.Closer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Close() {
|
func Close() {
|
||||||
|
if !Enabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
connAccess.Lock()
|
connAccess.Lock()
|
||||||
defer connAccess.Unlock()
|
defer connAccess.Unlock()
|
||||||
for element := openConnection.Front(); element != nil; element = element.Next() {
|
for element := openConnection.Front(); element != nil; element = element.Next() {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||||
"github.com/sagernet/sing-box/common/warning"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
@@ -17,41 +16,6 @@ import (
|
|||||||
"github.com/sagernet/tfo-go"
|
"github.com/sagernet/tfo-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
var warnBindInterfaceOnUnsupportedPlatform = warning.New(
|
|
||||||
func() bool {
|
|
||||||
return !(C.IsLinux || C.IsWindows || C.IsDarwin)
|
|
||||||
},
|
|
||||||
"outbound option `bind_interface` is only supported on Linux and Windows",
|
|
||||||
)
|
|
||||||
|
|
||||||
var warnRoutingMarkOnUnsupportedPlatform = warning.New(
|
|
||||||
func() bool {
|
|
||||||
return !C.IsLinux
|
|
||||||
},
|
|
||||||
"outbound option `routing_mark` is only supported on Linux",
|
|
||||||
)
|
|
||||||
|
|
||||||
var warnReuseAdderOnUnsupportedPlatform = warning.New(
|
|
||||||
func() bool {
|
|
||||||
return !(C.IsDarwin || C.IsDragonfly || C.IsFreebsd || C.IsLinux || C.IsNetbsd || C.IsOpenbsd || C.IsSolaris || C.IsWindows)
|
|
||||||
},
|
|
||||||
"outbound option `reuse_addr` is unsupported on current platform",
|
|
||||||
)
|
|
||||||
|
|
||||||
var warnProtectPathOnNonAndroid = warning.New(
|
|
||||||
func() bool {
|
|
||||||
return !C.IsAndroid
|
|
||||||
},
|
|
||||||
"outbound option `protect_path` is only supported on Android",
|
|
||||||
)
|
|
||||||
|
|
||||||
var warnTFOOnUnsupportedPlatform = warning.New(
|
|
||||||
func() bool {
|
|
||||||
return !(C.IsDarwin || C.IsFreebsd || C.IsLinux || C.IsWindows)
|
|
||||||
},
|
|
||||||
"outbound option `tcp_fast_open` is unsupported on current platform",
|
|
||||||
)
|
|
||||||
|
|
||||||
type DefaultDialer struct {
|
type DefaultDialer struct {
|
||||||
dialer4 tfo.Dialer
|
dialer4 tfo.Dialer
|
||||||
dialer6 tfo.Dialer
|
dialer6 tfo.Dialer
|
||||||
@@ -66,7 +30,6 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
|||||||
var dialer net.Dialer
|
var dialer net.Dialer
|
||||||
var listener net.ListenConfig
|
var listener net.ListenConfig
|
||||||
if options.BindInterface != "" {
|
if options.BindInterface != "" {
|
||||||
warnBindInterfaceOnUnsupportedPlatform.Check()
|
|
||||||
bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
|
bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
|
||||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||||
listener.Control = control.Append(listener.Control, bindFunc)
|
listener.Control = control.Append(listener.Control, bindFunc)
|
||||||
@@ -80,7 +43,6 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
|||||||
listener.Control = control.Append(listener.Control, bindFunc)
|
listener.Control = control.Append(listener.Control, bindFunc)
|
||||||
}
|
}
|
||||||
if options.RoutingMark != 0 {
|
if options.RoutingMark != 0 {
|
||||||
warnRoutingMarkOnUnsupportedPlatform.Check()
|
|
||||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
||||||
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
|
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
|
||||||
} else if router.DefaultMark() != 0 {
|
} else if router.DefaultMark() != 0 {
|
||||||
@@ -88,11 +50,9 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
|||||||
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
|
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
|
||||||
}
|
}
|
||||||
if options.ReuseAddr {
|
if options.ReuseAddr {
|
||||||
warnReuseAdderOnUnsupportedPlatform.Check()
|
|
||||||
listener.Control = control.Append(listener.Control, control.ReuseAddr())
|
listener.Control = control.Append(listener.Control, control.ReuseAddr())
|
||||||
}
|
}
|
||||||
if options.ProtectPath != "" {
|
if options.ProtectPath != "" {
|
||||||
warnProtectPathOnNonAndroid.Check()
|
|
||||||
dialer.Control = control.Append(dialer.Control, control.ProtectPath(options.ProtectPath))
|
dialer.Control = control.Append(dialer.Control, control.ProtectPath(options.ProtectPath))
|
||||||
listener.Control = control.Append(listener.Control, control.ProtectPath(options.ProtectPath))
|
listener.Control = control.Append(listener.Control, control.ProtectPath(options.ProtectPath))
|
||||||
}
|
}
|
||||||
@@ -101,9 +61,6 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
|||||||
} else {
|
} else {
|
||||||
dialer.Timeout = C.TCPTimeout
|
dialer.Timeout = C.TCPTimeout
|
||||||
}
|
}
|
||||||
if options.TCPFastOpen {
|
|
||||||
warnTFOOnUnsupportedPlatform.Check()
|
|
||||||
}
|
|
||||||
var udpFragment bool
|
var udpFragment bool
|
||||||
if options.UDPFragment != nil {
|
if options.UDPFragment != nil {
|
||||||
udpFragment = *options.UDPFragment
|
udpFragment = *options.UDPFragment
|
||||||
@@ -154,9 +111,9 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
|
|||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
if !address.IsIPv6() {
|
if !address.IsIPv6() {
|
||||||
return d.udpDialer4.DialContext(ctx, network, address.String())
|
return trackConn(d.udpDialer4.DialContext(ctx, network, address.String()))
|
||||||
} else {
|
} else {
|
||||||
return d.udpDialer6.DialContext(ctx, network, address.String())
|
return trackConn(d.udpDialer6.DialContext(ctx, network, address.String()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !address.IsIPv6() {
|
if !address.IsIPv6() {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
|
"github.com/sagernet/sing/common/bufio"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
@@ -68,11 +69,11 @@ func (d *ResolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conn, err := N.ListenSerial(ctx, d.dialer, destination, addresses)
|
conn, destinationAddress, err := N.ListenSerial(ctx, d.dialer, destination, addresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewResolvePacketConn(ctx, d.router, d.strategy, conn), nil
|
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ResolveDialer) Upstream() any {
|
func (d *ResolveDialer) Upstream() any {
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
package dialer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-dns"
|
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
"github.com/sagernet/sing/common/buf"
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewResolvePacketConn(ctx context.Context, router adapter.Router, strategy dns.DomainStrategy, conn net.PacketConn) N.NetPacketConn {
|
|
||||||
if udpConn, ok := conn.(*net.UDPConn); ok {
|
|
||||||
return &ResolveUDPConn{udpConn, ctx, router, strategy}
|
|
||||||
} else {
|
|
||||||
return &ResolvePacketConn{conn, ctx, router, strategy}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResolveUDPConn struct {
|
|
||||||
*net.UDPConn
|
|
||||||
ctx context.Context
|
|
||||||
router adapter.Router
|
|
||||||
strategy dns.DomainStrategy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResolveUDPConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
|
|
||||||
n, addr, err := w.ReadFromUDPAddrPort(buffer.FreeBytes())
|
|
||||||
if err != nil {
|
|
||||||
return M.Socksaddr{}, err
|
|
||||||
}
|
|
||||||
buffer.Truncate(n)
|
|
||||||
return M.SocksaddrFromNetIP(addr), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResolveUDPConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
|
||||||
defer buffer.Release()
|
|
||||||
if destination.IsFqdn() {
|
|
||||||
addresses, err := w.router.Lookup(w.ctx, destination.Fqdn, w.strategy)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return common.Error(w.UDPConn.WriteToUDPAddrPort(buffer.Bytes(), M.SocksaddrFrom(addresses[0], destination.Port).AddrPort()))
|
|
||||||
}
|
|
||||||
return common.Error(w.UDPConn.WriteToUDPAddrPort(buffer.Bytes(), destination.AddrPort()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResolveUDPConn) Upstream() any {
|
|
||||||
return w.UDPConn
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResolvePacketConn struct {
|
|
||||||
net.PacketConn
|
|
||||||
ctx context.Context
|
|
||||||
router adapter.Router
|
|
||||||
strategy dns.DomainStrategy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResolvePacketConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
|
|
||||||
_, addr, err := buffer.ReadPacketFrom(w)
|
|
||||||
if err != nil {
|
|
||||||
return M.Socksaddr{}, err
|
|
||||||
}
|
|
||||||
return M.SocksaddrFromNet(addr), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResolvePacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
|
||||||
defer buffer.Release()
|
|
||||||
if destination.IsFqdn() {
|
|
||||||
addresses, err := w.router.Lookup(w.ctx, destination.Fqdn, w.strategy)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return common.Error(w.WriteTo(buffer.Bytes(), M.SocksaddrFrom(addresses[0], destination.Port).UDPAddr()))
|
|
||||||
}
|
|
||||||
return common.Error(w.WriteTo(buffer.Bytes(), destination.UDPAddr()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *ResolvePacketConn) Upstream() any {
|
|
||||||
return w.PacketConn
|
|
||||||
}
|
|
||||||
@@ -249,6 +249,10 @@ func (c *ClientConn) WriterReplaceable() bool {
|
|||||||
return c.requestWrite
|
return c.requestWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClientConn) NeedAdditionalReadDeadline() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClientConn) Upstream() any {
|
func (c *ClientConn) Upstream() any {
|
||||||
return c.Conn
|
return c.Conn
|
||||||
}
|
}
|
||||||
@@ -377,6 +381,10 @@ func (c *ClientPacketConn) RemoteAddr() net.Addr {
|
|||||||
return c.destination.UDPAddr()
|
return c.destination.UDPAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClientPacketConn) NeedAdditionalReadDeadline() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClientPacketConn) Upstream() any {
|
func (c *ClientPacketConn) Upstream() any {
|
||||||
return c.ExtendedConn
|
return c.ExtendedConn
|
||||||
}
|
}
|
||||||
@@ -413,7 +421,11 @@ func (c *ClientPacketAddrConn) ReadFrom(p []byte) (n int, addr net.Addr, err err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
addr = destination.UDPAddr()
|
if destination.IsFqdn() {
|
||||||
|
addr = destination
|
||||||
|
} else {
|
||||||
|
addr = destination.UDPAddr()
|
||||||
|
}
|
||||||
var length uint16
|
var length uint16
|
||||||
err = binary.Read(c.ExtendedConn, binary.BigEndian, &length)
|
err = binary.Read(c.ExtendedConn, binary.BigEndian, &length)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -514,6 +526,10 @@ func (c *ClientPacketAddrConn) FrontHeadroom() int {
|
|||||||
return 2 + M.MaxSocksaddrLength
|
return 2 + M.MaxSocksaddrLength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ClientPacketAddrConn) NeedAdditionalReadDeadline() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ClientPacketAddrConn) Upstream() any {
|
func (c *ClientPacketAddrConn) Upstream() any {
|
||||||
return c.ExtendedConn
|
return c.ExtendedConn
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ func (c *ServerConn) FrontHeadroom() int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ServerConn) NeedAdditionalReadDeadline() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ServerConn) Upstream() any {
|
func (c *ServerConn) Upstream() any {
|
||||||
return c.ExtendedConn
|
return c.ExtendedConn
|
||||||
}
|
}
|
||||||
@@ -183,6 +187,10 @@ func (c *ServerPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksad
|
|||||||
return c.ExtendedConn.WriteBuffer(buffer)
|
return c.ExtendedConn.WriteBuffer(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ServerPacketConn) NeedAdditionalReadDeadline() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ServerPacketConn) Upstream() any {
|
func (c *ServerPacketConn) Upstream() any {
|
||||||
return c.ExtendedConn
|
return c.ExtendedConn
|
||||||
}
|
}
|
||||||
@@ -245,6 +253,10 @@ func (c *ServerPacketAddrConn) WritePacket(buffer *buf.Buffer, destination M.Soc
|
|||||||
return c.ExtendedConn.WriteBuffer(buffer)
|
return c.ExtendedConn.WriteBuffer(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ServerPacketAddrConn) NeedAdditionalReadDeadline() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ServerPacketAddrConn) Upstream() any {
|
func (c *ServerPacketAddrConn) Upstream() any {
|
||||||
return c.ExtendedConn
|
return c.ExtendedConn
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package process
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"os/user"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Searcher interface {
|
type Searcher interface {
|
||||||
@@ -28,5 +30,15 @@ type Info struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FindProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
func FindProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
||||||
return findProcessInfo(searcher, ctx, network, source, destination)
|
info, err := searcher.FindProcessInfo(ctx, network, source, destination)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if info.UserId != -1 {
|
||||||
|
osUser, _ := user.LookupId(F.ToString(info.UserId))
|
||||||
|
if osUser != nil {
|
||||||
|
info.User = osUser.Username
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
//go:build linux && !android
|
|
||||||
|
|
||||||
package process
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/netip"
|
|
||||||
"os/user"
|
|
||||||
|
|
||||||
F "github.com/sagernet/sing/common/format"
|
|
||||||
)
|
|
||||||
|
|
||||||
func findProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
|
||||||
info, err := searcher.FindProcessInfo(ctx, network, source, destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if info.UserId != -1 {
|
|
||||||
osUser, _ := user.LookupId(F.ToString(info.UserId))
|
|
||||||
if osUser != nil {
|
|
||||||
info.User = osUser.Username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return info, nil
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
//go:build !linux || android
|
|
||||||
|
|
||||||
package process
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/netip"
|
|
||||||
)
|
|
||||||
|
|
||||||
func findProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
|
||||||
return searcher.FindProcessInfo(ctx, network, source, destination)
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/sagernet/sing/protocol/http"
|
"github.com/sagernet/sing/protocol/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,5 +16,5 @@ func HTTPHost(ctx context.Context, reader io.Reader) (*adapter.InboundContext, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &adapter.InboundContext{Protocol: C.ProtocolHTTP, Domain: request.Host}, nil
|
return &adapter.InboundContext{Protocol: C.ProtocolHTTP, Domain: M.ParseSocksaddr(request.Host).AddrString()}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
27
common/sniff/http_test.go
Normal file
27
common/sniff/http_test.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package sniff_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/common/sniff"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSniffHTTP1(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
pkt := "GET / HTTP/1.1\r\nHost: www.google.com\r\nAccept: */*\r\n\r\n"
|
||||||
|
metadata, err := sniff.HTTPHost(context.Background(), strings.NewReader(pkt))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, metadata.Domain, "www.google.com")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSniffHTTP1WithPort(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
pkt := "GET / HTTP/1.1\r\nHost: www.gov.cn:8080\r\nAccept: */*\r\n\r\n"
|
||||||
|
metadata, err := sniff.HTTPHost(context.Background(), strings.NewReader(pkt))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, metadata.Domain, "www.gov.cn")
|
||||||
|
}
|
||||||
@@ -24,12 +24,12 @@ func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout
|
|||||||
}
|
}
|
||||||
err := conn.SetReadDeadline(time.Now().Add(timeout))
|
err := conn.SetReadDeadline(time.Now().Add(timeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, E.Cause(err, "set read deadline")
|
||||||
}
|
}
|
||||||
_, err = buffer.ReadOnceFrom(conn)
|
_, err = buffer.ReadOnceFrom(conn)
|
||||||
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, E.Cause(err, "read payload")
|
||||||
}
|
}
|
||||||
var metadata *adapter.InboundContext
|
var metadata *adapter.InboundContext
|
||||||
var errors []error
|
var errors []error
|
||||||
|
|||||||
@@ -124,8 +124,9 @@ func (e *RealityClientConfig) ClientHandshake(ctx context.Context, conn net.Conn
|
|||||||
binary.BigEndian.PutUint64(hello.SessionId, uint64(nowTime.Unix()))
|
binary.BigEndian.PutUint64(hello.SessionId, uint64(nowTime.Unix()))
|
||||||
|
|
||||||
hello.SessionId[0] = 1
|
hello.SessionId[0] = 1
|
||||||
hello.SessionId[1] = 7
|
hello.SessionId[1] = 8
|
||||||
hello.SessionId[2] = 5
|
hello.SessionId[2] = 0
|
||||||
|
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
|
||||||
copy(hello.SessionId[8:], e.shortID[:])
|
copy(hello.SessionId[8:], e.shortID[:])
|
||||||
|
|
||||||
if debug.Enabled {
|
if debug.Enabled {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ func NewSTDServer(ctx context.Context, router adapter.Router, logger log.Logger,
|
|||||||
tlsConfig.ServerName = options.ServerName
|
tlsConfig.ServerName = options.ServerName
|
||||||
}
|
}
|
||||||
if len(options.ALPN) > 0 {
|
if len(options.ALPN) > 0 {
|
||||||
tlsConfig.NextProtos = append(tlsConfig.NextProtos, options.ALPN...)
|
tlsConfig.NextProtos = append(options.ALPN, tlsConfig.NextProtos...)
|
||||||
}
|
}
|
||||||
if options.MinVersion != "" {
|
if options.MinVersion != "" {
|
||||||
minVersion, err := ParseTLSVersion(options.MinVersion)
|
minVersion, err := ParseTLSVersion(options.MinVersion)
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
package warning
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Warning struct {
|
|
||||||
logger log.Logger
|
|
||||||
check CheckFunc
|
|
||||||
message string
|
|
||||||
checkOnce sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
type CheckFunc = func() bool
|
|
||||||
|
|
||||||
func New(checkFunc CheckFunc, message string) Warning {
|
|
||||||
return Warning{
|
|
||||||
check: checkFunc,
|
|
||||||
message: message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Warning) Check() {
|
|
||||||
w.checkOnce.Do(func() {
|
|
||||||
if w.check() {
|
|
||||||
log.Warn(w.message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,26 @@
|
|||||||
|
#### 1.2.6
|
||||||
|
|
||||||
|
* Fix bugs and update dependencies
|
||||||
|
|
||||||
|
#### 1.2.3
|
||||||
|
|
||||||
|
* Introducing our [new Android client application](/installation/clients/sfa)
|
||||||
|
* Improve UDP domain destination NAT
|
||||||
|
* Update reality protocol
|
||||||
|
* Fix TTL calculation for DNS response
|
||||||
|
* Fix v2ray HTTP transport compatibility
|
||||||
|
* Fix bugs and update dependencies
|
||||||
|
|
||||||
|
#### 1.2.2
|
||||||
|
|
||||||
|
* Accept `any` outbound in dns rule **1**
|
||||||
|
* Fix bugs and update dependencies
|
||||||
|
|
||||||
|
*1*:
|
||||||
|
|
||||||
|
Now you can use the `any` outbound rule to match server address queries instead of filling in all server domains
|
||||||
|
to `domain` rule.
|
||||||
|
|
||||||
#### 1.2.1
|
#### 1.2.1
|
||||||
|
|
||||||
* Fix missing default host in v2ray http transport`s request
|
* Fix missing default host in v2ray http transport`s request
|
||||||
|
|||||||
@@ -232,6 +232,8 @@ Invert match result.
|
|||||||
|
|
||||||
Match outbound.
|
Match outbound.
|
||||||
|
|
||||||
|
`any` can be used as a value to match any outbound.
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
==Required==
|
==Required==
|
||||||
@@ -254,18 +256,4 @@ Disable cache and save cache in this query.
|
|||||||
|
|
||||||
#### rules
|
#### rules
|
||||||
|
|
||||||
Included default rules.
|
Included default rules.
|
||||||
|
|
||||||
#### invert
|
|
||||||
|
|
||||||
Invert match result.
|
|
||||||
|
|
||||||
#### server
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Tag of the target dns server.
|
|
||||||
|
|
||||||
#### disable_cache
|
|
||||||
|
|
||||||
Disable cache and save cache in this query.
|
|
||||||
@@ -231,6 +231,8 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
|||||||
|
|
||||||
匹配出站。
|
匹配出站。
|
||||||
|
|
||||||
|
`any` 可作为值用于匹配任意出站。
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
==必填==
|
==必填==
|
||||||
@@ -253,18 +255,4 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
|||||||
|
|
||||||
#### rules
|
#### rules
|
||||||
|
|
||||||
包括的默认规则。
|
包括的默认规则。
|
||||||
|
|
||||||
#### invert
|
|
||||||
|
|
||||||
反选匹配结果。
|
|
||||||
|
|
||||||
#### server
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
目标 DNS 服务器的标签。
|
|
||||||
|
|
||||||
#### disable_cache
|
|
||||||
|
|
||||||
在此查询中禁用缓存。
|
|
||||||
@@ -7,9 +7,9 @@
|
|||||||
#### Install
|
#### Install
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/SagerNet/sing-box
|
git clone -b main https://github.com/SagerNet/sing-box
|
||||||
cd sing-box
|
cd sing-box
|
||||||
./release/local/install_go.sh # skip if you have go1.19 already installed
|
./release/local/install_go.sh # skip if you have golang already installed
|
||||||
./release/local/install.sh
|
./release/local/install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
#### 安装
|
#### 安装
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/SagerNet/sing-box
|
git clone -b main https://github.com/SagerNet/sing-box
|
||||||
cd sing-box
|
cd sing-box
|
||||||
./release/local/install_go.sh # 如果已安装 go1.19 则跳过
|
./release/local/install_go.sh # 如果已安装 golang 则跳过
|
||||||
./release/local/install.sh
|
./release/local/install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,10 @@
|
|||||||
"disable_cache": true
|
"disable_cache": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"domain": "mydomain.com",
|
"outbound": "any",
|
||||||
|
"server": "local"
|
||||||
|
},
|
||||||
|
{
|
||||||
"geosite": "cn",
|
"geosite": "cn",
|
||||||
"server": "local"
|
"server": "local"
|
||||||
}
|
}
|
||||||
|
|||||||
17
docs/installation/clients/sfa.md
Normal file
17
docs/installation/clients/sfa.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# SFA
|
||||||
|
|
||||||
|
Experimental Android client for sing-box.
|
||||||
|
|
||||||
|
#### Requirements
|
||||||
|
|
||||||
|
* Android 5.0+
|
||||||
|
|
||||||
|
#### Download
|
||||||
|
|
||||||
|
* [AppCenter](https://install.appcenter.ms/users/nekohasekai/apps/sfa/distribution_groups/publictest)
|
||||||
|
|
||||||
|
#### Note
|
||||||
|
|
||||||
|
* User Agent in remote profile request is `SFA/$version ($version_code; sing-box $sing_box_version)`
|
||||||
|
* The working directory is located at `/sdcard/Android/data/io.nekohasekai.sfa/files` (External files directory)
|
||||||
|
* Crash logs is located in `$working_directory/stderr.log`
|
||||||
17
docs/installation/clients/sfa.zh.md
Normal file
17
docs/installation/clients/sfa.zh.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# SFA
|
||||||
|
|
||||||
|
实验性的 Android sing-box 客户端。
|
||||||
|
|
||||||
|
#### 要求
|
||||||
|
|
||||||
|
* Android 5.0+
|
||||||
|
|
||||||
|
#### 下载
|
||||||
|
|
||||||
|
* [AppCenter](https://install.appcenter.ms/users/nekohasekai/apps/sfa/distribution_groups/publictest)
|
||||||
|
|
||||||
|
#### 注意事项
|
||||||
|
|
||||||
|
* 远程配置文件请求中的 User Agent 为 `SFA/$version ($version_code; sing-box $sing_box_version)`
|
||||||
|
* 工作目录位于 `/sdcard/Android/data/io.nekohasekai.sfa/files` (外部文件目录)
|
||||||
|
* 崩溃日志位于 `$working_directory/stderr.log`
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# SFI
|
# SFI
|
||||||
|
|
||||||
Experimental official iOS client for sing-box.
|
Experimental iOS client for sing-box.
|
||||||
|
|
||||||
#### Requirements
|
#### Requirements
|
||||||
|
|
||||||
@@ -11,9 +11,10 @@ Experimental official iOS client for sing-box.
|
|||||||
|
|
||||||
* [TestFlight](https://testflight.apple.com/join/c6ylui2j)
|
* [TestFlight](https://testflight.apple.com/join/c6ylui2j)
|
||||||
|
|
||||||
#### Limit
|
#### Note
|
||||||
|
|
||||||
* `system` tun stack not working
|
* User Agent in remote profile request is `SFA/$version ($version_code; sing-box $sing_box_version)`
|
||||||
|
* Crash logs is located in `Settings` -> `View Service Log`
|
||||||
|
|
||||||
#### Privacy policy
|
#### Privacy policy
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# SFI
|
# SFI
|
||||||
|
|
||||||
实验性的官方 iOS sing-box 客户端。
|
实验性的 iOS sing-box 客户端。
|
||||||
|
|
||||||
#### 要求
|
#### 要求
|
||||||
|
|
||||||
@@ -11,9 +11,10 @@
|
|||||||
|
|
||||||
* [TestFlight](https://testflight.apple.com/join/c6ylui2j)
|
* [TestFlight](https://testflight.apple.com/join/c6ylui2j)
|
||||||
|
|
||||||
#### 限制
|
#### 注意事项
|
||||||
|
|
||||||
* `system` tun stack 不工作
|
* 远程配置文件请求中的 User Agent 为 `SFI/$version ($version_code; sing-box $sing_box_version)`
|
||||||
|
* 崩溃日志位于 `设置` -> `查看服务日志`
|
||||||
|
|
||||||
#### 隐私政策
|
#### 隐私政策
|
||||||
|
|
||||||
@@ -4,32 +4,26 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi/compatible"
|
"github.com/sagernet/sing-box/experimental/clashapi/compatible"
|
||||||
|
"github.com/sagernet/sing/common/atomic"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
connections compatible.Map[string, tracker]
|
uploadTemp atomic.Int64
|
||||||
uploadTemp *atomic.Int64
|
downloadTemp atomic.Int64
|
||||||
downloadTemp *atomic.Int64
|
uploadBlip atomic.Int64
|
||||||
uploadBlip *atomic.Int64
|
downloadBlip atomic.Int64
|
||||||
downloadBlip *atomic.Int64
|
uploadTotal atomic.Int64
|
||||||
uploadTotal *atomic.Int64
|
downloadTotal atomic.Int64
|
||||||
downloadTotal *atomic.Int64
|
|
||||||
ticker *time.Ticker
|
connections compatible.Map[string, tracker]
|
||||||
done chan struct{}
|
ticker *time.Ticker
|
||||||
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManager() *Manager {
|
func NewManager() *Manager {
|
||||||
manager := &Manager{
|
manager := &Manager{
|
||||||
uploadTemp: atomic.NewInt64(0),
|
ticker: time.NewTicker(time.Second),
|
||||||
downloadTemp: atomic.NewInt64(0),
|
done: make(chan struct{}),
|
||||||
uploadBlip: atomic.NewInt64(0),
|
|
||||||
downloadBlip: atomic.NewInt64(0),
|
|
||||||
uploadTotal: atomic.NewInt64(0),
|
|
||||||
downloadTotal: atomic.NewInt64(0),
|
|
||||||
ticker: time.NewTicker(time.Second),
|
|
||||||
done: make(chan struct{}),
|
|
||||||
}
|
}
|
||||||
go manager.handle()
|
go manager.handle()
|
||||||
return manager
|
return manager
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package trafficontrol
|
package trafficontrol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
@@ -8,10 +9,10 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/experimental/trackerconn"
|
"github.com/sagernet/sing-box/experimental/trackerconn"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/atomic"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid/v5"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
@@ -43,6 +44,19 @@ type trackerInfo struct {
|
|||||||
RulePayload string `json:"rulePayload"`
|
RulePayload string `json:"rulePayload"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t trackerInfo) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(map[string]any{
|
||||||
|
"id": t.UUID.String(),
|
||||||
|
"metadata": t.Metadata,
|
||||||
|
"upload": t.UploadTotal.Load(),
|
||||||
|
"download": t.DownloadTotal.Load(),
|
||||||
|
"start": t.Start,
|
||||||
|
"chains": t.Chain,
|
||||||
|
"rule": t.Rule,
|
||||||
|
"rulePayload": t.RulePayload,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type tcpTracker struct {
|
type tcpTracker struct {
|
||||||
N.ExtendedConn `json:"-"`
|
N.ExtendedConn `json:"-"`
|
||||||
*trackerInfo
|
*trackerInfo
|
||||||
@@ -97,8 +111,8 @@ func NewTCPTracker(conn net.Conn, manager *Manager, metadata Metadata, router ad
|
|||||||
next = group.Now()
|
next = group.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
upload := atomic.NewInt64(0)
|
upload := new(atomic.Int64)
|
||||||
download := atomic.NewInt64(0)
|
download := new(atomic.Int64)
|
||||||
|
|
||||||
t := &tcpTracker{
|
t := &tcpTracker{
|
||||||
ExtendedConn: trackerconn.NewHook(conn, func(n int64) {
|
ExtendedConn: trackerconn.NewHook(conn, func(n int64) {
|
||||||
@@ -184,8 +198,8 @@ func NewUDPTracker(conn N.PacketConn, manager *Manager, metadata Metadata, route
|
|||||||
next = group.Now()
|
next = group.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
upload := atomic.NewInt64(0)
|
upload := new(atomic.Int64)
|
||||||
download := atomic.NewInt64(0)
|
download := new(atomic.Int64)
|
||||||
|
|
||||||
ut := &udpTracker{
|
ut := &udpTracker{
|
||||||
PacketConn: trackerconn.NewHookPacket(conn, func(n int64) {
|
PacketConn: trackerconn.NewHookPacket(conn, func(n int64) {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -46,6 +44,7 @@ func clientConnect(sharedDirectory string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommandClient) Connect() error {
|
func (c *CommandClient) Connect() error {
|
||||||
|
common.Close(c.conn)
|
||||||
conn, err := clientConnect(c.sharedDirectory)
|
conn, err := clientConnect(c.sharedDirectory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -10,6 +8,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/debug"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/observable"
|
"github.com/sagernet/sing/common/observable"
|
||||||
"github.com/sagernet/sing/common/x/list"
|
"github.com/sagernet/sing/common/x/list"
|
||||||
@@ -57,7 +57,10 @@ func (s *CommandServer) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) Close() error {
|
func (s *CommandServer) Close() error {
|
||||||
return s.listener.Close()
|
return common.Close(
|
||||||
|
s.listener,
|
||||||
|
s.observer,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CommandServer) loopConnection(listener net.Listener) {
|
func (s *CommandServer) loopConnection(listener net.Listener) {
|
||||||
@@ -69,7 +72,9 @@ func (s *CommandServer) loopConnection(listener net.Listener) {
|
|||||||
go func() {
|
go func() {
|
||||||
hErr := s.handleConnection(conn)
|
hErr := s.handleConnection(conn)
|
||||||
if hErr != nil && !E.IsClosed(err) {
|
if hErr != nil && !E.IsClosed(err) {
|
||||||
log.Warn("log-server: process connection: ", hErr)
|
if debug.Enabled {
|
||||||
|
log.Warn("log-server: process connection: ", hErr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -44,7 +42,7 @@ func (s *CommandServer) handleStatusConn(conn net.Conn) error {
|
|||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil
|
return ctx.Err()
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
//go:build linux || darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
@@ -15,3 +18,36 @@ func parseConfig(configContent string) (option.Options, error) {
|
|||||||
}
|
}
|
||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckConfig(configContent string) error {
|
||||||
|
options, err := parseConfig(configContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
instance, err := box.New(box.Options{
|
||||||
|
Context: ctx,
|
||||||
|
Options: options,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
instance.Close()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatConfig(configContent string) (string, error) {
|
||||||
|
options, err := parseConfig(configContent)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
json.NewEncoder(&buffer)
|
||||||
|
encoder := json.NewEncoder(&buffer)
|
||||||
|
encoder.SetIndent("", " ")
|
||||||
|
err = encoder.Encode(options)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return buffer.String(), nil
|
||||||
|
}
|
||||||
|
|||||||
241
experimental/libbox/http.go
Normal file
241
experimental/libbox/http.go
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
"github.com/sagernet/sing/protocol/socks"
|
||||||
|
"github.com/sagernet/sing/protocol/socks/socks5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HTTPClient interface {
|
||||||
|
RestrictedTLS()
|
||||||
|
ModernTLS()
|
||||||
|
PinnedTLS12()
|
||||||
|
PinnedSHA256(sumHex string)
|
||||||
|
TrySocks5(port int32)
|
||||||
|
KeepAlive()
|
||||||
|
NewRequest() HTTPRequest
|
||||||
|
Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPRequest interface {
|
||||||
|
SetURL(link string) error
|
||||||
|
SetMethod(method string)
|
||||||
|
SetHeader(key string, value string)
|
||||||
|
SetContent(content []byte)
|
||||||
|
SetContentString(content string)
|
||||||
|
RandomUserAgent()
|
||||||
|
SetUserAgent(userAgent string)
|
||||||
|
Execute() (HTTPResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPResponse interface {
|
||||||
|
GetContent() ([]byte, error)
|
||||||
|
GetContentString() (string, error)
|
||||||
|
WriteTo(path string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ HTTPClient = (*httpClient)(nil)
|
||||||
|
_ HTTPRequest = (*httpRequest)(nil)
|
||||||
|
_ HTTPResponse = (*httpResponse)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type httpClient struct {
|
||||||
|
tls tls.Config
|
||||||
|
client http.Client
|
||||||
|
transport http.Transport
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHTTPClient() HTTPClient {
|
||||||
|
client := new(httpClient)
|
||||||
|
client.client.Timeout = C.TCPTimeout
|
||||||
|
client.client.Transport = &client.transport
|
||||||
|
client.transport.TLSClientConfig = &client.tls
|
||||||
|
client.transport.DisableKeepAlives = true
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) ModernTLS() {
|
||||||
|
c.tls.MinVersion = tls.VersionTLS12
|
||||||
|
c.tls.CipherSuites = common.Map(tls.CipherSuites(), func(it *tls.CipherSuite) uint16 { return it.ID })
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) RestrictedTLS() {
|
||||||
|
c.tls.MinVersion = tls.VersionTLS13
|
||||||
|
c.tls.CipherSuites = common.Map(common.Filter(tls.CipherSuites(), func(it *tls.CipherSuite) bool {
|
||||||
|
return common.Contains(it.SupportedVersions, uint16(tls.VersionTLS13))
|
||||||
|
}), func(it *tls.CipherSuite) uint16 {
|
||||||
|
return it.ID
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) PinnedTLS12() {
|
||||||
|
c.tls.MinVersion = tls.VersionTLS12
|
||||||
|
c.tls.MaxVersion = tls.VersionTLS12
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) PinnedSHA256(sumHex string) {
|
||||||
|
c.tls.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
|
for _, rawCert := range rawCerts {
|
||||||
|
certSum := sha256.Sum256(rawCert)
|
||||||
|
if sumHex == hex.EncodeToString(certSum[:]) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return E.New("pinned sha256 sum mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) TrySocks5(port int32) {
|
||||||
|
dialer := new(net.Dialer)
|
||||||
|
c.transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
for {
|
||||||
|
socksConn, err := dialer.DialContext(ctx, "tcp", "127.0.0.1:"+strconv.Itoa(int(port)))
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err = socks.ClientHandshake5(socksConn, socks5.CommandConnect, M.ParseSocksaddr(addr), "", "")
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//nolint:staticcheck
|
||||||
|
return socksConn, err
|
||||||
|
}
|
||||||
|
return dialer.DialContext(ctx, network, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) KeepAlive() {
|
||||||
|
c.transport.ForceAttemptHTTP2 = true
|
||||||
|
c.transport.DisableKeepAlives = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) NewRequest() HTTPRequest {
|
||||||
|
req := &httpRequest{httpClient: c}
|
||||||
|
req.request = http.Request{
|
||||||
|
Method: "GET",
|
||||||
|
Header: http.Header{},
|
||||||
|
}
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *httpClient) Close() {
|
||||||
|
c.transport.CloseIdleConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpRequest struct {
|
||||||
|
*httpClient
|
||||||
|
request http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) SetURL(link string) (err error) {
|
||||||
|
r.request.URL, err = url.Parse(link)
|
||||||
|
if r.request.URL.User != nil {
|
||||||
|
user := r.request.URL.User.Username()
|
||||||
|
password, _ := r.request.URL.User.Password()
|
||||||
|
r.request.SetBasicAuth(user, password)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) SetMethod(method string) {
|
||||||
|
r.request.Method = method
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) SetHeader(key string, value string) {
|
||||||
|
r.request.Header.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) RandomUserAgent() {
|
||||||
|
r.request.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%54, rand.Int()%2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) SetUserAgent(userAgent string) {
|
||||||
|
r.request.Header.Set("User-Agent", userAgent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) SetContent(content []byte) {
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
buffer.Write(content)
|
||||||
|
r.request.Body = io.NopCloser(bytes.NewReader(buffer.Bytes()))
|
||||||
|
r.request.ContentLength = int64(len(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) SetContentString(content string) {
|
||||||
|
r.SetContent([]byte(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *httpRequest) Execute() (HTTPResponse, error) {
|
||||||
|
response, err := r.client.Do(&r.request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
httpResp := &httpResponse{Response: response}
|
||||||
|
if response.StatusCode != http.StatusOK {
|
||||||
|
return nil, errors.New(httpResp.errorString())
|
||||||
|
}
|
||||||
|
return httpResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpResponse struct {
|
||||||
|
*http.Response
|
||||||
|
|
||||||
|
getContentOnce sync.Once
|
||||||
|
content []byte
|
||||||
|
contentError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpResponse) errorString() string {
|
||||||
|
content, err := h.GetContentString()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprint("HTTP ", h.Status)
|
||||||
|
}
|
||||||
|
return fmt.Sprint("HTTP ", h.Status, ": ", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpResponse) GetContent() ([]byte, error) {
|
||||||
|
h.getContentOnce.Do(func() {
|
||||||
|
defer h.Body.Close()
|
||||||
|
h.content, h.contentError = io.ReadAll(h.Body)
|
||||||
|
})
|
||||||
|
return h.content, h.contentError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpResponse) GetContentString() (string, error) {
|
||||||
|
content, err := h.GetContent()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(content), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpResponse) WriteTo(path string) error {
|
||||||
|
defer h.Body.Close()
|
||||||
|
file, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return common.Error(bufio.Copy(file, h.Body))
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build linux || darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import "github.com/sagernet/sing/common"
|
import "github.com/sagernet/sing/common"
|
||||||
@@ -31,3 +29,19 @@ func (i *iterator[T]) Next() T {
|
|||||||
func (i *iterator[T]) HasNext() bool {
|
func (i *iterator[T]) HasNext() bool {
|
||||||
return len(i.values) > 0
|
return len(i.values) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type abstractIterator[T any] interface {
|
||||||
|
Next() T
|
||||||
|
HasNext() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func iteratorToArray[T any](iterator abstractIterator[T]) []T {
|
||||||
|
if iterator == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var values []T
|
||||||
|
for iterator.HasNext() {
|
||||||
|
values = append(values, iterator.Next())
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|||||||
29
experimental/libbox/log.go
Normal file
29
experimental/libbox/log.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
//go:build darwin || linux
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var stderrFile *os.File
|
||||||
|
|
||||||
|
func RedirectStderr(path string) error {
|
||||||
|
if stats, err := os.Stat(path); err == nil && stats.Size() > 0 {
|
||||||
|
_ = os.Rename(path, path+".old")
|
||||||
|
}
|
||||||
|
outputFile, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = unix.Dup2(int(outputFile.Fd()), int(os.Stderr.Fd()))
|
||||||
|
if err != nil {
|
||||||
|
outputFile.Close()
|
||||||
|
os.Remove(outputFile.Name())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stderrFile = outputFile
|
||||||
|
return nil
|
||||||
|
}
|
||||||
183
experimental/libbox/monitor.go
Normal file
183
experimental/libbox/monitor.go
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-tun"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
"github.com/sagernet/sing/common/x/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ tun.DefaultInterfaceMonitor = (*platformDefaultInterfaceMonitor)(nil)
|
||||||
|
_ InterfaceUpdateListener = (*platformDefaultInterfaceMonitor)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type platformDefaultInterfaceMonitor struct {
|
||||||
|
*platformInterfaceWrapper
|
||||||
|
errorHandler E.Handler
|
||||||
|
networkAddresses []networkAddress
|
||||||
|
defaultInterfaceName string
|
||||||
|
defaultInterfaceIndex int
|
||||||
|
element *list.Element[tun.NetworkUpdateCallback]
|
||||||
|
access sync.Mutex
|
||||||
|
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
|
||||||
|
}
|
||||||
|
|
||||||
|
type networkAddress struct {
|
||||||
|
interfaceName string
|
||||||
|
interfaceIndex int
|
||||||
|
addresses []netip.Prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) Start() error {
|
||||||
|
return m.iif.StartDefaultInterfaceMonitor(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) Close() error {
|
||||||
|
return m.iif.CloseDefaultInterfaceMonitor(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) DefaultInterfaceName(destination netip.Addr) string {
|
||||||
|
for _, address := range m.networkAddresses {
|
||||||
|
for _, prefix := range address.addresses {
|
||||||
|
if prefix.Contains(destination) {
|
||||||
|
return address.interfaceName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.defaultInterfaceName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) DefaultInterfaceIndex(destination netip.Addr) int {
|
||||||
|
for _, address := range m.networkAddresses {
|
||||||
|
for _, prefix := range address.addresses {
|
||||||
|
if prefix.Contains(destination) {
|
||||||
|
return address.interfaceIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m.defaultInterfaceIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) OverrideAndroidVPN() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) AndroidVPNEnabled() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) RegisterCallback(callback tun.DefaultInterfaceUpdateCallback) *list.Element[tun.DefaultInterfaceUpdateCallback] {
|
||||||
|
m.access.Lock()
|
||||||
|
defer m.access.Unlock()
|
||||||
|
return m.callbacks.PushBack(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
|
||||||
|
m.access.Lock()
|
||||||
|
defer m.access.Unlock()
|
||||||
|
m.callbacks.Remove(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32) {
|
||||||
|
var err error
|
||||||
|
if m.iif.UsePlatformInterfaceGetter() {
|
||||||
|
err = m.updateInterfacesPlatform()
|
||||||
|
} else {
|
||||||
|
err = m.updateInterfaces()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
err = m.router.UpdateInterfaces()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
m.errorHandler.NewError(context.Background(), E.Cause(err, "update interfaces"))
|
||||||
|
}
|
||||||
|
interfaceIndex := int(interfaceIndex32)
|
||||||
|
if interfaceName == "" {
|
||||||
|
for _, netIf := range m.networkAddresses {
|
||||||
|
if netIf.interfaceIndex == interfaceIndex {
|
||||||
|
interfaceName = netIf.interfaceName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if interfaceIndex == -1 {
|
||||||
|
for _, netIf := range m.networkAddresses {
|
||||||
|
if netIf.interfaceName == interfaceName {
|
||||||
|
interfaceIndex = netIf.interfaceIndex
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if interfaceName == "" {
|
||||||
|
m.errorHandler.NewError(context.Background(), E.New("invalid interface name for ", interfaceIndex))
|
||||||
|
return
|
||||||
|
} else if interfaceIndex == -1 {
|
||||||
|
m.errorHandler.NewError(context.Background(), E.New("invalid interface index for ", interfaceName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if m.defaultInterfaceName == interfaceName && m.defaultInterfaceIndex == interfaceIndex {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.defaultInterfaceName = interfaceName
|
||||||
|
m.defaultInterfaceIndex = interfaceIndex
|
||||||
|
m.access.Lock()
|
||||||
|
callbacks := m.callbacks.Array()
|
||||||
|
m.access.Unlock()
|
||||||
|
for _, callback := range callbacks {
|
||||||
|
err = callback(tun.EventInterfaceUpdate)
|
||||||
|
if err != nil {
|
||||||
|
m.errorHandler.NewError(context.Background(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) updateInterfaces() error {
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var addresses []networkAddress
|
||||||
|
for _, iif := range interfaces {
|
||||||
|
var netAddresses []net.Addr
|
||||||
|
netAddresses, err = iif.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var address networkAddress
|
||||||
|
address.interfaceName = iif.Name
|
||||||
|
address.interfaceIndex = iif.Index
|
||||||
|
address.addresses = common.Map(common.FilterIsInstance(netAddresses, func(it net.Addr) (*net.IPNet, bool) {
|
||||||
|
value, loaded := it.(*net.IPNet)
|
||||||
|
return value, loaded
|
||||||
|
}), func(it *net.IPNet) netip.Prefix {
|
||||||
|
bits, _ := it.Mask.Size()
|
||||||
|
return netip.PrefixFrom(M.AddrFromIP(it.IP), bits)
|
||||||
|
})
|
||||||
|
addresses = append(addresses, address)
|
||||||
|
}
|
||||||
|
m.networkAddresses = addresses
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *platformDefaultInterfaceMonitor) updateInterfacesPlatform() error {
|
||||||
|
interfaces, err := m.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var addresses []networkAddress
|
||||||
|
for _, iif := range interfaces {
|
||||||
|
var address networkAddress
|
||||||
|
address.interfaceName = iif.Name
|
||||||
|
address.interfaceIndex = iif.Index
|
||||||
|
// address.addresses = common.Map(iif.Addresses, netip.MustParsePrefix)
|
||||||
|
addresses = append(addresses, address)
|
||||||
|
}
|
||||||
|
m.networkAddresses = addresses
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
//go:build linux || darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import "github.com/sagernet/sing-box/option"
|
import (
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
)
|
||||||
|
|
||||||
type PlatformInterface interface {
|
type PlatformInterface interface {
|
||||||
|
UsePlatformAutoDetectInterfaceControl() bool
|
||||||
AutoDetectInterfaceControl(fd int32) error
|
AutoDetectInterfaceControl(fd int32) error
|
||||||
OpenTun(options TunOptions) (int32, error)
|
OpenTun(options TunOptions) (int32, error)
|
||||||
WriteLog(message string)
|
WriteLog(message string)
|
||||||
@@ -12,6 +13,11 @@ type PlatformInterface interface {
|
|||||||
FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
|
FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
|
||||||
PackageNameByUid(uid int32) (string, error)
|
PackageNameByUid(uid int32) (string, error)
|
||||||
UIDByPackageName(packageName string) (int32, error)
|
UIDByPackageName(packageName string) (int32, error)
|
||||||
|
UsePlatformDefaultInterfaceMonitor() bool
|
||||||
|
StartDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
||||||
|
CloseDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
||||||
|
UsePlatformInterfaceGetter() bool
|
||||||
|
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TunInterface interface {
|
type TunInterface interface {
|
||||||
@@ -19,8 +25,19 @@ type TunInterface interface {
|
|||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type OnDemandRuleIterator interface {
|
type InterfaceUpdateListener interface {
|
||||||
Next() OnDemandRule
|
UpdateDefaultInterface(interfaceName string, interfaceIndex int32)
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkInterface struct {
|
||||||
|
Index int32
|
||||||
|
MTU int32
|
||||||
|
Name string
|
||||||
|
Addresses StringIterator
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkInterfaceIterator interface {
|
||||||
|
Next() *NetworkInterface
|
||||||
HasNext() bool
|
HasNext() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +50,11 @@ type OnDemandRule interface {
|
|||||||
ProbeURL() string
|
ProbeURL() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OnDemandRuleIterator interface {
|
||||||
|
Next() OnDemandRule
|
||||||
|
HasNext() bool
|
||||||
|
}
|
||||||
|
|
||||||
type onDemandRule struct {
|
type onDemandRule struct {
|
||||||
option.OnDemandRule
|
option.OnDemandRule
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,34 @@
|
|||||||
package platform
|
package platform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
|
Initialize(ctx context.Context, router adapter.Router) error
|
||||||
|
UsePlatformAutoDetectInterfaceControl() bool
|
||||||
AutoDetectInterfaceControl() control.Func
|
AutoDetectInterfaceControl() control.Func
|
||||||
OpenTun(options tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
|
OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
|
||||||
|
UsePlatformDefaultInterfaceMonitor() bool
|
||||||
|
CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor
|
||||||
|
UsePlatformInterfaceGetter() bool
|
||||||
|
Interfaces() ([]NetworkInterface, error)
|
||||||
process.Searcher
|
process.Searcher
|
||||||
io.Writer
|
io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NetworkInterface struct {
|
||||||
|
Index int
|
||||||
|
MTU int
|
||||||
|
Name string
|
||||||
|
Addresses []netip.Prefix
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build linux || darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build linux || darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -8,11 +6,13 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
|
"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
|
||||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
@@ -30,7 +30,11 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
instance, err := box.New(ctx, options, &platformInterfaceWrapper{platformInterface, platformInterface.UseProcFS()})
|
instance, err := box.New(box.Options{
|
||||||
|
Context: ctx,
|
||||||
|
Options: options,
|
||||||
|
PlatformInterface: &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
return nil, E.Cause(err, "create service")
|
return nil, E.Cause(err, "create service")
|
||||||
@@ -56,6 +60,16 @@ var _ platform.Interface = (*platformInterfaceWrapper)(nil)
|
|||||||
type platformInterfaceWrapper struct {
|
type platformInterfaceWrapper struct {
|
||||||
iif PlatformInterface
|
iif PlatformInterface
|
||||||
useProcFS bool
|
useProcFS bool
|
||||||
|
router adapter.Router
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
|
||||||
|
w.router = router
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) UsePlatformAutoDetectInterfaceControl() bool {
|
||||||
|
return w.iif.UsePlatformAutoDetectInterfaceControl()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
|
func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
|
||||||
@@ -66,7 +80,7 @@ func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *platformInterfaceWrapper) OpenTun(options tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
|
func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
|
||||||
if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
|
if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
|
||||||
return nil, E.New("android: unsupported uid options")
|
return nil, E.New("android: unsupported uid options")
|
||||||
}
|
}
|
||||||
@@ -77,12 +91,16 @@ func (w *platformInterfaceWrapper) OpenTun(options tun.Options, platformOptions
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dupFd, err := syscall.Dup(int(tunFd))
|
options.Name, err = getTunnelName(tunFd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "query tun name")
|
||||||
|
}
|
||||||
|
dupFd, err := dup(int(tunFd))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "dup tun file descriptor")
|
return nil, E.Cause(err, "dup tun file descriptor")
|
||||||
}
|
}
|
||||||
options.FileDescriptor = dupFd
|
options.FileDescriptor = dupFd
|
||||||
return tun.New(options)
|
return tun.New(*options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *platformInterfaceWrapper) Write(p []byte) (n int, err error) {
|
func (w *platformInterfaceWrapper) Write(p []byte) (n int, err error) {
|
||||||
@@ -116,3 +134,36 @@ func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network
|
|||||||
packageName, _ := w.iif.PackageNameByUid(uid)
|
packageName, _ := w.iif.PackageNameByUid(uid)
|
||||||
return &process.Info{UserId: uid, PackageName: packageName}, nil
|
return &process.Info{UserId: uid, PackageName: packageName}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) UsePlatformDefaultInterfaceMonitor() bool {
|
||||||
|
return w.iif.UsePlatformDefaultInterfaceMonitor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor {
|
||||||
|
return &platformDefaultInterfaceMonitor{
|
||||||
|
platformInterfaceWrapper: w,
|
||||||
|
errorHandler: errorHandler,
|
||||||
|
defaultInterfaceIndex: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
|
||||||
|
return w.iif.UsePlatformInterfaceGetter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) Interfaces() ([]platform.NetworkInterface, error) {
|
||||||
|
interfaceIterator, err := w.iif.GetInterfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var interfaces []platform.NetworkInterface
|
||||||
|
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
|
||||||
|
interfaces = append(interfaces, platform.NetworkInterface{
|
||||||
|
Index: int(netInterface.Index),
|
||||||
|
MTU: int(netInterface.MTU),
|
||||||
|
Name: netInterface.Name,
|
||||||
|
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return interfaces, nil
|
||||||
|
}
|
||||||
|
|||||||
9
experimental/libbox/service_other.go
Normal file
9
experimental/libbox/service_other.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func dup(fd int) (nfd int, err error) {
|
||||||
|
return syscall.Dup(fd)
|
||||||
|
}
|
||||||
7
experimental/libbox/service_windows.go
Normal file
7
experimental/libbox/service_windows.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package libbox
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func dup(fd int) (nfd int, err error) {
|
||||||
|
return 0, os.ErrInvalid
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build linux || darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
//go:build linux || darwin
|
|
||||||
|
|
||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -61,7 +59,7 @@ func mapRoutePrefix(prefixes []netip.Prefix) RoutePrefixIterator {
|
|||||||
var _ TunOptions = (*tunOptions)(nil)
|
var _ TunOptions = (*tunOptions)(nil)
|
||||||
|
|
||||||
type tunOptions struct {
|
type tunOptions struct {
|
||||||
tun.Options
|
*tun.Options
|
||||||
option.TunPlatformOptions
|
option.TunPlatformOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
experimental/libbox/tun_name_darwin.go
Normal file
11
experimental/libbox/tun_name_darwin.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package libbox
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
func getTunnelName(fd int32) (string, error) {
|
||||||
|
return unix.GetsockoptString(
|
||||||
|
int(fd),
|
||||||
|
2, /* #define SYSPROTO_CONTROL 2 */
|
||||||
|
2, /* #define UTUN_OPT_IFNAME 2 */
|
||||||
|
)
|
||||||
|
}
|
||||||
26
experimental/libbox/tun_name_linux.go
Normal file
26
experimental/libbox/tun_name_linux.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ifReqSize = unix.IFNAMSIZ + 64
|
||||||
|
|
||||||
|
func getTunnelName(fd int32) (string, error) {
|
||||||
|
var ifr [ifReqSize]byte
|
||||||
|
var errno syscall.Errno
|
||||||
|
_, _, errno = unix.Syscall(
|
||||||
|
unix.SYS_IOCTL,
|
||||||
|
uintptr(fd),
|
||||||
|
uintptr(unix.TUNGETIFF),
|
||||||
|
uintptr(unsafe.Pointer(&ifr[0])),
|
||||||
|
)
|
||||||
|
if errno != 0 {
|
||||||
|
return "", fmt.Errorf("failed to get name of TUN device: %w", errno)
|
||||||
|
}
|
||||||
|
return unix.ByteSliceToString(ifr[:]), nil
|
||||||
|
}
|
||||||
9
experimental/libbox/tun_name_other.go
Normal file
9
experimental/libbox/tun_name_other.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build !(darwin || linux)
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func getTunnelName(fd int32) (string, error) {
|
||||||
|
return "", os.ErrInvalid
|
||||||
|
}
|
||||||
@@ -3,11 +3,10 @@ package trackerconn
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/atomic"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(conn net.Conn, readCounter []*atomic.Int64, writeCounter []*atomic.Int64) *Conn {
|
func New(conn net.Conn, readCounter []*atomic.Int64, writeCounter []*atomic.Int64) *Conn {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package trackerconn
|
package trackerconn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/sagernet/sing/common/atomic"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewPacket(conn N.PacketConn, readCounter []*atomic.Int64, writeCounter []*atomic.Int64) *PacketConn {
|
func NewPacket(conn N.PacketConn, readCounter []*atomic.Int64, writeCounter []*atomic.Int64) *PacketConn {
|
||||||
|
|||||||
@@ -12,10 +12,9 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/experimental/trackerconn"
|
"github.com/sagernet/sing-box/experimental/trackerconn"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing/common/atomic"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -211,7 +210,7 @@ func (s *StatsService) loadOrCreateCounter(name string) *atomic.Int64 {
|
|||||||
if loaded {
|
if loaded {
|
||||||
return counter
|
return counter
|
||||||
}
|
}
|
||||||
counter = atomic.NewInt64(0)
|
counter = &atomic.Int64{}
|
||||||
s.counters[name] = counter
|
s.counters[name] = counter
|
||||||
return counter
|
return counter
|
||||||
}
|
}
|
||||||
|
|||||||
38
go.mod
38
go.mod
@@ -4,7 +4,7 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
berty.tech/go-libtor v1.0.385
|
berty.tech/go-libtor v1.0.385
|
||||||
github.com/Dreamacro/clash v1.14.0
|
github.com/Dreamacro/clash v1.15.0
|
||||||
github.com/caddyserver/certmagic v0.17.2
|
github.com/caddyserver/certmagic v0.17.2
|
||||||
github.com/cretz/bine v0.2.0
|
github.com/cretz/bine v0.2.0
|
||||||
github.com/dustin/go-humanize v1.0.1
|
github.com/dustin/go-humanize v1.0.1
|
||||||
@@ -12,40 +12,39 @@ require (
|
|||||||
github.com/go-chi/chi/v5 v5.0.8
|
github.com/go-chi/chi/v5 v5.0.8
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/go-chi/render v1.0.2
|
github.com/go-chi/render v1.0.2
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible
|
github.com/gofrs/uuid/v5 v5.0.0
|
||||||
github.com/hashicorp/yamux v0.1.1
|
github.com/hashicorp/yamux v0.1.1
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961
|
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||||
github.com/mholt/acmez v1.1.0
|
github.com/mholt/acmez v1.1.0
|
||||||
github.com/miekg/dns v1.1.52
|
github.com/miekg/dns v1.1.53
|
||||||
github.com/ooni/go-libtor v1.1.7
|
github.com/ooni/go-libtor v1.1.7
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0
|
github.com/oschwald/maxminddb-golang v1.10.0
|
||||||
github.com/pires/go-proxyproto v0.7.0
|
github.com/pires/go-proxyproto v0.7.0
|
||||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
|
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
|
||||||
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca
|
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
|
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
|
||||||
github.com/sagernet/reality v0.0.0-20230323230523-5fa25e693e7f
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||||
github.com/sagernet/sing v0.2.1
|
github.com/sagernet/sing v0.2.4
|
||||||
github.com/sagernet/sing-dns v0.1.4
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.0
|
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507
|
||||||
github.com/sagernet/sing-shadowtls v0.1.0
|
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab
|
github.com/sagernet/sing-tun v0.1.4
|
||||||
github.com/sagernet/sing-vmess v0.1.3
|
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
|
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
|
||||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
|
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
|
||||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
|
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
|
||||||
github.com/spf13/cobra v1.6.1
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.2
|
||||||
go.etcd.io/bbolt v1.3.7
|
go.etcd.io/bbolt v1.3.7
|
||||||
go.uber.org/atomic v1.10.0
|
|
||||||
go.uber.org/zap v1.24.0
|
go.uber.org/zap v1.24.0
|
||||||
go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35
|
go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35
|
||||||
golang.org/x/crypto v0.7.0
|
golang.org/x/crypto v0.8.0
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||||
golang.org/x/net v0.8.0
|
golang.org/x/net v0.9.0
|
||||||
golang.org/x/sys v0.6.0
|
golang.org/x/sys v0.7.0
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde
|
||||||
google.golang.org/grpc v1.54.0
|
google.golang.org/grpc v1.54.0
|
||||||
google.golang.org/protobuf v1.30.0
|
google.golang.org/protobuf v1.30.0
|
||||||
@@ -64,7 +63,7 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/btree v1.0.1 // indirect
|
github.com/google/btree v1.0.1 // indirect
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/josharian/native v1.1.0 // indirect
|
github.com/josharian/native v1.1.0 // indirect
|
||||||
github.com/klauspost/compress v1.15.15 // indirect
|
github.com/klauspost/compress v1.15.15 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||||
@@ -82,9 +81,10 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||||
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
golang.org/x/mod v0.8.0 // indirect
|
||||||
golang.org/x/text v0.8.0 // indirect
|
golang.org/x/text v0.9.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.6.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
|
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
|
||||||
|
|||||||
74
go.sum
74
go.sum
@@ -1,7 +1,7 @@
|
|||||||
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
|
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
|
||||||
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
||||||
github.com/Dreamacro/clash v1.14.0 h1:ehJ/C/1m9LEjmME72WSE/Y2YqbR3Q54AbjqiRCvtyW4=
|
github.com/Dreamacro/clash v1.15.0 h1:mlpD950VEggXZBNahV66hyKDRxcczkj3vymoAt78KyE=
|
||||||
github.com/Dreamacro/clash v1.14.0/go.mod h1:ia2CU7V713H1QdCqMwOLK9U9V5Ay8X0voj3yQr2tk+I=
|
github.com/Dreamacro/clash v1.15.0/go.mod h1:WNH69bN11LiAdgdSr4hpkEuXVMfBbWyhEKMCTx9BtNE=
|
||||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
@@ -33,8 +33,8 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
|
|||||||
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
@@ -49,10 +49,10 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
|
|||||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961 h1:x/YtdDlmypenG1te/FfH6LVM+3krhXk5CFV8VYNNX5M=
|
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 h1:+aAGyK41KRn8jbF2Q7PLL0Sxwg6dShGcQSeCC7nZQ8E=
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI=
|
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI=
|
||||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
@@ -70,8 +70,8 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG
|
|||||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
|
github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
|
||||||
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
|
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
|
||||||
github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c=
|
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||||
github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||||
@@ -101,28 +101,28 @@ github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt
|
|||||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I=
|
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I=
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
||||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||||
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca h1:w56+kf8BeqLqllrRJ1tdwKc3sCdWOn/DuNHpY9fAiqs=
|
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035 h1:KttYh6bBhIw8Y6/Ljn7CGwC3CKZn788rzMJmeAKjY+8=
|
||||||
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
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/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 h1:tztuJB+giOWNRKQEBVY2oI3PsheTooMdh+/yxemYQYY=
|
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 h1:tztuJB+giOWNRKQEBVY2oI3PsheTooMdh+/yxemYQYY=
|
||||||
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32/go.mod h1:QMCkxXAC3CvBgDZVIJp43NWTuwGBScCzMLVLynjERL8=
|
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32/go.mod h1:QMCkxXAC3CvBgDZVIJp43NWTuwGBScCzMLVLynjERL8=
|
||||||
github.com/sagernet/reality v0.0.0-20230323230523-5fa25e693e7f h1:plVtFF9NVw5Py4jH/KQuWxojdMFDroTsQ1PVJcU9djM=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||||
github.com/sagernet/reality v0.0.0-20230323230523-5fa25e693e7f/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||||
github.com/sagernet/sing v0.2.1 h1:r0STYeyfKBBtoAHsBtW1dQonxG+3Qidde7/1VAMhdn8=
|
github.com/sagernet/sing v0.2.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo=
|
||||||
github.com/sagernet/sing v0.2.1/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
|
github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||||
github.com/sagernet/sing-dns v0.1.4 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0=
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4=
|
||||||
github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk=
|
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.0 h1:ILDWL7pwWfkPLEbviE/MyCgfjaBmJY/JVVY+5jhSb58=
|
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 h1:bAHZCdWqJkb8LEW98+YsMVDXGRMUVjka8IC+St6ot88=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.0/go.mod h1:ysYzszRLpNzJSorvlWRMuzU6Vchsp7sd52q+JNY4axw=
|
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507/go.mod h1:UJjvQGw0lyYaDGIDvUraL16fwaAEH1WFw1Y6sUcMPog=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
|
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4=
|
||||||
github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
|
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI=
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab h1:a9oeWuPBuIZ70qMhIIH6RrYhp886xN9jJIwsuu4ZFUo=
|
github.com/sagernet/sing-tun v0.1.4 h1:Fa6kgvuM2fPbPu3R97S8L8NgaD5lJq3wQorNuTb5oqo=
|
||||||
github.com/sagernet/sing-tun v0.1.4-0.20230326080954-8848c0e4cbab/go.mod h1:4YxIDEkkCjGXDOTMPw1SXpLmCQUFAWuaQN250oo+928=
|
github.com/sagernet/sing-tun v0.1.4/go.mod h1:7BrtP7NMp9FK5oVsZWg92b7yFrD+sM2+udapFurReyw=
|
||||||
github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM=
|
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U=
|
||||||
github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE=
|
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U=
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
||||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||||
@@ -133,8 +133,8 @@ github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+V
|
|||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
|
||||||
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
||||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -168,8 +168,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
@@ -180,8 +180,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
@@ -199,15 +199,15 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ import (
|
|||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/atomic"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Inbound = (*myInboundAdapter)(nil)
|
var _ adapter.Inbound = (*myInboundAdapter)(nil)
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ func (n *Naive) Start() error {
|
|||||||
n.httpServer = &http.Server{
|
n.httpServer = &http.Server{
|
||||||
Handler: n,
|
Handler: n,
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
|
BaseContext: func(listener net.Listener) context.Context {
|
||||||
|
return n.ctx
|
||||||
|
},
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
var sErr error
|
var sErr error
|
||||||
@@ -606,6 +609,10 @@ func (c *naiveH2Conn) SetWriteDeadline(t time.Time) error {
|
|||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *naiveH2Conn) NeedAdditionalReadDeadline() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (c *naiveH2Conn) UpstreamReader() any {
|
func (c *naiveH2Conn) UpstreamReader() any {
|
||||||
return c.reader
|
return c.reader
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ func (t *Tun) Start() error {
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if t.platformInterface != nil {
|
if t.platformInterface != nil {
|
||||||
tunInterface, err = t.platformInterface.OpenTun(t.tunOptions, t.platformOptions)
|
tunInterface, err = t.platformInterface.OpenTun(&t.tunOptions, t.platformOptions)
|
||||||
} else {
|
} else {
|
||||||
tunInterface, err = tun.New(t.tunOptions)
|
tunInterface, err = tun.New(t.tunOptions)
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ func (t *Tun) Start() error {
|
|||||||
UDPTimeout: t.udpTimeout,
|
UDPTimeout: t.udpTimeout,
|
||||||
Handler: t,
|
Handler: t,
|
||||||
Logger: t.logger,
|
Logger: t.logger,
|
||||||
UnderPlatform: t.platformInterface != nil,
|
ForwarderBindInterface: t.platformInterface != nil,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
dns.RegisterTransport([]string{"dhcp"}, func(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
dns.RegisterTransport([]string{"dhcp"}, func(name string, ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
||||||
return nil, E.New(`DHCP is not included in this build, rebuild with -tags with_dhcp`)
|
return nil, E.New(`DHCP is not included in this build, rebuild with -tags with_dhcp`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
const WithQUIC = false
|
const WithQUIC = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
dns.RegisterTransport([]string{"quic", "h3"}, func(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
dns.RegisterTransport([]string{"quic", "h3"}, func(name string, ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, link string) (dns.Transport, error) {
|
||||||
return nil, C.ErrQUICNotIncluded
|
return nil, C.ErrQUICNotIncluded
|
||||||
})
|
})
|
||||||
v2ray.RegisterQUICConstructor(
|
v2ray.RegisterQUICConstructor(
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ func (f *simpleFactory) NewLogger(tag string) ContextLogger {
|
|||||||
return &simpleLogger{f, tag}
|
return &simpleLogger{f, tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *simpleFactory) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var _ ContextLogger = (*simpleLogger)(nil)
|
var _ ContextLogger = (*simpleLogger)(nil)
|
||||||
|
|
||||||
type simpleLogger struct {
|
type simpleLogger struct {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type Factory interface {
|
|||||||
SetLevel(level Level)
|
SetLevel(level Level)
|
||||||
Logger() ContextLogger
|
Logger() ContextLogger
|
||||||
NewLogger(tag string) ContextLogger
|
NewLogger(tag string) ContextLogger
|
||||||
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type ObservableFactory interface {
|
type ObservableFactory interface {
|
||||||
|
|||||||
@@ -36,15 +36,16 @@ func (f Formatter) Format(ctx context.Context, level Level, tag string, message
|
|||||||
if tag != "" {
|
if tag != "" {
|
||||||
message = tag + ": " + message
|
message = tag + ": " + message
|
||||||
}
|
}
|
||||||
var id uint32
|
var id ID
|
||||||
var hasId bool
|
var hasId bool
|
||||||
if ctx != nil {
|
if ctx != nil {
|
||||||
id, hasId = IDFromContext(ctx)
|
id, hasId = IDFromContext(ctx)
|
||||||
}
|
}
|
||||||
if hasId {
|
if hasId {
|
||||||
|
activeDuration := formatDuration(time.Since(id.CreatedAt))
|
||||||
if !f.DisableColors {
|
if !f.DisableColors {
|
||||||
var color aurora.Color
|
var color aurora.Color
|
||||||
color = aurora.Color(uint8(id))
|
color = aurora.Color(uint8(id.ID))
|
||||||
color %= 215
|
color %= 215
|
||||||
row := uint(color / 36)
|
row := uint(color / 36)
|
||||||
column := uint(color % 36)
|
column := uint(color % 36)
|
||||||
@@ -62,9 +63,9 @@ func (f Formatter) Format(ctx context.Context, level Level, tag string, message
|
|||||||
color += 16
|
color += 16
|
||||||
color = color << 16
|
color = color << 16
|
||||||
color |= 1 << 14
|
color |= 1 << 14
|
||||||
message = F.ToString("[", aurora.Colorize(id, color).String(), "] ", message)
|
message = F.ToString("[", aurora.Colorize(id.ID, color).String(), " ", activeDuration, "] ", message)
|
||||||
} else {
|
} else {
|
||||||
message = F.ToString("[", id, "] ", message)
|
message = F.ToString("[", id.ID, " ", activeDuration, "] ", message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
@@ -99,15 +100,16 @@ func (f Formatter) FormatWithSimple(ctx context.Context, level Level, tag string
|
|||||||
message = tag + ": " + message
|
message = tag + ": " + message
|
||||||
}
|
}
|
||||||
messageSimple := message
|
messageSimple := message
|
||||||
var id uint32
|
var id ID
|
||||||
var hasId bool
|
var hasId bool
|
||||||
if ctx != nil {
|
if ctx != nil {
|
||||||
id, hasId = IDFromContext(ctx)
|
id, hasId = IDFromContext(ctx)
|
||||||
}
|
}
|
||||||
if hasId {
|
if hasId {
|
||||||
|
activeDuration := formatDuration(time.Since(id.CreatedAt))
|
||||||
if !f.DisableColors {
|
if !f.DisableColors {
|
||||||
var color aurora.Color
|
var color aurora.Color
|
||||||
color = aurora.Color(uint8(id))
|
color = aurora.Color(uint8(id.ID))
|
||||||
color %= 215
|
color %= 215
|
||||||
row := uint(color / 36)
|
row := uint(color / 36)
|
||||||
column := uint(color % 36)
|
column := uint(color % 36)
|
||||||
@@ -125,11 +127,11 @@ func (f Formatter) FormatWithSimple(ctx context.Context, level Level, tag string
|
|||||||
color += 16
|
color += 16
|
||||||
color = color << 16
|
color = color << 16
|
||||||
color |= 1 << 14
|
color |= 1 << 14
|
||||||
message = F.ToString("[", aurora.Colorize(id, color).String(), "] ", message)
|
message = F.ToString("[", aurora.Colorize(id.ID, color).String(), " ", activeDuration, "] ", message)
|
||||||
} else {
|
} else {
|
||||||
message = F.ToString("[", id, "] ", message)
|
message = F.ToString("[", id.ID, " ", activeDuration, "] ", message)
|
||||||
}
|
}
|
||||||
messageSimple = F.ToString("[", id, "] ", messageSimple)
|
messageSimple = F.ToString("[", id.ID, " ", activeDuration, "] ", messageSimple)
|
||||||
|
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
@@ -153,3 +155,13 @@ func xd(value int, x int) string {
|
|||||||
}
|
}
|
||||||
return message
|
return message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatDuration(duration time.Duration) string {
|
||||||
|
if duration < time.Second {
|
||||||
|
return F.ToString(duration.Milliseconds(), "ms")
|
||||||
|
} else if duration < time.Minute {
|
||||||
|
return F.ToString(int64(duration.Seconds()), ".", int64(duration.Seconds()*100)%100, "s")
|
||||||
|
} else {
|
||||||
|
return F.ToString(int64(duration.Minutes()), "m", int64(duration.Seconds())%60, "s")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
17
log/id.go
17
log/id.go
@@ -3,6 +3,7 @@ package log
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/random"
|
"github.com/sagernet/sing/common/random"
|
||||||
)
|
)
|
||||||
@@ -13,11 +14,19 @@ func init() {
|
|||||||
|
|
||||||
type idKey struct{}
|
type idKey struct{}
|
||||||
|
|
||||||
func ContextWithNewID(ctx context.Context) context.Context {
|
type ID struct {
|
||||||
return context.WithValue(ctx, (*idKey)(nil), rand.Uint32())
|
ID uint32
|
||||||
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func IDFromContext(ctx context.Context) (uint32, bool) {
|
func ContextWithNewID(ctx context.Context) context.Context {
|
||||||
id, loaded := ctx.Value((*idKey)(nil)).(uint32)
|
return context.WithValue(ctx, (*idKey)(nil), ID{
|
||||||
|
ID: rand.Uint32(),
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func IDFromContext(ctx context.Context) (ID, bool) {
|
||||||
|
id, loaded := ctx.Value((*idKey)(nil)).(ID)
|
||||||
return id, loaded
|
return id, loaded
|
||||||
}
|
}
|
||||||
|
|||||||
110
log/log.go
Normal file
110
log/log.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
type factoryWithFile struct {
|
||||||
|
Factory
|
||||||
|
file *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *factoryWithFile) Close() error {
|
||||||
|
return common.Close(
|
||||||
|
f.Factory,
|
||||||
|
common.PtrOrNil(f.file),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type observableFactoryWithFile struct {
|
||||||
|
ObservableFactory
|
||||||
|
file *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *observableFactoryWithFile) Close() error {
|
||||||
|
return common.Close(
|
||||||
|
f.ObservableFactory,
|
||||||
|
common.PtrOrNil(f.file),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
Options option.LogOptions
|
||||||
|
Observable bool
|
||||||
|
DefaultWriter io.Writer
|
||||||
|
BaseTime time.Time
|
||||||
|
PlatformWriter io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(options Options) (Factory, error) {
|
||||||
|
logOptions := options.Options
|
||||||
|
|
||||||
|
if logOptions.Disabled {
|
||||||
|
return NewNOPFactory(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var logFile *os.File
|
||||||
|
var logWriter io.Writer
|
||||||
|
|
||||||
|
switch logOptions.Output {
|
||||||
|
case "":
|
||||||
|
logWriter = options.DefaultWriter
|
||||||
|
if logWriter == nil {
|
||||||
|
logWriter = os.Stderr
|
||||||
|
}
|
||||||
|
case "stderr":
|
||||||
|
logWriter = os.Stderr
|
||||||
|
case "stdout":
|
||||||
|
logWriter = os.Stdout
|
||||||
|
default:
|
||||||
|
var err error
|
||||||
|
logFile, err = os.OpenFile(C.BasePath(logOptions.Output), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
logWriter = logFile
|
||||||
|
}
|
||||||
|
logFormatter := Formatter{
|
||||||
|
BaseTime: options.BaseTime,
|
||||||
|
DisableColors: logOptions.DisableColor || logFile != nil,
|
||||||
|
DisableTimestamp: !logOptions.Timestamp && logFile != nil,
|
||||||
|
FullTimestamp: logOptions.Timestamp,
|
||||||
|
TimestampFormat: "-0700 2006-01-02 15:04:05",
|
||||||
|
}
|
||||||
|
var factory Factory
|
||||||
|
if options.Observable {
|
||||||
|
factory = NewObservableFactory(logFormatter, logWriter, options.PlatformWriter)
|
||||||
|
} else {
|
||||||
|
factory = NewFactory(logFormatter, logWriter, options.PlatformWriter)
|
||||||
|
}
|
||||||
|
if logOptions.Level != "" {
|
||||||
|
logLevel, err := ParseLevel(logOptions.Level)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "parse log level")
|
||||||
|
}
|
||||||
|
factory.SetLevel(logLevel)
|
||||||
|
} else {
|
||||||
|
factory.SetLevel(LevelTrace)
|
||||||
|
}
|
||||||
|
if logFile != nil {
|
||||||
|
if options.Observable {
|
||||||
|
factory = &observableFactoryWithFile{
|
||||||
|
ObservableFactory: factory.(ObservableFactory),
|
||||||
|
file: logFile,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
factory = &factoryWithFile{
|
||||||
|
Factory: factory,
|
||||||
|
file: logFile,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return factory, nil
|
||||||
|
}
|
||||||
@@ -72,6 +72,10 @@ func (f *nopFactory) FatalContext(ctx context.Context, args ...any) {
|
|||||||
func (f *nopFactory) PanicContext(ctx context.Context, args ...any) {
|
func (f *nopFactory) PanicContext(ctx context.Context, args ...any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *nopFactory) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *nopFactory) Subscribe() (subscription observable.Subscription[Entry], done <-chan struct{}, err error) {
|
func (f *nopFactory) Subscribe() (subscription observable.Subscription[Entry], done <-chan struct{}, err error) {
|
||||||
return nil, nil, os.ErrInvalid
|
return nil, nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ nav:
|
|||||||
- Installation:
|
- Installation:
|
||||||
- From source: installation/from-source.md
|
- From source: installation/from-source.md
|
||||||
- Clients:
|
- Clients:
|
||||||
- SFI:
|
- iOS: installation/clients/sfi.md
|
||||||
- installation/clients/sfi/index.md
|
- Android: installation/clients/sfa.md
|
||||||
- Configuration:
|
- Configuration:
|
||||||
- configuration/index.md
|
- configuration/index.md
|
||||||
- Log:
|
- Log:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ntp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -9,6 +10,7 @@ import (
|
|||||||
"github.com/sagernet/sing-box/common/settings"
|
"github.com/sagernet/sing-box/common/settings"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
@@ -20,7 +22,7 @@ var _ adapter.TimeService = (*Service)(nil)
|
|||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel common.ContextCancelCauseFunc
|
||||||
server M.Socksaddr
|
server M.Socksaddr
|
||||||
writeToSystem bool
|
writeToSystem bool
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
@@ -30,7 +32,7 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewService(ctx context.Context, router adapter.Router, logger logger.Logger, options option.NTPOptions) *Service {
|
func NewService(ctx context.Context, router adapter.Router, logger logger.Logger, options option.NTPOptions) *Service {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := common.ContextWithCancelCause(ctx)
|
||||||
server := options.ServerOptions.Build()
|
server := options.ServerOptions.Build()
|
||||||
if server.Port == 0 {
|
if server.Port == 0 {
|
||||||
server.Port = 123
|
server.Port = 123
|
||||||
@@ -64,7 +66,7 @@ func (s *Service) Start() error {
|
|||||||
|
|
||||||
func (s *Service) Close() error {
|
func (s *Service) Close() error {
|
||||||
s.ticker.Stop()
|
s.ticker.Stop()
|
||||||
s.cancel()
|
s.cancel(os.ErrClosed)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,19 +61,19 @@ func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type V2RayHTTPOptions struct {
|
type V2RayHTTPOptions struct {
|
||||||
Host Listable[string] `json:"host,omitempty"`
|
Host Listable[string] `json:"host,omitempty"`
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Method string `json:"method,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
Headers map[string]string `json:"headers,omitempty"`
|
Headers map[string]Listable[string] `json:"headers,omitempty"`
|
||||||
IdleTimeout Duration `json:"idle_timeout,omitempty"`
|
IdleTimeout Duration `json:"idle_timeout,omitempty"`
|
||||||
PingTimeout Duration `json:"ping_timeout,omitempty"`
|
PingTimeout Duration `json:"ping_timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type V2RayWebsocketOptions struct {
|
type V2RayWebsocketOptions struct {
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Headers map[string]string `json:"headers,omitempty"`
|
Headers map[string]Listable[string] `json:"headers,omitempty"`
|
||||||
MaxEarlyData uint32 `json:"max_early_data,omitempty"`
|
MaxEarlyData uint32 `json:"max_early_data,omitempty"`
|
||||||
EarlyDataHeaderName string `json:"early_data_header_name,omitempty"`
|
EarlyDataHeaderName string `json:"early_data_header_name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type V2RayQUICOptions struct{}
|
type V2RayQUICOptions struct{}
|
||||||
|
|||||||
@@ -10,45 +10,51 @@ import (
|
|||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.Outbound) (adapter.Outbound, error) {
|
func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Outbound) (adapter.Outbound, error) {
|
||||||
|
var metadata *adapter.InboundContext
|
||||||
|
if tag != "" {
|
||||||
|
ctx, metadata = adapter.AppendContext(ctx)
|
||||||
|
metadata.Outbound = tag
|
||||||
|
}
|
||||||
if options.Type == "" {
|
if options.Type == "" {
|
||||||
return nil, E.New("missing outbound type")
|
return nil, E.New("missing outbound type")
|
||||||
}
|
}
|
||||||
|
ctx = ContextWithTag(ctx, tag)
|
||||||
switch options.Type {
|
switch options.Type {
|
||||||
case C.TypeDirect:
|
case C.TypeDirect:
|
||||||
return NewDirect(router, logger, options.Tag, options.DirectOptions)
|
return NewDirect(router, logger, tag, options.DirectOptions)
|
||||||
case C.TypeBlock:
|
case C.TypeBlock:
|
||||||
return NewBlock(logger, options.Tag), nil
|
return NewBlock(logger, tag), nil
|
||||||
case C.TypeDNS:
|
case C.TypeDNS:
|
||||||
return NewDNS(router, options.Tag), nil
|
return NewDNS(router, tag), nil
|
||||||
case C.TypeSocks:
|
case C.TypeSocks:
|
||||||
return NewSocks(router, logger, options.Tag, options.SocksOptions)
|
return NewSocks(router, logger, tag, options.SocksOptions)
|
||||||
case C.TypeHTTP:
|
case C.TypeHTTP:
|
||||||
return NewHTTP(router, logger, options.Tag, options.HTTPOptions)
|
return NewHTTP(router, logger, tag, options.HTTPOptions)
|
||||||
case C.TypeShadowsocks:
|
case C.TypeShadowsocks:
|
||||||
return NewShadowsocks(ctx, router, logger, options.Tag, options.ShadowsocksOptions)
|
return NewShadowsocks(ctx, router, logger, tag, options.ShadowsocksOptions)
|
||||||
case C.TypeVMess:
|
case C.TypeVMess:
|
||||||
return NewVMess(ctx, router, logger, options.Tag, options.VMessOptions)
|
return NewVMess(ctx, router, logger, tag, options.VMessOptions)
|
||||||
case C.TypeTrojan:
|
case C.TypeTrojan:
|
||||||
return NewTrojan(ctx, router, logger, options.Tag, options.TrojanOptions)
|
return NewTrojan(ctx, router, logger, tag, options.TrojanOptions)
|
||||||
case C.TypeWireGuard:
|
case C.TypeWireGuard:
|
||||||
return NewWireGuard(ctx, router, logger, options.Tag, options.WireGuardOptions)
|
return NewWireGuard(ctx, router, logger, tag, options.WireGuardOptions)
|
||||||
case C.TypeHysteria:
|
case C.TypeHysteria:
|
||||||
return NewHysteria(ctx, router, logger, options.Tag, options.HysteriaOptions)
|
return NewHysteria(ctx, router, logger, tag, options.HysteriaOptions)
|
||||||
case C.TypeTor:
|
case C.TypeTor:
|
||||||
return NewTor(ctx, router, logger, options.Tag, options.TorOptions)
|
return NewTor(ctx, router, logger, tag, options.TorOptions)
|
||||||
case C.TypeSSH:
|
case C.TypeSSH:
|
||||||
return NewSSH(ctx, router, logger, options.Tag, options.SSHOptions)
|
return NewSSH(ctx, router, logger, tag, options.SSHOptions)
|
||||||
case C.TypeShadowTLS:
|
case C.TypeShadowTLS:
|
||||||
return NewShadowTLS(ctx, router, logger, options.Tag, options.ShadowTLSOptions)
|
return NewShadowTLS(ctx, router, logger, tag, options.ShadowTLSOptions)
|
||||||
case C.TypeShadowsocksR:
|
case C.TypeShadowsocksR:
|
||||||
return NewShadowsocksR(ctx, router, logger, options.Tag, options.ShadowsocksROptions)
|
return NewShadowsocksR(ctx, router, logger, tag, options.ShadowsocksROptions)
|
||||||
case C.TypeVLESS:
|
case C.TypeVLESS:
|
||||||
return NewVLESS(ctx, router, logger, options.Tag, options.VLESSOptions)
|
return NewVLESS(ctx, router, logger, tag, options.VLESSOptions)
|
||||||
case C.TypeSelector:
|
case C.TypeSelector:
|
||||||
return NewSelector(router, logger, options.Tag, options.SelectorOptions)
|
return NewSelector(router, logger, tag, options.SelectorOptions)
|
||||||
case C.TypeURLTest:
|
case C.TypeURLTest:
|
||||||
return NewURLTest(router, logger, options.Tag, options.URLTestOptions)
|
return NewURLTest(router, logger, tag, options.URLTestOptions)
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown outbound type: ", options.Type)
|
return nil, E.New("unknown outbound type: ", options.Type)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
@@ -56,15 +57,21 @@ func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata a
|
|||||||
func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
var outConn net.PacketConn
|
var outConn net.PacketConn
|
||||||
|
var destinationAddress netip.Addr
|
||||||
var err error
|
var err error
|
||||||
if len(metadata.DestinationAddresses) > 0 {
|
if len(metadata.DestinationAddresses) > 0 {
|
||||||
outConn, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses)
|
outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses)
|
||||||
} else {
|
} else {
|
||||||
outConn, err = this.ListenPacket(ctx, metadata.Destination)
|
outConn, err = this.ListenPacket(ctx, metadata.Destination)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return N.HandshakeFailure(conn, err)
|
return N.HandshakeFailure(conn, err)
|
||||||
}
|
}
|
||||||
|
if destinationAddress.IsValid() {
|
||||||
|
if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
|
||||||
|
natConn.UpdateDestination(destinationAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
switch metadata.Protocol {
|
switch metadata.Protocol {
|
||||||
case C.ProtocolSTUN:
|
case C.ProtocolSTUN:
|
||||||
ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout)
|
ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout)
|
||||||
|
|||||||
@@ -102,11 +102,10 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
|
|||||||
|
|
||||||
func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
fastClose, cancel := context.WithCancel(ctx)
|
fastClose, cancel := common.ContextWithCancelCause(ctx)
|
||||||
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
|
||||||
var group task.Group
|
var group task.Group
|
||||||
group.Append0(func(ctx context.Context) error {
|
group.Append0(func(ctx context.Context) error {
|
||||||
defer cancel()
|
|
||||||
_buffer := buf.StackNewSize(dns.FixedPacketSize)
|
_buffer := buf.StackNewSize(dns.FixedPacketSize)
|
||||||
defer common.KeepAlive(_buffer)
|
defer common.KeepAlive(_buffer)
|
||||||
buffer := common.Dup(_buffer)
|
buffer := common.Dup(_buffer)
|
||||||
@@ -115,11 +114,13 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
|||||||
buffer.FullReset()
|
buffer.FullReset()
|
||||||
destination, err := conn.ReadPacket(buffer)
|
destination, err := conn.ReadPacket(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cancel(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var message mDNS.Msg
|
var message mDNS.Msg
|
||||||
err = message.Unpack(buffer.Bytes())
|
err = message.Unpack(buffer.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cancel(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
timeout.Update()
|
timeout.Update()
|
||||||
@@ -127,17 +128,22 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
|
|||||||
go func() error {
|
go func() error {
|
||||||
response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
|
response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cancel(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
timeout.Update()
|
timeout.Update()
|
||||||
responseBuffer := buf.NewPacket()
|
responseBuffer := buf.NewPacket()
|
||||||
n, err := response.PackBuffer(responseBuffer.FreeBytes())
|
n, err := response.PackBuffer(responseBuffer.FreeBytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
cancel(err)
|
||||||
responseBuffer.Release()
|
responseBuffer.Release()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
responseBuffer.Truncate(len(n))
|
responseBuffer.Truncate(len(n))
|
||||||
err = conn.WritePacket(responseBuffer, destination)
|
err = conn.WritePacket(responseBuffer, destination)
|
||||||
|
if err != nil {
|
||||||
|
cancel(err)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ import (
|
|||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/protocol/http"
|
sHTTP "github.com/sagernet/sing/protocol/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*HTTP)(nil)
|
var _ adapter.Outbound = (*HTTP)(nil)
|
||||||
|
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
myOutboundAdapter
|
myOutboundAdapter
|
||||||
client *http.Client
|
client *sHTTP.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (*HTTP, error) {
|
func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (*HTTP, error) {
|
||||||
@@ -37,7 +37,12 @@ func NewHTTP(router adapter.Router, logger log.ContextLogger, tag string, option
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
},
|
},
|
||||||
http.NewClient(detour, options.ServerOptions.Build(), options.Username, options.Password),
|
sHTTP.NewClient(sHTTP.Options{
|
||||||
|
Dialer: detour,
|
||||||
|
Server: options.ServerOptions.Build(),
|
||||||
|
Username: options.Username,
|
||||||
|
Password: options.Password,
|
||||||
|
}),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
outbound/lookback.go
Normal file
14
outbound/lookback.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package outbound
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type outboundTagKey struct{}
|
||||||
|
|
||||||
|
func ContextWithTag(ctx context.Context, outboundTag string) context.Context {
|
||||||
|
return context.WithValue(ctx, outboundTagKey{}, outboundTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TagFromContext(ctx context.Context) (string, bool) {
|
||||||
|
value, loaded := ctx.Value(outboundTagKey{}).(string)
|
||||||
|
return value, loaded
|
||||||
|
}
|
||||||
@@ -136,6 +136,9 @@ var _ N.Dialer = (*shadowsocksDialer)(nil)
|
|||||||
type shadowsocksDialer Shadowsocks
|
type shadowsocksDialer Shadowsocks
|
||||||
|
|
||||||
func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
|
metadata.Outbound = h.tag
|
||||||
|
metadata.Destination = destination
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
@@ -154,13 +157,16 @@ func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, des
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &bufio.BindPacketConn{PacketConn: h.method.DialPacketConn(outConn), Addr: destination}, nil
|
return bufio.NewBindPacketConn(h.method.DialPacketConn(outConn), destination), nil
|
||||||
default:
|
default:
|
||||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *shadowsocksDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *shadowsocksDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
|
metadata.Outbound = h.tag
|
||||||
|
metadata.Destination = destination
|
||||||
outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr)
|
outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -99,6 +99,9 @@ func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *ShadowsocksR) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *ShadowsocksR) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
|
metadata.Outbound = h.tag
|
||||||
|
metadata.Destination = destination
|
||||||
switch network {
|
switch network {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
@@ -124,13 +127,16 @@ func (h *ShadowsocksR) DialContext(ctx context.Context, network string, destinat
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &bufio.BindPacketConn{PacketConn: conn, Addr: destination}, nil
|
return bufio.NewBindPacketConn(conn, destination), nil
|
||||||
default:
|
default:
|
||||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ShadowsocksR) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *ShadowsocksR) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
|
metadata.Outbound = h.tag
|
||||||
|
metadata.Destination = destination
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr)
|
outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -86,23 +86,26 @@ func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.Context
|
|||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShadowTLS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *ShadowTLS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
|
metadata.Outbound = h.tag
|
||||||
|
metadata.Destination = destination
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
return s.client.DialContext(ctx)
|
return h.client.DialContext(ctx)
|
||||||
default:
|
default:
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShadowTLS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *ShadowTLS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShadowTLS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (h *ShadowTLS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
return NewConnection(ctx, s, conn, metadata)
|
return NewConnection(ctx, h, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ShadowTLS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (h *ShadowTLS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ func (h *trojanDialer) DialContext(ctx context.Context, network string, destinat
|
|||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
return trojan.NewClientConn(conn, h.key, destination), nil
|
return trojan.NewClientConn(conn, h.key, destination), nil
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
return &bufio.BindPacketConn{PacketConn: trojan.NewClientPacketConn(conn, h.key), Addr: destination}, nil
|
return bufio.NewBindPacketConn(trojan.NewClientPacketConn(conn, h.key), destination), nil
|
||||||
default:
|
default:
|
||||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-box/transport/v2ray"
|
"github.com/sagernet/sing-box/transport/v2ray"
|
||||||
"github.com/sagernet/sing-box/transport/vless"
|
"github.com/sagernet/sing-box/transport/vless"
|
||||||
"github.com/sagernet/sing-dns"
|
|
||||||
"github.com/sagernet/sing-vmess/packetaddr"
|
"github.com/sagernet/sing-vmess/packetaddr"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
@@ -105,11 +104,14 @@ func (h *VLESS) DialContext(ctx context.Context, network string, destination M.S
|
|||||||
if h.xudp {
|
if h.xudp {
|
||||||
return h.client.DialEarlyXUDPPacketConn(conn, destination)
|
return h.client.DialEarlyXUDPPacketConn(conn, destination)
|
||||||
} else if h.packetAddr {
|
} else if h.packetAddr {
|
||||||
|
if destination.IsFqdn() {
|
||||||
|
return nil, E.New("packetaddr: domain destination is not supported")
|
||||||
|
}
|
||||||
packetConn, err := h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress})
|
packetConn, err := h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &bufio.BindPacketConn{PacketConn: dialer.NewResolvePacketConn(ctx, h.router, dns.DomainStrategyAsIS, packetaddr.NewConn(packetConn, destination)), Addr: destination}, nil
|
return bufio.NewBindPacketConn(packetaddr.NewConn(packetConn, destination), destination), nil
|
||||||
} else {
|
} else {
|
||||||
return h.client.DialEarlyPacketConn(conn, destination)
|
return h.client.DialEarlyPacketConn(conn, destination)
|
||||||
}
|
}
|
||||||
@@ -140,11 +142,14 @@ func (h *VLESS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
|
|||||||
if h.xudp {
|
if h.xudp {
|
||||||
return h.client.DialEarlyXUDPPacketConn(conn, destination)
|
return h.client.DialEarlyXUDPPacketConn(conn, destination)
|
||||||
} else if h.packetAddr {
|
} else if h.packetAddr {
|
||||||
|
if destination.IsFqdn() {
|
||||||
|
return nil, E.New("packetaddr: domain destination is not supported")
|
||||||
|
}
|
||||||
conn, err := h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress})
|
conn, err := h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return dialer.NewResolvePacketConn(ctx, h.router, dns.DomainStrategyAsIS, packetaddr.NewConn(conn, destination)), nil
|
return packetaddr.NewConn(conn, destination), nil
|
||||||
} else {
|
} else {
|
||||||
return h.client.DialEarlyPacketConn(conn, destination)
|
return h.client.DialEarlyPacketConn(conn, destination)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-box/transport/v2ray"
|
"github.com/sagernet/sing-box/transport/v2ray"
|
||||||
"github.com/sagernet/sing-dns"
|
|
||||||
"github.com/sagernet/sing-vmess"
|
"github.com/sagernet/sing-vmess"
|
||||||
"github.com/sagernet/sing-vmess/packetaddr"
|
"github.com/sagernet/sing-vmess/packetaddr"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
@@ -188,7 +187,10 @@ func (h *vmessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if h.packetAddr {
|
if h.packetAddr {
|
||||||
return dialer.NewResolvePacketConn(ctx, h.router, dns.DomainStrategyAsIS, packetaddr.NewConn(h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress}), destination)), nil
|
if destination.IsFqdn() {
|
||||||
|
return nil, E.New("packetaddr: domain destination is not supported")
|
||||||
|
}
|
||||||
|
return packetaddr.NewConn(h.client.DialEarlyPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress}), destination), nil
|
||||||
} else if h.xudp {
|
} else if h.xudp {
|
||||||
return h.client.DialEarlyXUDPPacketConn(conn, destination), nil
|
return h.client.DialEarlyXUDPPacketConn(conn, destination), nil
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -179,5 +179,6 @@ func (w *WireGuard) Close() error {
|
|||||||
if w.device != nil {
|
if w.device != nil {
|
||||||
w.device.Close()
|
w.device.Close()
|
||||||
}
|
}
|
||||||
return common.Close(w.tunDevice)
|
w.tunDevice.Close()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
mkdir -p /var/lib/sing-box
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
rm -rf /var/lib/sing-box
|
|
||||||
@@ -4,10 +4,9 @@ Documentation=https://sing-box.sagernet.org
|
|||||||
After=network.target nss-lookup.target
|
After=network.target nss-lookup.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
WorkingDirectory=/var/lib/sing-box
|
|
||||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
||||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
||||||
ExecStart=/usr/bin/sing-box run -c /etc/sing-box/config.json
|
ExecStart=/usr/bin/sing-box -D /var/lib/sing-box -C /etc/sing-box run
|
||||||
ExecReload=/bin/kill -HUP $MAINPID
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=10s
|
RestartSec=10s
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ Documentation=https://sing-box.sagernet.org
|
|||||||
After=network.target nss-lookup.target
|
After=network.target nss-lookup.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
WorkingDirectory=/var/lib/sing-box-%i
|
|
||||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
||||||
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
||||||
ExecStart=/usr/bin/sing-box run -c /etc/sing-box/%i.json
|
ExecStart=/usr/bin/sing-box -D /var/lib/sing-box-%i -c /etc/sing-box/%i.json run
|
||||||
ExecReload=/bin/kill -HUP $MAINPID
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=10s
|
RestartSec=10s
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ go install -v -trimpath -ldflags "-s -w -buildid=" -tags with_quic,with_wireguar
|
|||||||
popd
|
popd
|
||||||
|
|
||||||
sudo cp $(go env GOPATH)/bin/sing-box /usr/local/bin/
|
sudo cp $(go env GOPATH)/bin/sing-box /usr/local/bin/
|
||||||
sudo mkdir -p /var/lib/sing-box
|
|
||||||
sudo mkdir -p /usr/local/etc/sing-box
|
sudo mkdir -p /usr/local/etc/sing-box
|
||||||
sudo cp $PROJECT/release/config/config.json /usr/local/etc/sing-box/config.json
|
sudo cp $PROJECT/release/config/config.json /usr/local/etc/sing-box/config.json
|
||||||
sudo cp $DIR/sing-box.service /etc/systemd/system
|
sudo cp $DIR/sing-box.service /etc/systemd/system
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user