mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 16:41:30 +00:00
refactor: Modular outbounds
This commit is contained in:
parent
e537c56b6b
commit
0b2c7ec35c
|
@ -1,6 +1,10 @@
|
||||||
package adapter
|
package adapter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,3 +17,8 @@ type Outbound interface {
|
||||||
Dependencies() []string
|
Dependencies() []string
|
||||||
N.Dialer
|
N.Dialer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OutboundRegistry interface {
|
||||||
|
option.OutboundOptionsRegistry
|
||||||
|
CreateOutbound(ctx context.Context, router Router, logger log.ContextLogger, tag string, outboundType string, options any) (Outbound, error)
|
||||||
|
}
|
||||||
|
|
45
adapter/outbound/adapter.go
Normal file
45
adapter/outbound/adapter.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package outbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Adapter struct {
|
||||||
|
protocol string
|
||||||
|
network []string
|
||||||
|
tag string
|
||||||
|
dependencies []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAdapter(protocol string, network []string, tag string, dependencies []string) Adapter {
|
||||||
|
return Adapter{
|
||||||
|
protocol: protocol,
|
||||||
|
network: network,
|
||||||
|
tag: tag,
|
||||||
|
dependencies: dependencies,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAdapterWithDialerOptions(protocol string, network []string, tag string, dialOptions option.DialerOptions) Adapter {
|
||||||
|
var dependencies []string
|
||||||
|
if dialOptions.Detour != "" {
|
||||||
|
dependencies = []string{dialOptions.Detour}
|
||||||
|
}
|
||||||
|
return NewAdapter(protocol, network, tag, dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adapter) Type() string {
|
||||||
|
return a.protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adapter) Tag() string {
|
||||||
|
return a.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adapter) Network() []string {
|
||||||
|
return a.network
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adapter) Dependencies() []string {
|
||||||
|
return a.dependencies
|
||||||
|
}
|
|
@ -9,8 +9,6 @@ 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"
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
@ -21,42 +19,6 @@ import (
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
type myOutboundAdapter struct {
|
|
||||||
protocol string
|
|
||||||
network []string
|
|
||||||
router adapter.Router
|
|
||||||
logger log.ContextLogger
|
|
||||||
tag string
|
|
||||||
dependencies []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *myOutboundAdapter) Type() string {
|
|
||||||
return a.protocol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *myOutboundAdapter) Tag() string {
|
|
||||||
return a.tag
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *myOutboundAdapter) Network() []string {
|
|
||||||
return a.network
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *myOutboundAdapter) Dependencies() []string {
|
|
||||||
return a.dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *myOutboundAdapter) NewError(ctx context.Context, err error) {
|
|
||||||
NewError(a.logger, ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func withDialerDependency(options option.DialerOptions) []string {
|
|
||||||
if options.Detour != "" {
|
|
||||||
return []string{options.Detour}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error {
|
func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
ctx = adapter.WithContext(ctx, &metadata)
|
ctx = adapter.WithContext(ctx, &metadata)
|
||||||
var outConn net.Conn
|
var outConn net.Conn
|
||||||
|
@ -233,12 +195,3 @@ func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) erro
|
||||||
}
|
}
|
||||||
return bufio.CopyConn(ctx, conn, serverConn)
|
return bufio.CopyConn(ctx, conn, serverConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewError(logger log.ContextLogger, ctx context.Context, err error) {
|
|
||||||
common.Close(err)
|
|
||||||
if E.IsClosedOrCanceled(err) {
|
|
||||||
logger.DebugContext(ctx, "connection closed: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.ErrorContext(ctx, err)
|
|
||||||
}
|
|
68
adapter/outbound/registry.go
Normal file
68
adapter/outbound/registry.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package outbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConstructorFunc[T any] func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options T) (adapter.Outbound, error)
|
||||||
|
|
||||||
|
func Register[Options any](registry *Registry, outboundType string, constructor ConstructorFunc[Options]) {
|
||||||
|
registry.register(outboundType, func() any {
|
||||||
|
return new(Options)
|
||||||
|
}, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options any) (adapter.Outbound, error) {
|
||||||
|
return constructor(ctx, router, logger, tag, common.PtrValueOrDefault(options.(*Options)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ adapter.OutboundRegistry = (*Registry)(nil)
|
||||||
|
|
||||||
|
type (
|
||||||
|
optionsConstructorFunc func() any
|
||||||
|
constructorFunc func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options any) (adapter.Outbound, error)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Registry struct {
|
||||||
|
access sync.Mutex
|
||||||
|
optiosnType map[string]optionsConstructorFunc
|
||||||
|
constructors map[string]constructorFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRegistry() *Registry {
|
||||||
|
return &Registry{
|
||||||
|
optiosnType: make(map[string]optionsConstructorFunc),
|
||||||
|
constructors: make(map[string]constructorFunc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) CreateOptions(outboundType string) (any, bool) {
|
||||||
|
r.access.Lock()
|
||||||
|
defer r.access.Unlock()
|
||||||
|
optionsConstructor, loaded := r.optiosnType[outboundType]
|
||||||
|
if !loaded {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return optionsConstructor(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) CreateOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, outboundType string, options any) (adapter.Outbound, error) {
|
||||||
|
r.access.Lock()
|
||||||
|
defer r.access.Unlock()
|
||||||
|
constructor, loaded := r.constructors[outboundType]
|
||||||
|
if !loaded {
|
||||||
|
return nil, E.New("outbound type not found: " + outboundType)
|
||||||
|
}
|
||||||
|
return constructor(ctx, router, logger, tag, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) register(outboundType string, optionsConstructor optionsConstructorFunc, constructor constructorFunc) {
|
||||||
|
r.access.Lock()
|
||||||
|
defer r.access.Unlock()
|
||||||
|
r.optiosnType[outboundType] = optionsConstructor
|
||||||
|
r.constructors[outboundType] = constructor
|
||||||
|
}
|
53
box.go
53
box.go
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/inbound"
|
"github.com/sagernet/sing-box/inbound"
|
||||||
"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/outbound"
|
"github.com/sagernet/sing-box/protocol/direct"
|
||||||
"github.com/sagernet/sing-box/route"
|
"github.com/sagernet/sing-box/route"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
@ -48,12 +48,26 @@ type Options struct {
|
||||||
PlatformLogWriter log.PlatformWriter
|
PlatformLogWriter log.PlatformWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Context(ctx context.Context, registry adapter.OutboundRegistry) context.Context {
|
||||||
|
if service.FromContext[option.OutboundOptionsRegistry](ctx) != nil &&
|
||||||
|
service.FromContext[adapter.OutboundRegistry](ctx) != nil {
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
ctx = service.ContextWith[option.OutboundOptionsRegistry](ctx, registry)
|
||||||
|
ctx = service.ContextWith[adapter.OutboundRegistry](ctx, registry)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
func New(options Options) (*Box, error) {
|
func New(options Options) (*Box, error) {
|
||||||
createdAt := time.Now()
|
createdAt := time.Now()
|
||||||
ctx := options.Context
|
ctx := options.Context
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
}
|
}
|
||||||
|
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
||||||
|
if outboundRegistry == nil {
|
||||||
|
return nil, E.New("missing outbound registry in context")
|
||||||
|
}
|
||||||
ctx = service.ContextWithDefaultRegistry(ctx)
|
ctx = service.ContextWithDefaultRegistry(ctx)
|
||||||
ctx = pause.WithDefaultManager(ctx)
|
ctx = pause.WithDefaultManager(ctx)
|
||||||
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
|
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
|
||||||
|
@ -98,6 +112,16 @@ func New(options Options) (*Box, error) {
|
||||||
return nil, E.Cause(err, "parse route options")
|
return nil, E.Cause(err, "parse route options")
|
||||||
}
|
}
|
||||||
inbounds := make([]adapter.Inbound, 0, len(options.Inbounds))
|
inbounds := make([]adapter.Inbound, 0, len(options.Inbounds))
|
||||||
|
//nolint:staticcheck
|
||||||
|
if len(options.LegacyOutbounds) > 0 {
|
||||||
|
for _, legacyOutbound := range options.LegacyOutbounds {
|
||||||
|
options.Outbounds = append(options.Outbounds, option.Outbound{
|
||||||
|
Type: legacyOutbound.Type,
|
||||||
|
Tag: legacyOutbound.Tag,
|
||||||
|
Options: common.Must1(legacyOutbound.RawOptions()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
outbounds := make([]adapter.Outbound, 0, len(options.Outbounds))
|
outbounds := make([]adapter.Outbound, 0, len(options.Outbounds))
|
||||||
for i, inboundOptions := range options.Inbounds {
|
for i, inboundOptions := range options.Inbounds {
|
||||||
var in adapter.Inbound
|
var in adapter.Inbound
|
||||||
|
@ -121,29 +145,38 @@ func New(options Options) (*Box, error) {
|
||||||
inbounds = append(inbounds, in)
|
inbounds = append(inbounds, in)
|
||||||
}
|
}
|
||||||
for i, outboundOptions := range options.Outbounds {
|
for i, outboundOptions := range options.Outbounds {
|
||||||
var out adapter.Outbound
|
var currentOutbound adapter.Outbound
|
||||||
var tag string
|
var tag string
|
||||||
if outboundOptions.Tag != "" {
|
if outboundOptions.Tag != "" {
|
||||||
tag = outboundOptions.Tag
|
tag = outboundOptions.Tag
|
||||||
} else {
|
} else {
|
||||||
tag = F.ToString(i)
|
tag = F.ToString(i)
|
||||||
}
|
}
|
||||||
out, err = outbound.New(
|
outboundCtx := ctx
|
||||||
ctx,
|
if tag != "" {
|
||||||
|
// TODO: remove this
|
||||||
|
outboundCtx = adapter.WithContext(outboundCtx, &adapter.InboundContext{
|
||||||
|
Outbound: tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
currentOutbound, err = outboundRegistry.CreateOutbound(
|
||||||
|
outboundCtx,
|
||||||
router,
|
router,
|
||||||
logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
|
logFactory.NewLogger(F.ToString("outbound/", outboundOptions.Type, "[", tag, "]")),
|
||||||
tag,
|
tag,
|
||||||
outboundOptions)
|
outboundOptions.Type,
|
||||||
|
outboundOptions.Options,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse outbound[", i, "]")
|
return nil, E.Cause(err, "parse outbound[", i, "]")
|
||||||
}
|
}
|
||||||
outbounds = append(outbounds, out)
|
outbounds = append(outbounds, currentOutbound)
|
||||||
}
|
}
|
||||||
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"), "direct", option.Outbound{Type: "direct", Tag: "default"})
|
defaultOutbound, cErr := direct.NewOutbound(ctx, router, logFactory.NewLogger("outbound/direct"), "direct", option.DirectOutboundOptions{})
|
||||||
common.Must(oErr)
|
common.Must(cErr)
|
||||||
outbounds = append(outbounds, out)
|
outbounds = append(outbounds, defaultOutbound)
|
||||||
return out
|
return defaultOutbound
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -7,8 +7,9 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box"
|
||||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||||
_ "github.com/sagernet/sing-box/include"
|
"github.com/sagernet/sing-box/include"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
"github.com/sagernet/sing/service/filemanager"
|
"github.com/sagernet/sing/service/filemanager"
|
||||||
|
@ -68,4 +69,5 @@ func preRun(cmd *cobra.Command, args []string) {
|
||||||
configPaths = append(configPaths, "config.json")
|
configPaths = append(configPaths, "config.json")
|
||||||
}
|
}
|
||||||
globalCtx = service.ContextWith(globalCtx, deprecated.NewEnvManager(log.StdLogger()))
|
globalCtx = service.ContextWith(globalCtx, deprecated.NewEnvManager(log.StdLogger()))
|
||||||
|
globalCtx = box.Context(globalCtx, include.OutboundRegistry())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ func format() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, optionsEntry := range optionsList {
|
for _, optionsEntry := range optionsList {
|
||||||
optionsEntry.options, err = badjson.Omitempty(optionsEntry.options)
|
optionsEntry.options, err = badjson.Omitempty(context.TODO(), optionsEntry.options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,19 +78,14 @@ func mergePathResources(options *option.Options) error {
|
||||||
}
|
}
|
||||||
options.Inbounds[index] = inbound
|
options.Inbounds[index] = inbound
|
||||||
}
|
}
|
||||||
for index, outbound := range options.Outbounds {
|
for _, outbound := range options.Outbounds {
|
||||||
rawOptions, err := outbound.RawOptions()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch outbound.Type {
|
switch outbound.Type {
|
||||||
case C.TypeSSH:
|
case C.TypeSSH:
|
||||||
outbound.SSHOptions = mergeSSHOutboundOptions(outbound.SSHOptions)
|
mergeSSHOutboundOptions(outbound.Options.(*option.SSHOutboundOptions))
|
||||||
}
|
}
|
||||||
if tlsOptions, containsTLSOptions := rawOptions.(option.OutboundTLSOptionsWrapper); containsTLSOptions {
|
if tlsOptions, containsTLSOptions := outbound.Options.(option.OutboundTLSOptionsWrapper); containsTLSOptions {
|
||||||
tlsOptions.ReplaceOutboundTLSOptions(mergeTLSOutboundOptions(tlsOptions.TakeOutboundTLSOptions()))
|
tlsOptions.ReplaceOutboundTLSOptions(mergeTLSOutboundOptions(tlsOptions.TakeOutboundTLSOptions()))
|
||||||
}
|
}
|
||||||
options.Outbounds[index] = outbound
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -138,13 +133,12 @@ func mergeTLSOutboundOptions(options *option.OutboundTLSOptions) *option.Outboun
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeSSHOutboundOptions(options option.SSHOutboundOptions) option.SSHOutboundOptions {
|
func mergeSSHOutboundOptions(options *option.SSHOutboundOptions) {
|
||||||
if options.PrivateKeyPath != "" {
|
if options.PrivateKeyPath != "" {
|
||||||
if content, err := os.ReadFile(os.ExpandEnv(options.PrivateKeyPath)); err == nil {
|
if content, err := os.ReadFile(os.ExpandEnv(options.PrivateKeyPath)); err == nil {
|
||||||
options.PrivateKey = trimStringArray(strings.Split(string(content), "\n"))
|
options.PrivateKey = trimStringArray(strings.Split(string(content), "\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return options
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimStringArray(array []string) []string {
|
func trimStringArray(array []string) []string {
|
||||||
|
|
|
@ -57,7 +57,7 @@ func readConfigAt(path string) (*OptionsEntry, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "read config at ", path)
|
return nil, E.Cause(err, "read config at ", path)
|
||||||
}
|
}
|
||||||
options, err := json.UnmarshalExtended[option.Options](configContent)
|
options, err := json.UnmarshalExtendedContext[option.Options](globalCtx, configContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "decode config at ", path)
|
return nil, E.Cause(err, "decode config at ", path)
|
||||||
}
|
}
|
||||||
|
@ -109,13 +109,13 @@ func readConfigAndMerge() (option.Options, error) {
|
||||||
}
|
}
|
||||||
var mergedMessage json.RawMessage
|
var mergedMessage json.RawMessage
|
||||||
for _, options := range optionsList {
|
for _, options := range optionsList {
|
||||||
mergedMessage, err = badjson.MergeJSON(options.options.RawMessage, mergedMessage, false)
|
mergedMessage, err = badjson.MergeJSON(globalCtx, options.options.RawMessage, mergedMessage, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return option.Options{}, E.Cause(err, "merge config at ", options.path)
|
return option.Options{}, E.Cause(err, "merge config at ", options.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var mergedOptions option.Options
|
var mergedOptions option.Options
|
||||||
err = mergedOptions.UnmarshalJSON(mergedMessage)
|
err = mergedOptions.UnmarshalJSONContext(globalCtx, mergedMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return option.Options{}, E.Cause(err, "unmarshal merged config")
|
return option.Options{}, E.Cause(err, "unmarshal merged config")
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||||
setMultiPathTCP(&dialer4)
|
setMultiPathTCP(&dialer4)
|
||||||
}
|
}
|
||||||
if options.IsWireGuardListener {
|
if options.IsWireGuardListener {
|
||||||
for _, controlFn := range wgControlFns {
|
for _, controlFn := range WgControlFns {
|
||||||
listener.Control = control.Append(listener.Control, controlFn)
|
listener.Control = control.Append(listener.Control, controlFn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,12 @@ package dialer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/control"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WireGuardListener interface {
|
type WireGuardListener interface {
|
||||||
ListenPacketCompat(network, address string) (net.PacketConn, error)
|
ListenPacketCompat(network, address string) (net.PacketConn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var WgControlFns []control.Func
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
//go:build with_wireguard
|
|
||||||
|
|
||||||
package dialer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/sagernet/wireguard-go/conn"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ WireGuardListener = (conn.Listener)(nil)
|
|
||||||
|
|
||||||
var wgControlFns = conn.ControlFns
|
|
|
@ -1,9 +0,0 @@
|
||||||
//go:build !with_wireguard
|
|
||||||
|
|
||||||
package dialer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/sagernet/sing/common/control"
|
|
||||||
)
|
|
||||||
|
|
||||||
var wgControlFns []control.Func
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/protocol/group"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/batch"
|
"github.com/sagernet/sing/common/batch"
|
||||||
"github.com/sagernet/sing/common/json/badjson"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
@ -59,7 +59,7 @@ func getGroup(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
||||||
func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
||||||
group, ok := proxy.(adapter.OutboundGroup)
|
outboundGroup, ok := proxy.(adapter.OutboundGroup)
|
||||||
if !ok {
|
if !ok {
|
||||||
render.Status(r, http.StatusNotFound)
|
render.Status(r, http.StatusNotFound)
|
||||||
render.JSON(w, r, ErrNotFound)
|
render.JSON(w, r, ErrNotFound)
|
||||||
|
@ -82,10 +82,10 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var result map[string]uint16
|
var result map[string]uint16
|
||||||
if urlTestGroup, isURLTestGroup := group.(adapter.URLTestGroup); isURLTestGroup {
|
if urlTestGroup, isURLTestGroup := outboundGroup.(adapter.URLTestGroup); isURLTestGroup {
|
||||||
result, err = urlTestGroup.URLTest(ctx)
|
result, err = urlTestGroup.URLTest(ctx)
|
||||||
} else {
|
} else {
|
||||||
outbounds := common.FilterNotNil(common.Map(group.All(), func(it string) adapter.Outbound {
|
outbounds := common.FilterNotNil(common.Map(outboundGroup.All(), func(it string) adapter.Outbound {
|
||||||
itOutbound, _ := server.router.Outbound(it)
|
itOutbound, _ := server.router.Outbound(it)
|
||||||
return itOutbound
|
return itOutbound
|
||||||
}))
|
}))
|
||||||
|
@ -95,7 +95,7 @@ func getGroupDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
||||||
var resultAccess sync.Mutex
|
var resultAccess sync.Mutex
|
||||||
for _, detour := range outbounds {
|
for _, detour := range outbounds {
|
||||||
tag := detour.Tag()
|
tag := detour.Tag()
|
||||||
realTag := outbound.RealTag(detour)
|
realTag := group.RealTag(detour)
|
||||||
if checked[realTag] {
|
if checked[realTag] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/protocol/group"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
"github.com/sagernet/sing/common/json/badjson"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
@ -168,7 +168,7 @@ func updateProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
proxy := r.Context().Value(CtxKeyProxy).(adapter.Outbound)
|
||||||
selector, ok := proxy.(*outbound.Selector)
|
selector, ok := proxy.(*group.Selector)
|
||||||
if !ok {
|
if !ok {
|
||||||
render.Status(r, http.StatusBadRequest)
|
render.Status(r, http.StatusBadRequest)
|
||||||
render.JSON(w, r, newError("Must be a Selector"))
|
render.JSON(w, r, newError("Must be a Selector"))
|
||||||
|
@ -204,7 +204,7 @@ func getProxyDelay(server *Server) func(w http.ResponseWriter, r *http.Request)
|
||||||
|
|
||||||
delay, err := urltest.URLTest(ctx, url, proxy)
|
delay, err := urltest.URLTest(ctx, url, proxy)
|
||||||
defer func() {
|
defer func() {
|
||||||
realTag := outbound.RealTag(proxy)
|
realTag := group.RealTag(proxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.urlTestHistory.DeleteURLTestHistory(realTag)
|
server.urlTestHistory.DeleteURLTestHistory(realTag)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/protocol/group"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/varbin"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
|
@ -118,14 +118,14 @@ func writeGroups(writer io.Writer, boxService *BoxService) error {
|
||||||
}
|
}
|
||||||
var groups []OutboundGroup
|
var groups []OutboundGroup
|
||||||
for _, iGroup := range iGroups {
|
for _, iGroup := range iGroups {
|
||||||
var group OutboundGroup
|
var outboundGroup OutboundGroup
|
||||||
group.Tag = iGroup.Tag()
|
outboundGroup.Tag = iGroup.Tag()
|
||||||
group.Type = iGroup.Type()
|
outboundGroup.Type = iGroup.Type()
|
||||||
_, group.Selectable = iGroup.(*outbound.Selector)
|
_, outboundGroup.Selectable = iGroup.(*group.Selector)
|
||||||
group.Selected = iGroup.Now()
|
outboundGroup.Selected = iGroup.Now()
|
||||||
if cacheFile != nil {
|
if cacheFile != nil {
|
||||||
if isExpand, loaded := cacheFile.LoadGroupExpand(group.Tag); loaded {
|
if isExpand, loaded := cacheFile.LoadGroupExpand(outboundGroup.Tag); loaded {
|
||||||
group.IsExpand = isExpand
|
outboundGroup.IsExpand = isExpand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,12 +142,12 @@ func writeGroups(writer io.Writer, boxService *BoxService) error {
|
||||||
item.URLTestTime = history.Time.Unix()
|
item.URLTestTime = history.Time.Unix()
|
||||||
item.URLTestDelay = int32(history.Delay)
|
item.URLTestDelay = int32(history.Delay)
|
||||||
}
|
}
|
||||||
group.ItemList = append(group.ItemList, &item)
|
outboundGroup.ItemList = append(outboundGroup.ItemList, &item)
|
||||||
}
|
}
|
||||||
if len(group.ItemList) < 2 {
|
if len(outboundGroup.ItemList) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
groups = append(groups, group)
|
groups = append(groups, outboundGroup)
|
||||||
}
|
}
|
||||||
return varbin.Write(writer, binary.BigEndian, groups)
|
return varbin.Write(writer, binary.BigEndian, groups)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/protocol/group"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/varbin"
|
"github.com/sagernet/sing/common/varbin"
|
||||||
)
|
)
|
||||||
|
@ -47,7 +47,7 @@ func (s *CommandServer) handleSelectOutbound(conn net.Conn) error {
|
||||||
if !isLoaded {
|
if !isLoaded {
|
||||||
return writeError(conn, E.New("selector not found: ", groupTag))
|
return writeError(conn, E.New("selector not found: ", groupTag))
|
||||||
}
|
}
|
||||||
selector, isSelector := outboundGroup.(*outbound.Selector)
|
selector, isSelector := outboundGroup.(*group.Selector)
|
||||||
if !isSelector {
|
if !isSelector {
|
||||||
return writeError(conn, E.New("outbound is not a selector: ", groupTag))
|
return writeError(conn, E.New("outbound is not a selector: ", groupTag))
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/protocol/group"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/batch"
|
"github.com/sagernet/sing/common/batch"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
@ -49,7 +49,7 @@ func (s *CommandServer) handleURLTest(conn net.Conn) error {
|
||||||
if !isOutboundGroup {
|
if !isOutboundGroup {
|
||||||
return writeError(conn, E.New("outbound is not a group: ", groupTag))
|
return writeError(conn, E.New("outbound is not a group: ", groupTag))
|
||||||
}
|
}
|
||||||
urlTest, isURLTest := abstractOutboundGroup.(*outbound.URLTest)
|
urlTest, isURLTest := abstractOutboundGroup.(*group.URLTest)
|
||||||
if isURLTest {
|
if isURLTest {
|
||||||
go urlTest.CheckOutbounds()
|
go urlTest.CheckOutbounds()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||||
"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/include"
|
||||||
"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-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
|
@ -47,6 +48,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||||
}
|
}
|
||||||
runtimeDebug.FreeOSMemory()
|
runtimeDebug.FreeOSMemory()
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
ctx = box.Context(ctx, include.OutboundRegistry())
|
||||||
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
||||||
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
||||||
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/humanize"
|
"github.com/sagernet/sing-box/common/humanize"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
_ "github.com/sagernet/sing-box/include"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -3,7 +3,6 @@ module github.com/sagernet/sing-box
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
berty.tech/go-libtor v1.0.385
|
|
||||||
github.com/caddyserver/certmagic v0.20.0
|
github.com/caddyserver/certmagic v0.20.0
|
||||||
github.com/cloudflare/circl v1.3.7
|
github.com/cloudflare/circl v1.3.7
|
||||||
github.com/cretz/bine v0.2.0
|
github.com/cretz/bine v0.2.0
|
||||||
|
@ -17,7 +16,6 @@ require (
|
||||||
github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa
|
github.com/metacubex/tfo-go v0.0.0-20241006021335-daedaf0ca7aa
|
||||||
github.com/mholt/acmez v1.2.0
|
github.com/mholt/acmez v1.2.0
|
||||||
github.com/miekg/dns v1.1.62
|
github.com/miekg/dns v1.1.62
|
||||||
github.com/ooni/go-libtor v1.1.8
|
|
||||||
github.com/oschwald/maxminddb-golang v1.12.0
|
github.com/oschwald/maxminddb-golang v1.12.0
|
||||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1
|
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1
|
||||||
|
@ -27,7 +25,7 @@ require (
|
||||||
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3
|
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3
|
||||||
github.com/sagernet/quic-go v0.48.0-beta.1
|
github.com/sagernet/quic-go v0.48.0-beta.1
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||||
github.com/sagernet/sing v0.5.0-rc.4.0.20241023053048-94f058276959
|
github.com/sagernet/sing v0.5.0-rc.4.0.20241101160402-8452992a6369
|
||||||
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a
|
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a
|
||||||
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec
|
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec
|
||||||
github.com/sagernet/sing-quic v0.3.0-rc.1
|
github.com/sagernet/sing-quic v0.3.0-rc.1
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -1,5 +1,3 @@
|
||||||
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
|
|
||||||
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
|
||||||
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.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||||
|
@ -9,7 +7,6 @@ github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NY
|
||||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
|
||||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -81,8 +78,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
|
||||||
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
||||||
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
|
||||||
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
||||||
github.com/ooni/go-libtor v1.1.8 h1:Wo3V3DVTxl5vZdxtQakqYP+DAHx7pPtAFSl1bnAa08w=
|
|
||||||
github.com/ooni/go-libtor v1.1.8/go.mod h1:q1YyLwRD9GeMyeerVvwc0vJ2YgwDLTp2bdVcrh/JXyI=
|
|
||||||
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
|
||||||
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
|
||||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||||
|
@ -115,8 +110,8 @@ github.com/sagernet/quic-go v0.48.0-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||||
github.com/sagernet/sing v0.5.0-rc.4.0.20241023053048-94f058276959 h1:8BzTt5cU8h6HK4CcRq1UQHKsgUi942GjO0by/ntFZIs=
|
github.com/sagernet/sing v0.5.0-rc.4.0.20241101160402-8452992a6369 h1:gfiUYWslwKM7OtvG37PV0iIDCWcacJSEUS2h29rpYac=
|
||||||
github.com/sagernet/sing v0.5.0-rc.4.0.20241023053048-94f058276959/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.5.0-rc.4.0.20241101160402-8452992a6369/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a h1:jpAlbmZxc1LymZrmJacsvHI57Wito5xy8qASZJMWoOQ=
|
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a h1:jpAlbmZxc1LymZrmJacsvHI57Wito5xy8qASZJMWoOQ=
|
||||||
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
|
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
|
||||||
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec h1:6Fd/VsEsw9qIjaGi1IBTZSb4b4v5JYtNcoiBtGsQC48=
|
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec h1:6Fd/VsEsw9qIjaGi1IBTZSb4b4v5JYtNcoiBtGsQC48=
|
||||||
|
@ -146,7 +141,6 @@ github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3k
|
||||||
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=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
@ -168,7 +162,6 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
|
@ -182,7 +175,6 @@ golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
59
include/outbound.go
Normal file
59
include/outbound.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package include
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing-box/protocol/block"
|
||||||
|
"github.com/sagernet/sing-box/protocol/direct"
|
||||||
|
"github.com/sagernet/sing-box/protocol/dns"
|
||||||
|
"github.com/sagernet/sing-box/protocol/group"
|
||||||
|
"github.com/sagernet/sing-box/protocol/http"
|
||||||
|
"github.com/sagernet/sing-box/protocol/shadowsocks"
|
||||||
|
"github.com/sagernet/sing-box/protocol/shadowtls"
|
||||||
|
"github.com/sagernet/sing-box/protocol/socks"
|
||||||
|
"github.com/sagernet/sing-box/protocol/ssh"
|
||||||
|
"github.com/sagernet/sing-box/protocol/tor"
|
||||||
|
"github.com/sagernet/sing-box/protocol/trojan"
|
||||||
|
"github.com/sagernet/sing-box/protocol/vless"
|
||||||
|
"github.com/sagernet/sing-box/protocol/vmess"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func OutboundRegistry() *outbound.Registry {
|
||||||
|
registry := outbound.NewRegistry()
|
||||||
|
|
||||||
|
direct.RegisterOutbound(registry)
|
||||||
|
|
||||||
|
block.RegisterOutbound(registry)
|
||||||
|
dns.RegisterOutbound(registry)
|
||||||
|
|
||||||
|
group.RegisterSelector(registry)
|
||||||
|
group.RegisterURLTest(registry)
|
||||||
|
|
||||||
|
socks.RegisterOutbound(registry)
|
||||||
|
http.RegisterOutbound(registry)
|
||||||
|
shadowsocks.RegisterOutbound(registry)
|
||||||
|
vmess.RegisterOutbound(registry)
|
||||||
|
trojan.RegisterOutbound(registry)
|
||||||
|
tor.RegisterOutbound(registry)
|
||||||
|
ssh.RegisterOutbound(registry)
|
||||||
|
shadowtls.RegisterOutbound(registry)
|
||||||
|
vless.RegisterOutbound(registry)
|
||||||
|
|
||||||
|
registerQUICOutbounds(registry)
|
||||||
|
registerWireGuardOutbound(registry)
|
||||||
|
registerStubForRemovedOutbounds(registry)
|
||||||
|
|
||||||
|
return registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerStubForRemovedOutbounds(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.ShadowsocksROutboundOptions](registry, C.TypeShadowsocksR, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (adapter.Outbound, error) {
|
||||||
|
return nil, E.New("ShadowsocksR is deprecated and removed in sing-box 1.6.0")
|
||||||
|
})
|
||||||
|
}
|
|
@ -3,6 +3,16 @@
|
||||||
package include
|
package include
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
"github.com/sagernet/sing-box/protocol/hysteria"
|
||||||
|
"github.com/sagernet/sing-box/protocol/hysteria2"
|
||||||
|
"github.com/sagernet/sing-box/protocol/tuic"
|
||||||
_ "github.com/sagernet/sing-box/transport/v2rayquic"
|
_ "github.com/sagernet/sing-box/transport/v2rayquic"
|
||||||
_ "github.com/sagernet/sing-dns/quic"
|
_ "github.com/sagernet/sing-dns/quic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func registerQUICOutbounds(registry *outbound.Registry) {
|
||||||
|
hysteria.RegisterOutbound(registry)
|
||||||
|
tuic.RegisterOutbound(registry)
|
||||||
|
hysteria2.RegisterOutbound(registry)
|
||||||
|
}
|
||||||
|
|
|
@ -6,8 +6,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"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-dns"
|
||||||
|
@ -29,3 +31,15 @@ func init() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerQUICOutbounds(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.HysteriaOutboundOptions](registry, C.TypeHysteria, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (adapter.Outbound, error) {
|
||||||
|
return nil, C.ErrQUICNotIncluded
|
||||||
|
})
|
||||||
|
outbound.Register[option.TUICOutboundOptions](registry, C.TypeTUIC, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TUICOutboundOptions) (adapter.Outbound, error) {
|
||||||
|
return nil, C.ErrQUICNotIncluded
|
||||||
|
})
|
||||||
|
outbound.Register[option.Hysteria2OutboundOptions](registry, C.TypeHysteria2, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Hysteria2OutboundOptions) (adapter.Outbound, error) {
|
||||||
|
return nil, C.ErrQUICNotIncluded
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
12
include/wireguard.go
Normal file
12
include/wireguard.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build with_wireguard
|
||||||
|
|
||||||
|
package include
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
"github.com/sagernet/sing-box/protocol/wireguard"
|
||||||
|
)
|
||||||
|
|
||||||
|
func registerWireGuardOutbound(registry *outbound.Registry) {
|
||||||
|
wireguard.RegisterOutbound(registry)
|
||||||
|
}
|
20
include/wireguard_stub.go
Normal file
20
include/wireguard_stub.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//go:build !with_wireguard
|
||||||
|
|
||||||
|
package include
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func registerWireGuardOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.WireGuardOutboundOptions](registry, C.TypeWireGuard, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardOutboundOptions) (adapter.Outbound, error) {
|
||||||
|
return nil, E.New(`WireGuard is not included in this build, rebuild with -tags with_wireguard`)
|
||||||
|
})
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _Inbound struct {
|
type _Inbound struct {
|
||||||
|
@ -79,7 +80,7 @@ func (h Inbound) MarshalJSON() ([]byte, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return MarshallObjects((_Inbound)(h), rawOptions)
|
return badjson.MarshallObjects((_Inbound)(h), rawOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Inbound) UnmarshalJSON(bytes []byte) error {
|
func (h *Inbound) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -91,7 +92,7 @@ func (h *Inbound) UnmarshalJSON(bytes []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_Inbound)(h), rawOptions)
|
err = badjson.UnmarshallExcluded(bytes, (*_Inbound)(h), rawOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
package option
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
"github.com/sagernet/sing/common/json"
|
|
||||||
"github.com/sagernet/sing/common/json/badjson"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ToMap(v any) (*badjson.JSONObject, error) {
|
|
||||||
inputContent, err := json.Marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var content badjson.JSONObject
|
|
||||||
err = content.UnmarshalJSON(inputContent)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &content, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MergeObjects(objects ...any) (*badjson.JSONObject, error) {
|
|
||||||
var content badjson.JSONObject
|
|
||||||
for _, object := range objects {
|
|
||||||
objectMap, err := ToMap(object)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
content.PutAll(objectMap)
|
|
||||||
}
|
|
||||||
return &content, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshallObjects(objects ...any) ([]byte, error) {
|
|
||||||
objects = common.FilterNotNil(objects)
|
|
||||||
if len(objects) == 1 {
|
|
||||||
return json.Marshal(objects[0])
|
|
||||||
}
|
|
||||||
content, err := MergeObjects(objects...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return content.MarshalJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshallExcluded(inputContent []byte, parentObject any, object any) error {
|
|
||||||
parentContent, err := ToMap(parentObject)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var content badjson.JSONObject
|
|
||||||
err = content.UnmarshalJSON(inputContent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, key := range parentContent.Keys() {
|
|
||||||
content.Remove(key)
|
|
||||||
}
|
|
||||||
if object == nil {
|
|
||||||
if content.IsEmpty() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return E.New("unexpected key: ", content.Keys()[0])
|
|
||||||
}
|
|
||||||
inputContent, err = content.MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return json.UnmarshalDisallowUnknownFields(inputContent, object)
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
@ -16,12 +17,15 @@ type _Options struct {
|
||||||
Outbounds []Outbound `json:"outbounds,omitempty"`
|
Outbounds []Outbound `json:"outbounds,omitempty"`
|
||||||
Route *RouteOptions `json:"route,omitempty"`
|
Route *RouteOptions `json:"route,omitempty"`
|
||||||
Experimental *ExperimentalOptions `json:"experimental,omitempty"`
|
Experimental *ExperimentalOptions `json:"experimental,omitempty"`
|
||||||
|
|
||||||
|
// Deprecated: use Outbounds instead
|
||||||
|
LegacyOutbounds []LegacyOutbound `json:"_"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options _Options
|
type Options _Options
|
||||||
|
|
||||||
func (o *Options) UnmarshalJSON(content []byte) error {
|
func (o *Options) UnmarshalJSONContext(ctx context.Context, content []byte) error {
|
||||||
decoder := json.NewDecoder(bytes.NewReader(content))
|
decoder := json.NewDecoderContext(ctx, bytes.NewReader(content))
|
||||||
decoder.DisallowUnknownFields()
|
decoder.DisallowUnknownFields()
|
||||||
err := decoder.Decode((*_Options)(o))
|
err := decoder.Decode((*_Options)(o))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -38,3 +42,5 @@ type LogOptions struct {
|
||||||
Timestamp bool `json:"timestamp,omitempty"`
|
Timestamp bool `json:"timestamp,omitempty"`
|
||||||
DisableColor bool `json:"-"`
|
DisableColor bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StubOptions struct{}
|
|
@ -1,104 +1,49 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
C "github.com/sagernet/sing-box/constant"
|
"context"
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type OutboundOptionsRegistry interface {
|
||||||
|
CreateOptions(outboundType string) (any, bool)
|
||||||
|
}
|
||||||
|
|
||||||
type _Outbound struct {
|
type _Outbound struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Tag string `json:"tag,omitempty"`
|
Tag string `json:"tag,omitempty"`
|
||||||
DirectOptions DirectOutboundOptions `json:"-"`
|
Options any `json:"-"`
|
||||||
SocksOptions SocksOutboundOptions `json:"-"`
|
|
||||||
HTTPOptions HTTPOutboundOptions `json:"-"`
|
|
||||||
ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"`
|
|
||||||
VMessOptions VMessOutboundOptions `json:"-"`
|
|
||||||
TrojanOptions TrojanOutboundOptions `json:"-"`
|
|
||||||
WireGuardOptions WireGuardOutboundOptions `json:"-"`
|
|
||||||
HysteriaOptions HysteriaOutboundOptions `json:"-"`
|
|
||||||
TorOptions TorOutboundOptions `json:"-"`
|
|
||||||
SSHOptions SSHOutboundOptions `json:"-"`
|
|
||||||
ShadowTLSOptions ShadowTLSOutboundOptions `json:"-"`
|
|
||||||
ShadowsocksROptions ShadowsocksROutboundOptions `json:"-"`
|
|
||||||
VLESSOptions VLESSOutboundOptions `json:"-"`
|
|
||||||
TUICOptions TUICOutboundOptions `json:"-"`
|
|
||||||
Hysteria2Options Hysteria2OutboundOptions `json:"-"`
|
|
||||||
SelectorOptions SelectorOutboundOptions `json:"-"`
|
|
||||||
URLTestOptions URLTestOutboundOptions `json:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Outbound _Outbound
|
type Outbound _Outbound
|
||||||
|
|
||||||
func (h *Outbound) RawOptions() (any, error) {
|
func (h *Outbound) MarshalJSONContext(ctx context.Context) ([]byte, error) {
|
||||||
var rawOptionsPtr any
|
return badjson.MarshallObjectsContext(ctx, (*_Outbound)(h), h.Options)
|
||||||
switch h.Type {
|
|
||||||
case C.TypeDirect:
|
|
||||||
rawOptionsPtr = &h.DirectOptions
|
|
||||||
case C.TypeBlock, C.TypeDNS:
|
|
||||||
rawOptionsPtr = nil
|
|
||||||
case C.TypeSOCKS:
|
|
||||||
rawOptionsPtr = &h.SocksOptions
|
|
||||||
case C.TypeHTTP:
|
|
||||||
rawOptionsPtr = &h.HTTPOptions
|
|
||||||
case C.TypeShadowsocks:
|
|
||||||
rawOptionsPtr = &h.ShadowsocksOptions
|
|
||||||
case C.TypeVMess:
|
|
||||||
rawOptionsPtr = &h.VMessOptions
|
|
||||||
case C.TypeTrojan:
|
|
||||||
rawOptionsPtr = &h.TrojanOptions
|
|
||||||
case C.TypeWireGuard:
|
|
||||||
rawOptionsPtr = &h.WireGuardOptions
|
|
||||||
case C.TypeHysteria:
|
|
||||||
rawOptionsPtr = &h.HysteriaOptions
|
|
||||||
case C.TypeTor:
|
|
||||||
rawOptionsPtr = &h.TorOptions
|
|
||||||
case C.TypeSSH:
|
|
||||||
rawOptionsPtr = &h.SSHOptions
|
|
||||||
case C.TypeShadowTLS:
|
|
||||||
rawOptionsPtr = &h.ShadowTLSOptions
|
|
||||||
case C.TypeShadowsocksR:
|
|
||||||
rawOptionsPtr = &h.ShadowsocksROptions
|
|
||||||
case C.TypeVLESS:
|
|
||||||
rawOptionsPtr = &h.VLESSOptions
|
|
||||||
case C.TypeTUIC:
|
|
||||||
rawOptionsPtr = &h.TUICOptions
|
|
||||||
case C.TypeHysteria2:
|
|
||||||
rawOptionsPtr = &h.Hysteria2Options
|
|
||||||
case C.TypeSelector:
|
|
||||||
rawOptionsPtr = &h.SelectorOptions
|
|
||||||
case C.TypeURLTest:
|
|
||||||
rawOptionsPtr = &h.URLTestOptions
|
|
||||||
case "":
|
|
||||||
return nil, E.New("missing outbound type")
|
|
||||||
default:
|
|
||||||
return nil, E.New("unknown outbound type: ", h.Type)
|
|
||||||
}
|
|
||||||
return rawOptionsPtr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Outbound) MarshalJSON() ([]byte, error) {
|
func (h *Outbound) UnmarshalJSONContext(ctx context.Context, content []byte) error {
|
||||||
rawOptions, err := h.RawOptions()
|
err := json.Unmarshal(content, (*_Outbound)(h))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return MarshallObjects((*_Outbound)(h), rawOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Outbound) UnmarshalJSON(bytes []byte) error {
|
|
||||||
err := json.Unmarshal(bytes, (*_Outbound)(h))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rawOptions, err := h.RawOptions()
|
registry := service.FromContext[OutboundOptionsRegistry](ctx)
|
||||||
if err != nil {
|
if registry == nil {
|
||||||
return err
|
return E.New("missing outbound options registry in context")
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_Outbound)(h), rawOptions)
|
options, loaded := registry.CreateOptions(h.Type)
|
||||||
|
if !loaded {
|
||||||
|
return E.New("unknown outbound type: ", h.Type)
|
||||||
|
}
|
||||||
|
err = badjson.UnmarshallExcludedContext(ctx, content, (*_Outbound)(h), options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
h.Options = options
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
103
option/outbound_legacy.go
Normal file
103
option/outbound_legacy.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package option
|
||||||
|
|
||||||
|
import (
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
type _LegacyOutbound struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Tag string `json:"tag,omitempty"`
|
||||||
|
DirectOptions DirectOutboundOptions `json:"-"`
|
||||||
|
SocksOptions SOCKSOutboundOptions `json:"-"`
|
||||||
|
HTTPOptions HTTPOutboundOptions `json:"-"`
|
||||||
|
ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"`
|
||||||
|
VMessOptions VMessOutboundOptions `json:"-"`
|
||||||
|
TrojanOptions TrojanOutboundOptions `json:"-"`
|
||||||
|
WireGuardOptions WireGuardOutboundOptions `json:"-"`
|
||||||
|
HysteriaOptions HysteriaOutboundOptions `json:"-"`
|
||||||
|
TorOptions TorOutboundOptions `json:"-"`
|
||||||
|
SSHOptions SSHOutboundOptions `json:"-"`
|
||||||
|
ShadowTLSOptions ShadowTLSOutboundOptions `json:"-"`
|
||||||
|
ShadowsocksROptions ShadowsocksROutboundOptions `json:"-"`
|
||||||
|
VLESSOptions VLESSOutboundOptions `json:"-"`
|
||||||
|
TUICOptions TUICOutboundOptions `json:"-"`
|
||||||
|
Hysteria2Options Hysteria2OutboundOptions `json:"-"`
|
||||||
|
SelectorOptions SelectorOutboundOptions `json:"-"`
|
||||||
|
URLTestOptions URLTestOutboundOptions `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LegacyOutbound _LegacyOutbound
|
||||||
|
|
||||||
|
func (h *LegacyOutbound) RawOptions() (any, error) {
|
||||||
|
var rawOptionsPtr any
|
||||||
|
switch h.Type {
|
||||||
|
case C.TypeDirect:
|
||||||
|
rawOptionsPtr = &h.DirectOptions
|
||||||
|
case C.TypeBlock, C.TypeDNS:
|
||||||
|
rawOptionsPtr = new(StubOptions)
|
||||||
|
case C.TypeSOCKS:
|
||||||
|
rawOptionsPtr = &h.SocksOptions
|
||||||
|
case C.TypeHTTP:
|
||||||
|
rawOptionsPtr = &h.HTTPOptions
|
||||||
|
case C.TypeShadowsocks:
|
||||||
|
rawOptionsPtr = &h.ShadowsocksOptions
|
||||||
|
case C.TypeVMess:
|
||||||
|
rawOptionsPtr = &h.VMessOptions
|
||||||
|
case C.TypeTrojan:
|
||||||
|
rawOptionsPtr = &h.TrojanOptions
|
||||||
|
case C.TypeWireGuard:
|
||||||
|
rawOptionsPtr = &h.WireGuardOptions
|
||||||
|
case C.TypeHysteria:
|
||||||
|
rawOptionsPtr = &h.HysteriaOptions
|
||||||
|
case C.TypeTor:
|
||||||
|
rawOptionsPtr = &h.TorOptions
|
||||||
|
case C.TypeSSH:
|
||||||
|
rawOptionsPtr = &h.SSHOptions
|
||||||
|
case C.TypeShadowTLS:
|
||||||
|
rawOptionsPtr = &h.ShadowTLSOptions
|
||||||
|
case C.TypeShadowsocksR:
|
||||||
|
rawOptionsPtr = &h.ShadowsocksROptions
|
||||||
|
case C.TypeVLESS:
|
||||||
|
rawOptionsPtr = &h.VLESSOptions
|
||||||
|
case C.TypeTUIC:
|
||||||
|
rawOptionsPtr = &h.TUICOptions
|
||||||
|
case C.TypeHysteria2:
|
||||||
|
rawOptionsPtr = &h.Hysteria2Options
|
||||||
|
case C.TypeSelector:
|
||||||
|
rawOptionsPtr = &h.SelectorOptions
|
||||||
|
case C.TypeURLTest:
|
||||||
|
rawOptionsPtr = &h.URLTestOptions
|
||||||
|
case "":
|
||||||
|
return nil, E.New("missing outbound type")
|
||||||
|
default:
|
||||||
|
return nil, E.New("unknown outbound type: ", h.Type)
|
||||||
|
}
|
||||||
|
return rawOptionsPtr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *LegacyOutbound) MarshalJSON() ([]byte, error) {
|
||||||
|
rawOptions, err := h.RawOptions()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return badjson.MarshallObjects((*_LegacyOutbound)(h), rawOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *LegacyOutbound) UnmarshalJSON(bytes []byte) error {
|
||||||
|
err := json.Unmarshal(bytes, (*_LegacyOutbound)(h))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rawOptions, err := h.RawOptions()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = badjson.UnmarshallExcluded(bytes, (*_LegacyOutbound)(h), rawOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _Rule struct {
|
type _Rule struct {
|
||||||
|
@ -28,7 +29,7 @@ func (r Rule) MarshalJSON() ([]byte, error) {
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown rule type: " + r.Type)
|
return nil, E.New("unknown rule type: " + r.Type)
|
||||||
}
|
}
|
||||||
return MarshallObjects((_Rule)(r), v)
|
return badjson.MarshallObjects((_Rule)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rule) UnmarshalJSON(bytes []byte) error {
|
func (r *Rule) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -46,7 +47,7 @@ func (r *Rule) UnmarshalJSON(bytes []byte) error {
|
||||||
default:
|
default:
|
||||||
return E.New("unknown rule type: " + r.Type)
|
return E.New("unknown rule type: " + r.Type)
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_Rule)(r), v)
|
err = badjson.UnmarshallExcluded(bytes, (*_Rule)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -109,7 +110,7 @@ type DefaultRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DefaultRule) MarshalJSON() ([]byte, error) {
|
func (r *DefaultRule) MarshalJSON() ([]byte, error) {
|
||||||
return MarshallObjects(r.RawDefaultRule, r.RuleAction)
|
return badjson.MarshallObjects(r.RawDefaultRule, r.RuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DefaultRule) UnmarshalJSON(data []byte) error {
|
func (r *DefaultRule) UnmarshalJSON(data []byte) error {
|
||||||
|
@ -117,7 +118,7 @@ func (r *DefaultRule) UnmarshalJSON(data []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return UnmarshallExcluded(data, &r.RawDefaultRule, &r.RuleAction)
|
return badjson.UnmarshallExcluded(data, &r.RawDefaultRule, &r.RuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DefaultRule) IsValid() bool {
|
func (r *DefaultRule) IsValid() bool {
|
||||||
|
@ -139,7 +140,7 @@ type LogicalRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LogicalRule) MarshalJSON() ([]byte, error) {
|
func (r *LogicalRule) MarshalJSON() ([]byte, error) {
|
||||||
return MarshallObjects(r._LogicalRule, r.RuleAction)
|
return badjson.MarshallObjects(r._LogicalRule, r.RuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LogicalRule) UnmarshalJSON(data []byte) error {
|
func (r *LogicalRule) UnmarshalJSON(data []byte) error {
|
||||||
|
@ -147,7 +148,7 @@ func (r *LogicalRule) UnmarshalJSON(data []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return UnmarshallExcluded(data, &r._LogicalRule, &r.RuleAction)
|
return badjson.UnmarshallExcluded(data, &r._LogicalRule, &r.RuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LogicalRule) IsValid() bool {
|
func (r *LogicalRule) IsValid() bool {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _RuleAction struct {
|
type _RuleAction struct {
|
||||||
|
@ -36,9 +37,9 @@ func (r RuleAction) MarshalJSON() ([]byte, error) {
|
||||||
return nil, E.New("unknown rule action: " + r.Action)
|
return nil, E.New("unknown rule action: " + r.Action)
|
||||||
}
|
}
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return MarshallObjects((_RuleAction)(r))
|
return badjson.MarshallObjects((_RuleAction)(r))
|
||||||
}
|
}
|
||||||
return MarshallObjects((_RuleAction)(r), v)
|
return badjson.MarshallObjects((_RuleAction)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuleAction) UnmarshalJSON(data []byte) error {
|
func (r *RuleAction) UnmarshalJSON(data []byte) error {
|
||||||
|
@ -68,7 +69,7 @@ func (r *RuleAction) UnmarshalJSON(data []byte) error {
|
||||||
// check unknown fields
|
// check unknown fields
|
||||||
return json.UnmarshalDisallowUnknownFields(data, &_RuleAction{})
|
return json.UnmarshalDisallowUnknownFields(data, &_RuleAction{})
|
||||||
}
|
}
|
||||||
return UnmarshallExcluded(data, (*_RuleAction)(r), v)
|
return badjson.UnmarshallExcluded(data, (*_RuleAction)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
type _DNSRuleAction struct {
|
type _DNSRuleAction struct {
|
||||||
|
@ -95,9 +96,9 @@ func (r DNSRuleAction) MarshalJSON() ([]byte, error) {
|
||||||
return nil, E.New("unknown DNS rule action: " + r.Action)
|
return nil, E.New("unknown DNS rule action: " + r.Action)
|
||||||
}
|
}
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return MarshallObjects((_DNSRuleAction)(r))
|
return badjson.MarshallObjects((_DNSRuleAction)(r))
|
||||||
}
|
}
|
||||||
return MarshallObjects((_DNSRuleAction)(r), v)
|
return badjson.MarshallObjects((_DNSRuleAction)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DNSRuleAction) UnmarshalJSON(data []byte) error {
|
func (r *DNSRuleAction) UnmarshalJSON(data []byte) error {
|
||||||
|
@ -121,7 +122,7 @@ func (r *DNSRuleAction) UnmarshalJSON(data []byte) error {
|
||||||
// check unknown fields
|
// check unknown fields
|
||||||
return json.UnmarshalDisallowUnknownFields(data, &_DNSRuleAction{})
|
return json.UnmarshalDisallowUnknownFields(data, &_DNSRuleAction{})
|
||||||
}
|
}
|
||||||
return UnmarshallExcluded(data, (*_DNSRuleAction)(r), v)
|
return badjson.UnmarshallExcluded(data, (*_DNSRuleAction)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RouteActionOptions struct {
|
type RouteActionOptions struct {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _DNSRule struct {
|
type _DNSRule struct {
|
||||||
|
@ -28,7 +29,7 @@ func (r DNSRule) MarshalJSON() ([]byte, error) {
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown rule type: " + r.Type)
|
return nil, E.New("unknown rule type: " + r.Type)
|
||||||
}
|
}
|
||||||
return MarshallObjects((_DNSRule)(r), v)
|
return badjson.MarshallObjects((_DNSRule)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DNSRule) UnmarshalJSON(bytes []byte) error {
|
func (r *DNSRule) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -46,7 +47,7 @@ func (r *DNSRule) UnmarshalJSON(bytes []byte) error {
|
||||||
default:
|
default:
|
||||||
return E.New("unknown rule type: " + r.Type)
|
return E.New("unknown rule type: " + r.Type)
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_DNSRule)(r), v)
|
err = badjson.UnmarshallExcluded(bytes, (*_DNSRule)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -111,7 +112,7 @@ type DefaultDNSRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DefaultDNSRule) MarshalJSON() ([]byte, error) {
|
func (r *DefaultDNSRule) MarshalJSON() ([]byte, error) {
|
||||||
return MarshallObjects(r.RawDefaultDNSRule, r.DNSRuleAction)
|
return badjson.MarshallObjects(r.RawDefaultDNSRule, r.DNSRuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DefaultDNSRule) UnmarshalJSON(data []byte) error {
|
func (r *DefaultDNSRule) UnmarshalJSON(data []byte) error {
|
||||||
|
@ -119,7 +120,7 @@ func (r *DefaultDNSRule) UnmarshalJSON(data []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return UnmarshallExcluded(data, &r.RawDefaultDNSRule, &r.DNSRuleAction)
|
return badjson.UnmarshallExcluded(data, &r.RawDefaultDNSRule, &r.DNSRuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DefaultDNSRule) IsValid() bool {
|
func (r *DefaultDNSRule) IsValid() bool {
|
||||||
|
@ -141,7 +142,7 @@ type LogicalDNSRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LogicalDNSRule) MarshalJSON() ([]byte, error) {
|
func (r *LogicalDNSRule) MarshalJSON() ([]byte, error) {
|
||||||
return MarshallObjects(r._LogicalDNSRule, r.DNSRuleAction)
|
return badjson.MarshallObjects(r._LogicalDNSRule, r.DNSRuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LogicalDNSRule) UnmarshalJSON(data []byte) error {
|
func (r *LogicalDNSRule) UnmarshalJSON(data []byte) error {
|
||||||
|
@ -149,7 +150,7 @@ func (r *LogicalDNSRule) UnmarshalJSON(data []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return UnmarshallExcluded(data, &r._LogicalDNSRule, &r.DNSRuleAction)
|
return badjson.UnmarshallExcluded(data, &r._LogicalDNSRule, &r.DNSRuleAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *LogicalDNSRule) IsValid() bool {
|
func (r *LogicalDNSRule) IsValid() bool {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
)
|
)
|
||||||
|
@ -37,7 +38,7 @@ func (r RuleSet) MarshalJSON() ([]byte, error) {
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown rule-set type: " + r.Type)
|
return nil, E.New("unknown rule-set type: " + r.Type)
|
||||||
}
|
}
|
||||||
return MarshallObjects((_RuleSet)(r), v)
|
return badjson.MarshallObjects((_RuleSet)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
|
func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -71,7 +72,7 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
|
||||||
} else {
|
} else {
|
||||||
r.Format = ""
|
r.Format = ""
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
|
err = badjson.UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -107,7 +108,7 @@ func (r HeadlessRule) MarshalJSON() ([]byte, error) {
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown rule type: " + r.Type)
|
return nil, E.New("unknown rule type: " + r.Type)
|
||||||
}
|
}
|
||||||
return MarshallObjects((_HeadlessRule)(r), v)
|
return badjson.MarshallObjects((_HeadlessRule)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *HeadlessRule) UnmarshalJSON(bytes []byte) error {
|
func (r *HeadlessRule) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -125,7 +126,7 @@ func (r *HeadlessRule) UnmarshalJSON(bytes []byte) error {
|
||||||
default:
|
default:
|
||||||
return E.New("unknown rule type: " + r.Type)
|
return E.New("unknown rule type: " + r.Type)
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_HeadlessRule)(r), v)
|
err = badjson.UnmarshallExcluded(bytes, (*_HeadlessRule)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -203,7 +204,7 @@ func (r PlainRuleSetCompat) MarshalJSON() ([]byte, error) {
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown rule-set version: ", r.Version)
|
return nil, E.New("unknown rule-set version: ", r.Version)
|
||||||
}
|
}
|
||||||
return MarshallObjects((_PlainRuleSetCompat)(r), v)
|
return badjson.MarshallObjects((_PlainRuleSetCompat)(r), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
|
func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -220,7 +221,7 @@ func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
|
||||||
default:
|
default:
|
||||||
return E.New("unknown rule-set version: ", r.Version)
|
return E.New("unknown rule-set version: ", r.Version)
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_PlainRuleSetCompat)(r), v)
|
err = badjson.UnmarshallExcluded(bytes, (*_PlainRuleSetCompat)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ type HTTPMixedInboundOptions struct {
|
||||||
InboundTLSOptionsContainer
|
InboundTLSOptionsContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocksOutboundOptions struct {
|
type SOCKSOutboundOptions struct {
|
||||||
DialerOptions
|
DialerOptions
|
||||||
ServerOptions
|
ServerOptions
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InboundACMEOptions struct {
|
type InboundACMEOptions struct {
|
||||||
|
@ -45,7 +46,7 @@ func (o ACMEDNS01ChallengeOptions) MarshalJSON() ([]byte, error) {
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown provider type: " + o.Provider)
|
return nil, E.New("unknown provider type: " + o.Provider)
|
||||||
}
|
}
|
||||||
return MarshallObjects((_ACMEDNS01ChallengeOptions)(o), v)
|
return badjson.MarshallObjects((_ACMEDNS01ChallengeOptions)(o), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -62,7 +63,7 @@ func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
default:
|
default:
|
||||||
return E.New("unknown provider type: " + o.Provider)
|
return E.New("unknown provider type: " + o.Provider)
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_ACMEDNS01ChallengeOptions)(o), v)
|
err = badjson.UnmarshallExcluded(bytes, (*_ACMEDNS01ChallengeOptions)(o), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _V2RayTransportOptions struct {
|
type _V2RayTransportOptions struct {
|
||||||
|
@ -35,7 +36,7 @@ func (o V2RayTransportOptions) MarshalJSON() ([]byte, error) {
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown transport type: " + o.Type)
|
return nil, E.New("unknown transport type: " + o.Type)
|
||||||
}
|
}
|
||||||
return MarshallObjects((_V2RayTransportOptions)(o), v)
|
return badjson.MarshallObjects((_V2RayTransportOptions)(o), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error {
|
func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
|
@ -58,7 +59,7 @@ func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
default:
|
default:
|
||||||
return E.New("unknown transport type: " + o.Type)
|
return E.New("unknown transport type: " + o.Type)
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_V2RayTransportOptions)(o), v)
|
err = badjson.UnmarshallExcluded(bytes, (*_V2RayTransportOptions)(o), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ adapter.Outbound = (*Block)(nil)
|
|
||||||
|
|
||||||
type Block struct {
|
|
||||||
myOutboundAdapter
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBlock(logger log.ContextLogger, tag string) *Block {
|
|
||||||
return &Block{
|
|
||||||
myOutboundAdapter{
|
|
||||||
protocol: C.TypeBlock,
|
|
||||||
network: []string{N.NetworkTCP, N.NetworkUDP},
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Block) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
|
||||||
h.logger.InfoContext(ctx, "blocked connection to ", destination)
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Block) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
|
||||||
h.logger.InfoContext(ctx, "blocked packet connection to ", destination)
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated
|
|
||||||
func (h *Block) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
|
||||||
conn.Close()
|
|
||||||
h.logger.InfoContext(ctx, "blocked connection to ", metadata.Destination)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated
|
|
||||||
func (h *Block) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
|
||||||
conn.Close()
|
|
||||||
h.logger.InfoContext(ctx, "blocked packet connection to ", metadata.Destination)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Outbound) (adapter.Outbound, error) {
|
|
||||||
if tag != "" {
|
|
||||||
ctx = adapter.WithContext(ctx, &adapter.InboundContext{
|
|
||||||
Outbound: tag,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if options.Type == "" {
|
|
||||||
return nil, E.New("missing outbound type")
|
|
||||||
}
|
|
||||||
ctx = ContextWithTag(ctx, tag)
|
|
||||||
switch options.Type {
|
|
||||||
case C.TypeDirect:
|
|
||||||
return NewDirect(router, logger, tag, options.DirectOptions)
|
|
||||||
case C.TypeBlock:
|
|
||||||
return NewBlock(logger, tag), nil
|
|
||||||
case C.TypeDNS:
|
|
||||||
return NewDNS(router, tag), nil
|
|
||||||
case C.TypeSOCKS:
|
|
||||||
return NewSocks(router, logger, tag, options.SocksOptions)
|
|
||||||
case C.TypeHTTP:
|
|
||||||
return NewHTTP(ctx, router, logger, tag, options.HTTPOptions)
|
|
||||||
case C.TypeShadowsocks:
|
|
||||||
return NewShadowsocks(ctx, router, logger, tag, options.ShadowsocksOptions)
|
|
||||||
case C.TypeVMess:
|
|
||||||
return NewVMess(ctx, router, logger, tag, options.VMessOptions)
|
|
||||||
case C.TypeTrojan:
|
|
||||||
return NewTrojan(ctx, router, logger, tag, options.TrojanOptions)
|
|
||||||
case C.TypeWireGuard:
|
|
||||||
return NewWireGuard(ctx, router, logger, tag, options.WireGuardOptions)
|
|
||||||
case C.TypeHysteria:
|
|
||||||
return NewHysteria(ctx, router, logger, tag, options.HysteriaOptions)
|
|
||||||
case C.TypeTor:
|
|
||||||
return NewTor(ctx, router, logger, tag, options.TorOptions)
|
|
||||||
case C.TypeSSH:
|
|
||||||
return NewSSH(ctx, router, logger, tag, options.SSHOptions)
|
|
||||||
case C.TypeShadowTLS:
|
|
||||||
return NewShadowTLS(ctx, router, logger, tag, options.ShadowTLSOptions)
|
|
||||||
case C.TypeShadowsocksR:
|
|
||||||
return NewShadowsocksR(ctx, router, logger, tag, options.ShadowsocksROptions)
|
|
||||||
case C.TypeVLESS:
|
|
||||||
return NewVLESS(ctx, router, logger, tag, options.VLESSOptions)
|
|
||||||
case C.TypeTUIC:
|
|
||||||
return NewTUIC(ctx, router, logger, tag, options.TUICOptions)
|
|
||||||
case C.TypeHysteria2:
|
|
||||||
return NewHysteria2(ctx, router, logger, tag, options.Hysteria2Options)
|
|
||||||
case C.TypeSelector:
|
|
||||||
return NewSelector(ctx, router, logger, tag, options.SelectorOptions)
|
|
||||||
case C.TypeURLTest:
|
|
||||||
return NewURLTest(ctx, router, logger, tag, options.URLTestOptions)
|
|
||||||
default:
|
|
||||||
return nil, E.New("unknown outbound type: ", options.Type)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
//go:build !with_quic
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (adapter.Outbound, error) {
|
|
||||||
return nil, C.ErrQUICNotIncluded
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHysteria2(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Hysteria2OutboundOptions) (adapter.Outbound, error) {
|
|
||||||
return nil, C.ErrQUICNotIncluded
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
//go:build with_shadowsocksr
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ int = "ShadowsocksR is deprecated and removed in sing-box 1.6.0"
|
|
||||||
|
|
||||||
func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (adapter.Outbound, error) {
|
|
||||||
return nil, os.ErrInvalid
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
//go:build !with_shadowsocksr
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (adapter.Outbound, error) {
|
|
||||||
return nil, E.New("ShadowsocksR is deprecated and removed in sing-box 1.6.0")
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
//go:build with_embedded_tor && !(android || ios)
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"berty.tech/go-libtor"
|
|
||||||
"github.com/cretz/bine/tor"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newConfig() tor.StartConf {
|
|
||||||
return tor.StartConf{
|
|
||||||
ProcessCreator: libtor.Creator,
|
|
||||||
UseEmbeddedControlConn: true,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
//go:build with_embedded_tor && (android || ios)
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/cretz/bine/tor"
|
|
||||||
"github.com/ooni/go-libtor"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newConfig() tor.StartConf {
|
|
||||||
return tor.StartConf{
|
|
||||||
ProcessCreator: libtor.Creator,
|
|
||||||
UseEmbeddedControlConn: true,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
//go:build !with_embedded_tor
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import "github.com/cretz/bine/tor"
|
|
||||||
|
|
||||||
func newConfig() tor.StartConf {
|
|
||||||
return tor.StartConf{}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
//go:build !with_quic
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TUICOutboundOptions) (adapter.Outbound, error) {
|
|
||||||
return nil, C.ErrQUICNotIncluded
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
//go:build !with_wireguard
|
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewWireGuard(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardOutboundOptions) (adapter.Outbound, error) {
|
|
||||||
return nil, E.New(`WireGuard is not included in this build, rebuild with -tags with_wireguard`)
|
|
||||||
}
|
|
42
protocol/block/outbound.go
Normal file
42
protocol/block/outbound.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package block
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.StubOptions](registry, C.TypeBlock, New)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Outbound struct {
|
||||||
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, _ option.StubOptions) (adapter.Outbound, error) {
|
||||||
|
return &Outbound{
|
||||||
|
Adapter: outbound.NewAdapter(C.TypeBlock, []string{N.NetworkTCP, N.NetworkUDP}, tag, nil),
|
||||||
|
logger: logger,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
h.logger.InfoContext(ctx, "blocked connection to ", destination)
|
||||||
|
return nil, syscall.EPERM
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
h.logger.InfoContext(ctx, "blocked packet connection to ", destination)
|
||||||
|
return nil, syscall.EPERM
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package direct
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package direct
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
|
@ -14,17 +15,20 @@ import (
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
_ adapter.Outbound = (*Direct)(nil)
|
outbound.Register[option.DirectOutboundOptions](registry, C.TypeDirect, NewOutbound)
|
||||||
_ N.ParallelDialer = (*Direct)(nil)
|
}
|
||||||
)
|
|
||||||
|
|
||||||
type Direct struct {
|
var _ N.ParallelDialer = (*Outbound)(nil)
|
||||||
myOutboundAdapter
|
|
||||||
|
type Outbound struct {
|
||||||
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
domainStrategy dns.DomainStrategy
|
domainStrategy dns.DomainStrategy
|
||||||
fallbackDelay time.Duration
|
fallbackDelay time.Duration
|
||||||
|
@ -33,21 +37,15 @@ type Direct struct {
|
||||||
// loopBack *loopBackDetector
|
// loopBack *loopBackDetector
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (*Direct, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
|
||||||
options.UDPFragmentDefault = true
|
options.UDPFragmentDefault = true
|
||||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &Direct{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, []string{N.NetworkTCP, N.NetworkUDP}, tag, options.DialerOptions),
|
||||||
protocol: C.TypeDirect,
|
logger: logger,
|
||||||
network: []string{N.NetworkTCP, N.NetworkUDP},
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
domainStrategy: dns.DomainStrategy(options.DomainStrategy),
|
domainStrategy: dns.DomainStrategy(options.DomainStrategy),
|
||||||
fallbackDelay: time.Duration(options.FallbackDelay),
|
fallbackDelay: time.Duration(options.FallbackDelay),
|
||||||
dialer: outboundDialer,
|
dialer: outboundDialer,
|
||||||
|
@ -69,9 +67,9 @@ func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, opti
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Direct) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
switch h.overrideOption {
|
switch h.overrideOption {
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -98,9 +96,9 @@ func (h *Direct) DialContext(ctx context.Context, network string, destination M.
|
||||||
return h.dialer.DialContext(ctx, network, destination)
|
return h.dialer.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Direct) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
|
func (h *Outbound) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
switch h.overrideOption {
|
switch h.overrideOption {
|
||||||
case 1, 2:
|
case 1, 2:
|
||||||
|
@ -125,9 +123,9 @@ func (h *Direct) DialParallel(ctx context.Context, network string, destination M
|
||||||
return N.DialParallel(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, h.fallbackDelay)
|
return N.DialParallel(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, h.fallbackDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
originDestination := destination
|
originDestination := destination
|
||||||
switch h.overrideOption {
|
switch h.overrideOption {
|
||||||
|
@ -156,14 +154,14 @@ func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func (h *Direct) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
/*func (h *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
if h.loopBack.CheckConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
if h.loopBack.CheckConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
||||||
return E.New("reject loopback connection to ", metadata.Destination)
|
return E.New("reject loopback connection to ", metadata.Destination)
|
||||||
}
|
}
|
||||||
return NewConnection(ctx, h, conn, metadata)
|
return NewConnection(ctx, h, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Direct) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (h *Outbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
if h.loopBack.CheckPacketConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
if h.loopBack.CheckPacketConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
||||||
return E.New("reject loopback packet connection to ", metadata.Destination)
|
return E.New("reject loopback packet connection to ", metadata.Destination)
|
||||||
}
|
}
|
|
@ -1,15 +1,13 @@
|
||||||
package outbound
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"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"
|
||||||
"github.com/sagernet/sing-dns"
|
dns "github.com/sagernet/sing-dns"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
@ -21,44 +19,6 @@ import (
|
||||||
mDNS "github.com/miekg/dns"
|
mDNS "github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*DNS)(nil)
|
|
||||||
|
|
||||||
type DNS struct {
|
|
||||||
myOutboundAdapter
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDNS(router adapter.Router, tag string) *DNS {
|
|
||||||
return &DNS{
|
|
||||||
myOutboundAdapter{
|
|
||||||
protocol: C.TypeDNS,
|
|
||||||
network: []string{N.NetworkTCP, N.NetworkUDP},
|
|
||||||
router: router,
|
|
||||||
tag: tag,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
|
||||||
return nil, os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DNS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
|
||||||
return nil, os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated
|
|
||||||
func (d *DNS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
|
||||||
metadata.Destination = M.Socksaddr{}
|
|
||||||
defer conn.Close()
|
|
||||||
for {
|
|
||||||
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
|
|
||||||
err := HandleStreamDNSRequest(ctx, d.router, conn, metadata)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleStreamDNSRequest(ctx context.Context, router adapter.Router, conn net.Conn, metadata adapter.InboundContext) error {
|
func HandleStreamDNSRequest(ctx context.Context, router adapter.Router, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
var queryLength uint16
|
var queryLength uint16
|
||||||
err := binary.Read(conn, binary.BigEndian, &queryLength)
|
err := binary.Read(conn, binary.BigEndian, &queryLength)
|
||||||
|
@ -100,11 +60,6 @@ func HandleStreamDNSRequest(ctx context.Context, router adapter.Router, conn net
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated
|
|
||||||
func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
|
||||||
return NewDNSPacketConnection(ctx, d.router, conn, nil, metadata)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.PacketConn, cachedPackets []*N.PacketBuffer, metadata adapter.InboundContext) error {
|
func NewDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.PacketConn, cachedPackets []*N.PacketBuffer, metadata adapter.InboundContext) error {
|
||||||
metadata.Destination = M.Socksaddr{}
|
metadata.Destination = M.Socksaddr{}
|
||||||
var reader N.PacketReader = conn
|
var reader N.PacketReader = conn
|
61
protocol/dns/outbound.go
Normal file
61
protocol/dns/outbound.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.StubOptions](registry, C.TypeDNS, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Outbound struct {
|
||||||
|
outbound.Adapter
|
||||||
|
router adapter.Router
|
||||||
|
logger logger.ContextLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.StubOptions) (adapter.Outbound, error) {
|
||||||
|
return &Outbound{
|
||||||
|
Adapter: outbound.NewAdapter(C.TypeDNS, []string{N.NetworkTCP, N.NetworkUDP}, tag, nil),
|
||||||
|
router: router,
|
||||||
|
logger: logger,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
|
func (d *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
|
metadata.Destination = M.Socksaddr{}
|
||||||
|
defer conn.Close()
|
||||||
|
for {
|
||||||
|
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
|
||||||
|
err := HandleStreamDNSRequest(ctx, d.router, conn, metadata)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated
|
||||||
|
func (d *Outbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
|
return NewDNSPacketConnection(ctx, d.router, conn, nil, metadata)
|
||||||
|
}
|
|
@ -1,28 +1,33 @@
|
||||||
package outbound
|
package group
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/interrupt"
|
"github.com/sagernet/sing-box/common/interrupt"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"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"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func RegisterSelector(registry *outbound.Registry) {
|
||||||
_ adapter.Outbound = (*Selector)(nil)
|
outbound.Register[option.SelectorOutboundOptions](registry, C.TypeSelector, NewSelector)
|
||||||
_ adapter.OutboundGroup = (*Selector)(nil)
|
}
|
||||||
)
|
|
||||||
|
var _ adapter.OutboundGroup = (*Selector)(nil)
|
||||||
|
|
||||||
type Selector struct {
|
type Selector struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
router adapter.Router
|
||||||
|
logger logger.ContextLogger
|
||||||
tags []string
|
tags []string
|
||||||
defaultTag string
|
defaultTag string
|
||||||
outbounds map[string]adapter.Outbound
|
outbounds map[string]adapter.Outbound
|
||||||
|
@ -31,16 +36,12 @@ type Selector struct {
|
||||||
interruptExternalConnections bool
|
interruptExternalConnections bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSelector(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SelectorOutboundOptions) (*Selector, error) {
|
func NewSelector(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SelectorOutboundOptions) (adapter.Outbound, error) {
|
||||||
outbound := &Selector{
|
outbound := &Selector{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapter(C.TypeSelector, nil, tag, options.Outbounds),
|
||||||
protocol: C.TypeSelector,
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: options.Outbounds,
|
|
||||||
},
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
router: router,
|
||||||
|
logger: logger,
|
||||||
tags: options.Outbounds,
|
tags: options.Outbounds,
|
||||||
defaultTag: options.Default,
|
defaultTag: options.Default,
|
||||||
outbounds: make(map[string]adapter.Outbound),
|
outbounds: make(map[string]adapter.Outbound),
|
||||||
|
@ -69,10 +70,10 @@ func (s *Selector) Start() error {
|
||||||
s.outbounds[tag] = detour
|
s.outbounds[tag] = detour
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.tag != "" {
|
if s.Tag() != "" {
|
||||||
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
||||||
if cacheFile != nil {
|
if cacheFile != nil {
|
||||||
selected := cacheFile.LoadSelected(s.tag)
|
selected := cacheFile.LoadSelected(s.Tag())
|
||||||
if selected != "" {
|
if selected != "" {
|
||||||
detour, loaded := s.outbounds[selected]
|
detour, loaded := s.outbounds[selected]
|
||||||
if loaded {
|
if loaded {
|
||||||
|
@ -113,10 +114,10 @@ func (s *Selector) SelectOutbound(tag string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
s.selected = detour
|
s.selected = detour
|
||||||
if s.tag != "" {
|
if s.Tag() != "" {
|
||||||
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
||||||
if cacheFile != nil {
|
if cacheFile != nil {
|
||||||
err := cacheFile.StoreSelected(s.tag, tag)
|
err := cacheFile.StoreSelected(s.Tag(), tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("store selected: ", err)
|
s.logger.Error("store selected: ", err)
|
||||||
}
|
}
|
||||||
|
@ -149,7 +150,7 @@ func (s *Selector) NewConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||||
if legacyHandler, ok := s.selected.(adapter.ConnectionHandler); ok {
|
if legacyHandler, ok := s.selected.(adapter.ConnectionHandler); ok {
|
||||||
return legacyHandler.NewConnection(ctx, conn, metadata)
|
return legacyHandler.NewConnection(ctx, conn, metadata)
|
||||||
} else {
|
} else {
|
||||||
return NewConnection(ctx, s.selected, conn, metadata)
|
return outbound.NewConnection(ctx, s.selected, conn, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +161,7 @@ func (s *Selector) NewPacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||||
if legacyHandler, ok := s.selected.(adapter.PacketConnectionHandler); ok {
|
if legacyHandler, ok := s.selected.(adapter.PacketConnectionHandler); ok {
|
||||||
return legacyHandler.NewPacketConnection(ctx, conn, metadata)
|
return legacyHandler.NewPacketConnection(ctx, conn, metadata)
|
||||||
} else {
|
} else {
|
||||||
return NewPacketConnection(ctx, s.selected, conn, metadata)
|
return outbound.NewPacketConnection(ctx, s.selected, conn, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package group
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/interrupt"
|
"github.com/sagernet/sing-box/common/interrupt"
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
@ -22,15 +23,20 @@ import (
|
||||||
"github.com/sagernet/sing/service/pause"
|
"github.com/sagernet/sing/service/pause"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func RegisterURLTest(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ adapter.Outbound = (*URLTest)(nil)
|
|
||||||
_ adapter.OutboundGroup = (*URLTest)(nil)
|
_ adapter.OutboundGroup = (*URLTest)(nil)
|
||||||
_ adapter.InterfaceUpdateListener = (*URLTest)(nil)
|
_ adapter.InterfaceUpdateListener = (*URLTest)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
type URLTest struct {
|
type URLTest struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
router adapter.Router
|
||||||
|
logger log.ContextLogger
|
||||||
tags []string
|
tags []string
|
||||||
link string
|
link string
|
||||||
interval time.Duration
|
interval time.Duration
|
||||||
|
@ -40,17 +46,12 @@ type URLTest struct {
|
||||||
interruptExternalConnections bool
|
interruptExternalConnections bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.URLTestOutboundOptions) (*URLTest, error) {
|
func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.URLTestOutboundOptions) (adapter.Outbound, error) {
|
||||||
outbound := &URLTest{
|
outbound := &URLTest{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapter(C.TypeURLTest, []string{N.NetworkTCP, N.NetworkUDP}, tag, options.Outbounds),
|
||||||
protocol: C.TypeURLTest,
|
|
||||||
network: []string{N.NetworkTCP, N.NetworkUDP},
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: options.Outbounds,
|
|
||||||
},
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
router: router,
|
||||||
|
logger: logger,
|
||||||
tags: options.Outbounds,
|
tags: options.Outbounds,
|
||||||
link: options.URL,
|
link: options.URL,
|
||||||
interval: time.Duration(options.Interval),
|
interval: time.Duration(options.Interval),
|
||||||
|
@ -171,14 +172,14 @@ func (s *URLTest) ListenPacket(ctx context.Context, destination M.Socksaddr) (ne
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func (s *URLTest) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (s *URLTest) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
ctx = interrupt.ContextWithIsExternalConnection(ctx)
|
ctx = interrupt.ContextWithIsExternalConnection(ctx)
|
||||||
return NewConnection(ctx, s, conn, metadata)
|
return outbound.NewConnection(ctx, s, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func (s *URLTest) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (s *URLTest) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
ctx = interrupt.ContextWithIsExternalConnection(ctx)
|
ctx = interrupt.ContextWithIsExternalConnection(ctx)
|
||||||
return NewPacketConnection(ctx, s, conn, metadata)
|
return outbound.NewPacketConnection(ctx, s, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *URLTest) InterfaceUpdated() {
|
func (s *URLTest) InterfaceUpdated() {
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -6,25 +6,30 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"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/logger"
|
||||||
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"
|
||||||
sHTTP "github.com/sagernet/sing/protocol/http"
|
sHTTP "github.com/sagernet/sing/protocol/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*HTTP)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.HTTPOutboundOptions](registry, C.TypeHTTP, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type HTTP struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
client *sHTTP.Client
|
client *sHTTP.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (*HTTP, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -33,16 +38,10 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &HTTP{
|
return &Outbound{
|
||||||
myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeHTTP, []string{N.NetworkTCP}, tag, options.DialerOptions),
|
||||||
protocol: C.TypeHTTP,
|
logger: logger,
|
||||||
network: []string{N.NetworkTCP},
|
client: sHTTP.NewClient(sHTTP.Options{
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
sHTTP.NewClient(sHTTP.Options{
|
|
||||||
Dialer: detour,
|
Dialer: detour,
|
||||||
Server: options.ServerOptions.Build(),
|
Server: options.ServerOptions.Build(),
|
||||||
Username: options.Username,
|
Username: options.Username,
|
||||||
|
@ -53,14 +52,14 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
return h.client.DialContext(ctx, network, destination)
|
return h.client.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTP) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
//go:build with_quic
|
package hysteria
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -8,31 +6,39 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/humanize"
|
"github.com/sagernet/sing-box/common/humanize"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"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/protocol/tuic"
|
||||||
"github.com/sagernet/sing-quic/hysteria"
|
"github.com/sagernet/sing-quic/hysteria"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.HysteriaOutboundOptions](registry, C.TypeHysteria, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ adapter.Outbound = (*TUIC)(nil)
|
_ adapter.Outbound = (*tuic.Outbound)(nil)
|
||||||
_ adapter.InterfaceUpdateListener = (*TUIC)(nil)
|
_ adapter.InterfaceUpdateListener = (*tuic.Outbound)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hysteria struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
client *hysteria.Client
|
client *hysteria.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (*Hysteria, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (adapter.Outbound, error) {
|
||||||
options.UDPFragmentDefault = true
|
options.UDPFragmentDefault = true
|
||||||
if options.TLS == nil || !options.TLS.Enabled {
|
if options.TLS == nil || !options.TLS.Enabled {
|
||||||
return nil, C.ErrTLSRequired
|
return nil, C.ErrTLSRequired
|
||||||
|
@ -88,20 +94,14 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Hysteria{
|
return &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeHysteria, networkList, tag, options.DialerOptions),
|
||||||
protocol: C.TypeHysteria,
|
logger: logger,
|
||||||
network: networkList,
|
client: client,
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
client: client,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
|
@ -117,15 +117,15 @@ func (h *Hysteria) DialContext(ctx context.Context, network string, destination
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
return h.client.ListenPacket(ctx, destination)
|
return h.client.ListenPacket(ctx, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria) InterfaceUpdated() {
|
func (h *Outbound) InterfaceUpdated() {
|
||||||
h.client.CloseWithError(E.New("network changed"))
|
h.client.CloseWithError(E.New("network changed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria) Close() error {
|
func (h *Outbound) Close() error {
|
||||||
return h.client.CloseWithError(os.ErrClosed)
|
return h.client.CloseWithError(os.ErrClosed)
|
||||||
}
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
//go:build with_quic
|
package hysteria2
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -8,31 +6,39 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"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/protocol/tuic"
|
||||||
"github.com/sagernet/sing-quic/hysteria"
|
"github.com/sagernet/sing-quic/hysteria"
|
||||||
"github.com/sagernet/sing-quic/hysteria2"
|
"github.com/sagernet/sing-quic/hysteria2"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.Hysteria2OutboundOptions](registry, C.TypeHysteria2, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ adapter.Outbound = (*TUIC)(nil)
|
_ adapter.Outbound = (*tuic.Outbound)(nil)
|
||||||
_ adapter.InterfaceUpdateListener = (*TUIC)(nil)
|
_ adapter.InterfaceUpdateListener = (*tuic.Outbound)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Hysteria2 struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
client *hysteria2.Client
|
client *hysteria2.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHysteria2(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Hysteria2OutboundOptions) (*Hysteria2, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Hysteria2OutboundOptions) (adapter.Outbound, error) {
|
||||||
options.UDPFragmentDefault = true
|
options.UDPFragmentDefault = true
|
||||||
if options.TLS == nil || !options.TLS.Enabled {
|
if options.TLS == nil || !options.TLS.Enabled {
|
||||||
return nil, C.ErrTLSRequired
|
return nil, C.ErrTLSRequired
|
||||||
|
@ -74,20 +80,14 @@ func NewHysteria2(ctx context.Context, router adapter.Router, logger log.Context
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Hysteria2{
|
return &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeHysteria2, networkList, tag, options.DialerOptions),
|
||||||
protocol: C.TypeHysteria2,
|
logger: logger,
|
||||||
network: networkList,
|
client: client,
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
client: client,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria2) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
|
@ -103,15 +103,15 @@ func (h *Hysteria2) DialContext(ctx context.Context, network string, destination
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria2) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
return h.client.ListenPacket(ctx)
|
return h.client.ListenPacket(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria2) InterfaceUpdated() {
|
func (h *Outbound) InterfaceUpdated() {
|
||||||
h.client.CloseWithError(E.New("network changed"))
|
h.client.CloseWithError(E.New("network changed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria2) Close() error {
|
func (h *Outbound) Close() error {
|
||||||
return h.client.CloseWithError(os.ErrClosed)
|
return h.client.CloseWithError(os.ErrClosed)
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package outbound
|
package shadowsocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/mux"
|
"github.com/sagernet/sing-box/common/mux"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
@ -15,15 +16,19 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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/common/uot"
|
"github.com/sagernet/sing/common/uot"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*Shadowsocks)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.ShadowsocksOutboundOptions](registry, C.TypeShadowsocks, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type Shadowsocks struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
method shadowsocks.Method
|
method shadowsocks.Method
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
|
@ -32,7 +37,7 @@ type Shadowsocks struct {
|
||||||
multiplexDialer *mux.Client
|
multiplexDialer *mux.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (adapter.Outbound, error) {
|
||||||
method, err := shadowsocks.CreateMethod(ctx, options.Method, shadowsocks.MethodOptions{
|
method, err := shadowsocks.CreateMethod(ctx, options.Method, shadowsocks.MethodOptions{
|
||||||
Password: options.Password,
|
Password: options.Password,
|
||||||
})
|
})
|
||||||
|
@ -43,15 +48,9 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &Shadowsocks{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeShadowsocks, options.Network.Build(), tag, options.DialerOptions),
|
||||||
protocol: C.TypeShadowsocks,
|
logger: logger,
|
||||||
network: options.Network.Build(),
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
dialer: outboundDialer,
|
dialer: outboundDialer,
|
||||||
method: method,
|
method: method,
|
||||||
serverAddr: options.ServerOptions.Build(),
|
serverAddr: options.ServerOptions.Build(),
|
||||||
|
@ -78,9 +77,9 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Shadowsocks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
|
@ -106,9 +105,9 @@ func (h *Shadowsocks) DialContext(ctx context.Context, network string, destinati
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
if h.uotClient != nil {
|
if h.uotClient != nil {
|
||||||
|
@ -125,24 +124,24 @@ func (h *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Shadowsocks) InterfaceUpdated() {
|
func (h *Outbound) InterfaceUpdated() {
|
||||||
if h.multiplexDialer != nil {
|
if h.multiplexDialer != nil {
|
||||||
h.multiplexDialer.Reset()
|
h.multiplexDialer.Reset()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Shadowsocks) Close() error {
|
func (h *Outbound) Close() error {
|
||||||
return common.Close(common.PtrOrNil(h.multiplexDialer))
|
return common.Close(common.PtrOrNil(h.multiplexDialer))
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ N.Dialer = (*shadowsocksDialer)(nil)
|
var _ N.Dialer = (*shadowsocksDialer)(nil)
|
||||||
|
|
||||||
type shadowsocksDialer Shadowsocks
|
type shadowsocksDialer Outbound
|
||||||
|
|
||||||
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.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
|
@ -170,7 +169,7 @@ func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, des
|
||||||
|
|
||||||
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.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
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 {
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package shadowtls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -6,6 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
@ -17,23 +18,18 @@ import (
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*ShadowTLS)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.ShadowTLSOutboundOptions](registry, C.TypeShadowTLS, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type ShadowTLS struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
client *shadowtls.Client
|
client *shadowtls.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowTLSOutboundOptions) (*ShadowTLS, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowTLSOutboundOptions) (adapter.Outbound, error) {
|
||||||
outbound := &ShadowTLS{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeShadowTLS, []string{N.NetworkTCP}, tag, options.DialerOptions),
|
||||||
protocol: C.TypeShadowTLS,
|
|
||||||
network: []string{N.NetworkTCP},
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
if options.TLS == nil || !options.TLS.Enabled {
|
if options.TLS == nil || !options.TLS.Enabled {
|
||||||
return nil, C.ErrTLSRequired
|
return nil, C.ErrTLSRequired
|
||||||
|
@ -91,9 +87,9 @@ func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.Context
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ShadowTLS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
|
@ -103,6 +99,6 @@ func (h *ShadowTLS) DialContext(ctx context.Context, network string, destination
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ShadowTLS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package outbound
|
package socks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
|
@ -12,22 +13,29 @@ import (
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
"github.com/sagernet/sing/common"
|
"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"
|
||||||
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/common/uot"
|
"github.com/sagernet/sing/common/uot"
|
||||||
"github.com/sagernet/sing/protocol/socks"
|
"github.com/sagernet/sing/protocol/socks"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*Socks)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.SOCKSOutboundOptions](registry, C.TypeSOCKS, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type Socks struct {
|
var _ adapter.Outbound = (*Outbound)(nil)
|
||||||
myOutboundAdapter
|
|
||||||
|
type Outbound struct {
|
||||||
|
outbound.Adapter
|
||||||
|
router adapter.Router
|
||||||
|
logger logger.ContextLogger
|
||||||
client *socks.Client
|
client *socks.Client
|
||||||
resolve bool
|
resolve bool
|
||||||
uotClient *uot.Client
|
uotClient *uot.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SOCKSOutboundOptions) (adapter.Outbound, error) {
|
||||||
var version socks.Version
|
var version socks.Version
|
||||||
var err error
|
var err error
|
||||||
if options.Version != "" {
|
if options.Version != "" {
|
||||||
|
@ -42,15 +50,10 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &Socks{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeSOCKS, options.Network.Build(), tag, options.DialerOptions),
|
||||||
protocol: C.TypeSOCKS,
|
router: router,
|
||||||
network: options.Network.Build(),
|
logger: logger,
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password),
|
client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password),
|
||||||
resolve: version == socks.Version4,
|
resolve: version == socks.Version4,
|
||||||
}
|
}
|
||||||
|
@ -64,9 +67,9 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Socks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
|
@ -90,9 +93,9 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
|
||||||
return h.client.DialContext(ctx, network, destination)
|
return h.client.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
if h.uotClient != nil {
|
if h.uotClient != nil {
|
||||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||||
|
@ -115,20 +118,20 @@ func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (h *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
if h.resolve {
|
if h.resolve {
|
||||||
return NewDirectConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4)
|
return outbound.NewDirectConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4)
|
||||||
} else {
|
} else {
|
||||||
return NewConnection(ctx, h, conn, metadata)
|
return outbound.NewConnection(ctx, h, conn, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func (h *Socks) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (h *Outbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
if h.resolve {
|
if h.resolve {
|
||||||
return NewDirectPacketConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4)
|
return outbound.NewDirectPacketConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4)
|
||||||
} else {
|
} else {
|
||||||
return NewPacketConnection(ctx, h, conn, metadata)
|
return outbound.NewPacketConnection(ctx, h, conn, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -12,26 +12,30 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"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"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
_ adapter.Outbound = (*SSH)(nil)
|
outbound.Register[option.SSHOutboundOptions](registry, C.TypeSSH, NewOutbound)
|
||||||
_ adapter.InterfaceUpdateListener = (*SSH)(nil)
|
}
|
||||||
)
|
|
||||||
|
|
||||||
type SSH struct {
|
var _ adapter.InterfaceUpdateListener = (*Outbound)(nil)
|
||||||
myOutboundAdapter
|
|
||||||
|
type Outbound struct {
|
||||||
|
outbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
logger logger.ContextLogger
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
user string
|
user string
|
||||||
|
@ -44,21 +48,15 @@ type SSH struct {
|
||||||
client *ssh.Client
|
client *ssh.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSSH(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SSHOutboundOptions) (*SSH, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SSHOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &SSH{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeSSH, []string{N.NetworkTCP}, tag, options.DialerOptions),
|
||||||
protocol: C.TypeSSH,
|
|
||||||
network: []string{N.NetworkTCP},
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
logger: logger,
|
||||||
dialer: outboundDialer,
|
dialer: outboundDialer,
|
||||||
serverAddr: options.ServerOptions.Build(),
|
serverAddr: options.ServerOptions.Build(),
|
||||||
user: options.User,
|
user: options.User,
|
||||||
|
@ -122,7 +120,7 @@ func randomVersion() string {
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSH) connect() (*ssh.Client, error) {
|
func (s *Outbound) connect() (*ssh.Client, error) {
|
||||||
if s.client != nil {
|
if s.client != nil {
|
||||||
return s.client, nil
|
return s.client, nil
|
||||||
}
|
}
|
||||||
|
@ -179,16 +177,16 @@ func (s *SSH) connect() (*ssh.Client, error) {
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSH) InterfaceUpdated() {
|
func (s *Outbound) InterfaceUpdated() {
|
||||||
common.Close(s.clientConn)
|
common.Close(s.clientConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSH) Close() error {
|
func (s *Outbound) Close() error {
|
||||||
return common.Close(s.clientConn)
|
return common.Close(s.clientConn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSH) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (s *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
client, err := s.connect()
|
client, err := s.connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -196,6 +194,6 @@ func (s *SSH) DialContext(ctx context.Context, network string, destination M.Soc
|
||||||
return client.Dial(network, destination.String())
|
return client.Dial(network, destination.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSH) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (s *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package tor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -8,6 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
|
@ -15,6 +16,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
|
@ -24,11 +26,14 @@ import (
|
||||||
"github.com/cretz/bine/tor"
|
"github.com/cretz/bine/tor"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*Tor)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.TorOutboundOptions](registry, C.TypeTor, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type Tor struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
logger logger.ContextLogger
|
||||||
proxy *ProxyListener
|
proxy *ProxyListener
|
||||||
startConf *tor.StartConf
|
startConf *tor.StartConf
|
||||||
options map[string]string
|
options map[string]string
|
||||||
|
@ -37,8 +42,8 @@ type Tor struct {
|
||||||
socksClient *socks.Client
|
socksClient *socks.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTor(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TorOutboundOptions) (*Tor, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TorOutboundOptions) (adapter.Outbound, error) {
|
||||||
startConf := newConfig()
|
var startConf tor.StartConf
|
||||||
startConf.DataDir = os.ExpandEnv(options.DataDirectory)
|
startConf.DataDir = os.ExpandEnv(options.DataDirectory)
|
||||||
startConf.TempDataDirBase = os.TempDir()
|
startConf.TempDataDirBase = os.TempDir()
|
||||||
startConf.ExtraArgs = options.ExtraArgs
|
startConf.ExtraArgs = options.ExtraArgs
|
||||||
|
@ -74,23 +79,17 @@ func NewTor(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Tor{
|
return &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeTor, []string{N.NetworkTCP}, tag, options.DialerOptions),
|
||||||
protocol: C.TypeTor,
|
|
||||||
network: []string{N.NetworkTCP},
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
logger: logger,
|
||||||
proxy: NewProxyListener(ctx, logger, outboundDialer),
|
proxy: NewProxyListener(ctx, logger, outboundDialer),
|
||||||
startConf: &startConf,
|
startConf: &startConf,
|
||||||
options: options.Options,
|
options: options.Options,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tor) Start() error {
|
func (t *Outbound) Start() error {
|
||||||
err := t.start()
|
err := t.start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Close()
|
t.Close()
|
||||||
|
@ -106,7 +105,7 @@ var torLogEvents = []control.EventCode{
|
||||||
control.EventCodeLogWarn,
|
control.EventCodeLogWarn,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tor) start() error {
|
func (t *Outbound) start() error {
|
||||||
torInstance, err := tor.Start(t.ctx, t.startConf)
|
torInstance, err := tor.Start(t.ctx, t.startConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.New(strings.ToLower(err.Error()))
|
return E.New(strings.ToLower(err.Error()))
|
||||||
|
@ -168,7 +167,7 @@ func (t *Tor) start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tor) recvLoop() {
|
func (t *Outbound) recvLoop() {
|
||||||
for rawEvent := range t.events {
|
for rawEvent := range t.events {
|
||||||
switch event := rawEvent.(type) {
|
switch event := rawEvent.(type) {
|
||||||
case *control.LogEvent:
|
case *control.LogEvent:
|
||||||
|
@ -191,7 +190,7 @@ func (t *Tor) recvLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tor) Close() error {
|
func (t *Outbound) Close() error {
|
||||||
err := common.Close(
|
err := common.Close(
|
||||||
common.PtrOrNil(t.proxy),
|
common.PtrOrNil(t.proxy),
|
||||||
common.PtrOrNil(t.instance),
|
common.PtrOrNil(t.instance),
|
||||||
|
@ -203,11 +202,11 @@ func (t *Tor) Close() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tor) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (t *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
t.logger.InfoContext(ctx, "outbound connection to ", destination)
|
t.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
return t.socksClient.DialContext(ctx, network, destination)
|
return t.socksClient.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tor) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (t *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
return nil, os.ErrInvalid
|
return nil, os.ErrInvalid
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package outbound
|
package tor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -7,6 +7,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/auth"
|
"github.com/sagernet/sing/common/auth"
|
||||||
|
@ -106,7 +107,7 @@ func (l *ProxyListener) NewConnection(ctx context.Context, conn net.Conn, upstre
|
||||||
metadata.Network = N.NetworkTCP
|
metadata.Network = N.NetworkTCP
|
||||||
metadata.Destination = upstreamMetadata.Destination
|
metadata.Destination = upstreamMetadata.Destination
|
||||||
l.logger.InfoContext(ctx, "proxy connection to ", metadata.Destination)
|
l.logger.InfoContext(ctx, "proxy connection to ", metadata.Destination)
|
||||||
return NewConnection(ctx, l.dialer, conn, metadata)
|
return outbound.NewConnection(ctx, l.dialer, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ProxyListener) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstreamMetadata M.Metadata) error {
|
func (l *ProxyListener) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstreamMetadata M.Metadata) error {
|
||||||
|
@ -114,5 +115,5 @@ func (l *ProxyListener) NewPacketConnection(ctx context.Context, conn N.PacketCo
|
||||||
metadata.Network = N.NetworkUDP
|
metadata.Network = N.NetworkUDP
|
||||||
metadata.Destination = upstreamMetadata.Destination
|
metadata.Destination = upstreamMetadata.Destination
|
||||||
l.logger.InfoContext(ctx, "proxy packet connection to ", metadata.Destination)
|
l.logger.InfoContext(ctx, "proxy packet connection to ", metadata.Destination)
|
||||||
return NewPacketConnection(ctx, l.dialer, conn, metadata)
|
return outbound.NewPacketConnection(ctx, l.dialer, conn, metadata)
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package outbound
|
package trojan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/mux"
|
"github.com/sagernet/sing-box/common/mux"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
|
@ -16,14 +17,18 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*Trojan)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.TrojanOutboundOptions](registry, C.TypeTrojan, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type Trojan struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
key [56]byte
|
key [56]byte
|
||||||
|
@ -32,20 +37,14 @@ type Trojan struct {
|
||||||
transport adapter.V2RayClientTransport
|
transport adapter.V2RayClientTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanOutboundOptions) (*Trojan, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &Trojan{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeTrojan, options.Network.Build(), tag, options.DialerOptions),
|
||||||
protocol: C.TypeTrojan,
|
logger: logger,
|
||||||
network: options.Network.Build(),
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
dialer: outboundDialer,
|
dialer: outboundDialer,
|
||||||
serverAddr: options.ServerOptions.Build(),
|
serverAddr: options.ServerOptions.Build(),
|
||||||
key: trojan.Key(options.Password),
|
key: trojan.Key(options.Password),
|
||||||
|
@ -69,7 +68,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Trojan) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
|
@ -89,7 +88,7 @@ func (h *Trojan) DialContext(ctx context.Context, network string, destination M.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Trojan) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
return (*trojanDialer)(h).ListenPacket(ctx, destination)
|
return (*trojanDialer)(h).ListenPacket(ctx, destination)
|
||||||
|
@ -99,7 +98,7 @@ func (h *Trojan) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Trojan) InterfaceUpdated() {
|
func (h *Outbound) InterfaceUpdated() {
|
||||||
if h.transport != nil {
|
if h.transport != nil {
|
||||||
h.transport.Close()
|
h.transport.Close()
|
||||||
}
|
}
|
||||||
|
@ -109,15 +108,15 @@ func (h *Trojan) InterfaceUpdated() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Trojan) Close() error {
|
func (h *Outbound) Close() error {
|
||||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||||
}
|
}
|
||||||
|
|
||||||
type trojanDialer Trojan
|
type trojanDialer Outbound
|
||||||
|
|
||||||
func (h *trojanDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *trojanDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
|
@ -1,6 +1,4 @@
|
||||||
//go:build with_quic
|
package tuic
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -9,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
@ -18,6 +17,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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/common/uot"
|
"github.com/sagernet/sing/common/uot"
|
||||||
|
@ -25,18 +25,20 @@ import (
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
_ adapter.Outbound = (*TUIC)(nil)
|
outbound.Register[option.TUICOutboundOptions](registry, C.TypeTUIC, NewOutbound)
|
||||||
_ adapter.InterfaceUpdateListener = (*TUIC)(nil)
|
}
|
||||||
)
|
|
||||||
|
|
||||||
type TUIC struct {
|
var _ adapter.InterfaceUpdateListener = (*Outbound)(nil)
|
||||||
myOutboundAdapter
|
|
||||||
|
type Outbound struct {
|
||||||
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
client *tuic.Client
|
client *tuic.Client
|
||||||
udpStream bool
|
udpStream bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TUICOutboundOptions) (*TUIC, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TUICOutboundOptions) (adapter.Outbound, error) {
|
||||||
options.UDPFragmentDefault = true
|
options.UDPFragmentDefault = true
|
||||||
if options.TLS == nil || !options.TLS.Enabled {
|
if options.TLS == nil || !options.TLS.Enabled {
|
||||||
return nil, C.ErrTLSRequired
|
return nil, C.ErrTLSRequired
|
||||||
|
@ -77,21 +79,15 @@ func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &TUIC{
|
return &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeTUIC, options.Network.Build(), tag, options.DialerOptions),
|
||||||
protocol: C.TypeTUIC,
|
logger: logger,
|
||||||
network: options.Network.Build(),
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
client: client,
|
client: client,
|
||||||
udpStream: options.UDPOverStream,
|
udpStream: options.UDPOverStream,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *TUIC) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
|
@ -119,7 +115,7 @@ func (h *TUIC) DialContext(ctx context.Context, network string, destination M.So
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *TUIC) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if h.udpStream {
|
if h.udpStream {
|
||||||
h.logger.InfoContext(ctx, "outbound stream packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound stream packet connection to ", destination)
|
||||||
streamConn, err := h.client.DialConn(ctx, uot.RequestDestination(uot.Version))
|
streamConn, err := h.client.DialConn(ctx, uot.RequestDestination(uot.Version))
|
||||||
|
@ -136,10 +132,10 @@ func (h *TUIC) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *TUIC) InterfaceUpdated() {
|
func (h *Outbound) InterfaceUpdated() {
|
||||||
_ = h.client.CloseWithError(E.New("network changed"))
|
_ = h.client.CloseWithError(E.New("network changed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *TUIC) Close() error {
|
func (h *Outbound) Close() error {
|
||||||
return h.client.CloseWithError(os.ErrClosed)
|
return h.client.CloseWithError(os.ErrClosed)
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package outbound
|
package vless
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/mux"
|
"github.com/sagernet/sing-box/common/mux"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
|
@ -17,14 +18,18 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*VLESS)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.VLESSOutboundOptions](registry, C.TypeVLESS, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type VLESS struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
client *vless.Client
|
client *vless.Client
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
|
@ -35,20 +40,14 @@ type VLESS struct {
|
||||||
xudp bool
|
xudp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (*VLESS, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &VLESS{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeVLESS, options.Network.Build(), tag, options.DialerOptions),
|
||||||
protocol: C.TypeVLESS,
|
logger: logger,
|
||||||
network: options.Network.Build(),
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
dialer: outboundDialer,
|
dialer: outboundDialer,
|
||||||
serverAddr: options.ServerOptions.Build(),
|
serverAddr: options.ServerOptions.Build(),
|
||||||
}
|
}
|
||||||
|
@ -88,7 +87,7 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VLESS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
|
@ -108,7 +107,7 @@ func (h *VLESS) DialContext(ctx context.Context, network string, destination M.S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VLESS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
return (*vlessDialer)(h).ListenPacket(ctx, destination)
|
return (*vlessDialer)(h).ListenPacket(ctx, destination)
|
||||||
|
@ -118,7 +117,7 @@ func (h *VLESS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VLESS) InterfaceUpdated() {
|
func (h *Outbound) InterfaceUpdated() {
|
||||||
if h.transport != nil {
|
if h.transport != nil {
|
||||||
h.transport.Close()
|
h.transport.Close()
|
||||||
}
|
}
|
||||||
|
@ -128,15 +127,15 @@ func (h *VLESS) InterfaceUpdated() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VLESS) Close() error {
|
func (h *Outbound) Close() error {
|
||||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||||
}
|
}
|
||||||
|
|
||||||
type vlessDialer VLESS
|
type vlessDialer Outbound
|
||||||
|
|
||||||
func (h *vlessDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *vlessDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
|
@ -179,7 +178,7 @@ func (h *vlessDialer) DialContext(ctx context.Context, network string, destinati
|
||||||
func (h *vlessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *vlessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
|
@ -1,10 +1,11 @@
|
||||||
package outbound
|
package vmess
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
"github.com/sagernet/sing-box/common/mux"
|
"github.com/sagernet/sing-box/common/mux"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
|
@ -16,15 +17,19 @@ import (
|
||||||
"github.com/sagernet/sing-vmess/packetaddr"
|
"github.com/sagernet/sing-vmess/packetaddr"
|
||||||
"github.com/sagernet/sing/common"
|
"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"
|
||||||
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/common/ntp"
|
"github.com/sagernet/sing/common/ntp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Outbound = (*VMess)(nil)
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
|
outbound.Register[option.VMessOutboundOptions](registry, C.TypeVMess, NewOutbound)
|
||||||
|
}
|
||||||
|
|
||||||
type VMess struct {
|
type Outbound struct {
|
||||||
myOutboundAdapter
|
outbound.Adapter
|
||||||
|
logger logger.ContextLogger
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
client *vmess.Client
|
client *vmess.Client
|
||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
|
@ -35,20 +40,14 @@ type VMess struct {
|
||||||
xudp bool
|
xudp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (*VMess, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &VMess{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeVMess, options.Network.Build(), tag, options.DialerOptions),
|
||||||
protocol: C.TypeVMess,
|
logger: logger,
|
||||||
network: options.Network.Build(),
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
dialer: outboundDialer,
|
dialer: outboundDialer,
|
||||||
serverAddr: options.ServerOptions.Build(),
|
serverAddr: options.ServerOptions.Build(),
|
||||||
}
|
}
|
||||||
|
@ -102,7 +101,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VMess) InterfaceUpdated() {
|
func (h *Outbound) InterfaceUpdated() {
|
||||||
if h.transport != nil {
|
if h.transport != nil {
|
||||||
h.transport.Close()
|
h.transport.Close()
|
||||||
}
|
}
|
||||||
|
@ -112,11 +111,11 @@ func (h *VMess) InterfaceUpdated() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VMess) Close() error {
|
func (h *Outbound) Close() error {
|
||||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
|
@ -136,7 +135,7 @@ func (h *VMess) DialContext(ctx context.Context, network string, destination M.S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VMess) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if h.multiplexDialer == nil {
|
if h.multiplexDialer == nil {
|
||||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
return (*vmessDialer)(h).ListenPacket(ctx, destination)
|
return (*vmessDialer)(h).ListenPacket(ctx, destination)
|
||||||
|
@ -146,11 +145,11 @@ func (h *VMess) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type vmessDialer VMess
|
type vmessDialer Outbound
|
||||||
|
|
||||||
func (h *vmessDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *vmessDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
|
@ -178,7 +177,7 @@ func (h *vmessDialer) DialContext(ctx context.Context, network string, destinati
|
||||||
|
|
||||||
func (h *vmessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (h *vmessDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
ctx, metadata := adapter.ExtendContext(ctx)
|
ctx, metadata := adapter.ExtendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.Tag()
|
||||||
metadata.Destination = destination
|
metadata.Destination = destination
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
10
protocol/wireguard/init.go
Normal file
10
protocol/wireguard/init.go
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package wireguard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
|
"github.com/sagernet/wireguard-go/conn"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dialer.WgControlFns = conn.ControlFns
|
||||||
|
}
|
|
@ -1,6 +1,4 @@
|
||||||
//go:build with_wireguard
|
package wireguard
|
||||||
|
|
||||||
package outbound
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -12,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
|
@ -21,6 +20,7 @@ import (
|
||||||
"github.com/sagernet/sing-tun"
|
"github.com/sagernet/sing-tun"
|
||||||
"github.com/sagernet/sing/common"
|
"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"
|
||||||
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/common/x/list"
|
"github.com/sagernet/sing/common/x/list"
|
||||||
|
@ -30,14 +30,17 @@ import (
|
||||||
"github.com/sagernet/wireguard-go/device"
|
"github.com/sagernet/wireguard-go/device"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func RegisterOutbound(registry *outbound.Registry) {
|
||||||
_ adapter.Outbound = (*WireGuard)(nil)
|
outbound.Register[option.WireGuardOutboundOptions](registry, C.TypeWireGuard, NewOutbound)
|
||||||
_ adapter.InterfaceUpdateListener = (*WireGuard)(nil)
|
}
|
||||||
)
|
|
||||||
|
|
||||||
type WireGuard struct {
|
var _ adapter.InterfaceUpdateListener = (*Outbound)(nil)
|
||||||
myOutboundAdapter
|
|
||||||
|
type Outbound struct {
|
||||||
|
outbound.Adapter
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
router adapter.Router
|
||||||
|
logger logger.ContextLogger
|
||||||
workers int
|
workers int
|
||||||
peers []wireguard.PeerConfig
|
peers []wireguard.PeerConfig
|
||||||
useStdNetBind bool
|
useStdNetBind bool
|
||||||
|
@ -51,17 +54,12 @@ type WireGuard struct {
|
||||||
tunDevice wireguard.Device
|
tunDevice wireguard.Device
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWireGuard(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardOutboundOptions) (*WireGuard, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardOutboundOptions) (adapter.Outbound, error) {
|
||||||
outbound := &WireGuard{
|
outbound := &Outbound{
|
||||||
myOutboundAdapter: myOutboundAdapter{
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeWireGuard, options.Network.Build(), tag, options.DialerOptions),
|
||||||
protocol: C.TypeWireGuard,
|
|
||||||
network: options.Network.Build(),
|
|
||||||
router: router,
|
|
||||||
logger: logger,
|
|
||||||
tag: tag,
|
|
||||||
dependencies: withDialerDependency(options.DialerOptions),
|
|
||||||
},
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
router: router,
|
||||||
|
logger: logger,
|
||||||
workers: options.Workers,
|
workers: options.Workers,
|
||||||
pauseManager: service.FromContext[pause.Manager](ctx),
|
pauseManager: service.FromContext[pause.Manager](ctx),
|
||||||
}
|
}
|
||||||
|
@ -111,7 +109,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context
|
||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) Start() error {
|
func (w *Outbound) Start() error {
|
||||||
if common.Any(w.peers, func(peer wireguard.PeerConfig) bool {
|
if common.Any(w.peers, func(peer wireguard.PeerConfig) bool {
|
||||||
return !peer.Endpoint.IsValid()
|
return !peer.Endpoint.IsValid()
|
||||||
}) {
|
}) {
|
||||||
|
@ -121,7 +119,7 @@ func (w *WireGuard) Start() error {
|
||||||
return w.start()
|
return w.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) PostStart() error {
|
func (w *Outbound) PostStart() error {
|
||||||
if common.All(w.peers, func(peer wireguard.PeerConfig) bool {
|
if common.All(w.peers, func(peer wireguard.PeerConfig) bool {
|
||||||
return peer.Endpoint.IsValid()
|
return peer.Endpoint.IsValid()
|
||||||
}) {
|
}) {
|
||||||
|
@ -130,7 +128,7 @@ func (w *WireGuard) PostStart() error {
|
||||||
return w.start()
|
return w.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) start() error {
|
func (w *Outbound) start() error {
|
||||||
err := wireguard.ResolvePeers(w.ctx, w.router, w.peers)
|
err := wireguard.ResolvePeers(w.ctx, w.router, w.peers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -150,7 +148,7 @@ func (w *WireGuard) start() error {
|
||||||
connectAddr = w.peers[0].Endpoint
|
connectAddr = w.peers[0].Endpoint
|
||||||
reserved = w.peers[0].Reserved
|
reserved = w.peers[0].Reserved
|
||||||
}
|
}
|
||||||
bind = wireguard.NewClientBind(w.ctx, w, w.listener, isConnect, connectAddr, reserved)
|
bind = wireguard.NewClientBind(w.ctx, w.logger, w.listener, isConnect, connectAddr, reserved)
|
||||||
}
|
}
|
||||||
err = w.tunDevice.Start()
|
err = w.tunDevice.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -177,7 +175,7 @@ func (w *WireGuard) start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) Close() error {
|
func (w *Outbound) Close() error {
|
||||||
if w.device != nil {
|
if w.device != nil {
|
||||||
w.device.Close()
|
w.device.Close()
|
||||||
}
|
}
|
||||||
|
@ -187,12 +185,12 @@ func (w *WireGuard) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) InterfaceUpdated() {
|
func (w *Outbound) InterfaceUpdated() {
|
||||||
w.device.BindUpdate()
|
w.device.BindUpdate()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) onPauseUpdated(event int) {
|
func (w *Outbound) onPauseUpdated(event int) {
|
||||||
switch event {
|
switch event {
|
||||||
case pause.EventDevicePaused:
|
case pause.EventDevicePaused:
|
||||||
w.device.Down()
|
w.device.Down()
|
||||||
|
@ -201,7 +199,7 @@ func (w *WireGuard) onPauseUpdated(event int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (w *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
switch network {
|
switch network {
|
||||||
case N.NetworkTCP:
|
case N.NetworkTCP:
|
||||||
w.logger.InfoContext(ctx, "outbound connection to ", destination)
|
w.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||||
|
@ -218,7 +216,7 @@ func (w *WireGuard) DialContext(ctx context.Context, network string, destination
|
||||||
return w.tunDevice.DialContext(ctx, network, destination)
|
return w.tunDevice.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (w *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||||
if destination.IsFqdn() {
|
if destination.IsFqdn() {
|
||||||
destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn)
|
destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn)
|
||||||
|
@ -236,12 +234,12 @@ func (w *WireGuard) ListenPacket(ctx context.Context, destination M.Socksaddr) (
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func (w *WireGuard) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (w *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
return NewDirectConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS)
|
return outbound.NewDirectConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// Deprecated
|
// Deprecated
|
||||||
func (w *WireGuard) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (w *Outbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
return NewDirectPacketConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS)
|
return outbound.NewDirectPacketConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS)
|
||||||
}
|
}
|
|
@ -7,7 +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"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
dnsOutbound "github.com/sagernet/sing-box/protocol/dns"
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
@ -22,7 +22,7 @@ func (r *Router) hijackDNSStream(ctx context.Context, conn net.Conn, metadata ad
|
||||||
metadata.Destination = M.Socksaddr{}
|
metadata.Destination = M.Socksaddr{}
|
||||||
for {
|
for {
|
||||||
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
|
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
|
||||||
err := outbound.HandleStreamDNSRequest(ctx, r, conn, metadata)
|
err := dnsOutbound.HandleStreamDNSRequest(ctx, r, conn, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetB
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := outbound.NewDNSPacketConnection(ctx, r, conn, packetBuffers, metadata)
|
err := dnsOutbound.NewDNSPacketConnection(ctx, r, conn, packetBuffers, metadata)
|
||||||
if err != nil && !E.IsClosedOrCanceled(err) {
|
if err != nil && !E.IsClosedOrCanceled(err) {
|
||||||
r.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection"))
|
r.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/adapter/outbound"
|
||||||
"github.com/sagernet/sing-box/common/conntrack"
|
"github.com/sagernet/sing-box/common/conntrack"
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
"github.com/sagernet/sing-box/common/sniff"
|
"github.com/sagernet/sing-box/common/sniff"
|
||||||
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-box/outbound"
|
|
||||||
"github.com/sagernet/sing-box/route/rule"
|
"github.com/sagernet/sing-box/route/rule"
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
"github.com/sagernet/sing-mux"
|
"github.com/sagernet/sing-mux"
|
||||||
|
|
|
@ -46,7 +46,7 @@ func TestBrutalShadowsocks(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -138,7 +138,7 @@ func TestBrutalTrojan(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -227,7 +227,7 @@ func TestBrutalVMess(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -326,7 +326,7 @@ func TestBrutalVLESS(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,7 +33,7 @@ func _TestProxyProtocol(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -49,7 +49,7 @@ func TestTUICDomainUDP(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestECH(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -145,7 +145,7 @@ func TestECHQUIC(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -235,7 +235,7 @@ func TestECHHysteria2(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,7 +31,7 @@ func TestHTTPSelf(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -63,7 +63,7 @@ func testHysteria2Self(t *testing.T, salamanderPassword string) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -178,7 +178,7 @@ func TestHysteria2Outbound(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeHysteria2,
|
Type: C.TypeHysteria2,
|
||||||
Hysteria2Options: option.Hysteria2OutboundOptions{
|
Hysteria2Options: option.Hysteria2OutboundOptions{
|
||||||
|
|
|
@ -46,7 +46,7 @@ func TestHysteriaSelf(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -160,7 +160,7 @@ func TestHysteriaOutbound(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeHysteria,
|
Type: C.TypeHysteria,
|
||||||
HysteriaOptions: option.HysteriaOutboundOptions{
|
HysteriaOptions: option.HysteriaOutboundOptions{
|
||||||
|
|
|
@ -49,7 +49,7 @@ func TestChainedInbound(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -92,7 +92,7 @@ func TestMuxCoolClient(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeVMess,
|
Type: C.TypeVMess,
|
||||||
VMessOptions: option.VMessOutboundOptions{
|
VMessOptions: option.VMessOutboundOptions{
|
||||||
|
@ -139,7 +139,7 @@ func TestMuxCoolSelf(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -81,7 +81,7 @@ func testShadowsocksMux(t *testing.T, options option.OutboundMultiplexOptions) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -154,7 +154,7 @@ func testVMessMux(t *testing.T, options option.OutboundMultiplexOptions) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,7 +35,7 @@ func testShadowsocksLegacy(t *testing.T, method string) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeShadowsocks,
|
Type: C.TypeShadowsocks,
|
||||||
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
||||||
|
|
|
@ -135,7 +135,7 @@ func testShadowsocksOutboundWithShadowsocksRust(t *testing.T, method string, pas
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeShadowsocks,
|
Type: C.TypeShadowsocks,
|
||||||
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
||||||
|
@ -177,7 +177,7 @@ func testShadowsocksSelf(t *testing.T, method string, password string) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -244,7 +244,7 @@ func TestShadowsocksUoT(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -317,7 +317,7 @@ func testShadowsocks2022EIH(t *testing.T, method string, password string) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -80,7 +80,7 @@ func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeShadowsocks,
|
Type: C.TypeShadowsocks,
|
||||||
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
||||||
|
@ -232,7 +232,7 @@ func TestShadowTLSInbound(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -306,7 +306,7 @@ func TestShadowTLSOutbound(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeShadowsocks,
|
Type: C.TypeShadowsocks,
|
||||||
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
||||||
|
|
|
@ -44,7 +44,7 @@ func testShadowsocksPlugin(t *testing.T, name string, opts string, args string)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeShadowsocks,
|
Type: C.TypeShadowsocks,
|
||||||
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
||||||
|
|
|
@ -37,7 +37,7 @@ func TestTCPSlowOpen(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,7 +46,7 @@ func TestUTLS(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,7 +31,7 @@ func TestTrojanOutbound(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeTrojan,
|
Type: C.TypeTrojan,
|
||||||
TrojanOptions: option.TrojanOutboundOptions{
|
TrojanOptions: option.TrojanOutboundOptions{
|
||||||
|
@ -92,7 +92,7 @@ func TestTrojanSelf(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -167,7 +167,7 @@ func TestTrojanPlainSelf(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -62,7 +62,7 @@ func testTUICSelf(t *testing.T, udpStream bool, zeroRTTHandshake bool) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -171,7 +171,7 @@ func TestTUICOutbound(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeTUIC,
|
Type: C.TypeTUIC,
|
||||||
TUICOptions: option.TUICOutboundOptions{
|
TUICOptions: option.TUICOutboundOptions{
|
||||||
|
|
|
@ -26,7 +26,7 @@ func TestV2RayAPI(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
Tag: "out",
|
Tag: "out",
|
||||||
|
|
|
@ -138,7 +138,7 @@ func testV2RayGRPCOutbound(t *testing.T, forceLite bool) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeVMess,
|
Type: C.TypeVMess,
|
||||||
Tag: "vmess-out",
|
Tag: "vmess-out",
|
||||||
|
|
|
@ -80,7 +80,7 @@ func testVMessTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -169,7 +169,7 @@ func testTrojanTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -260,7 +260,7 @@ func TestVMessQUICSelf(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
@ -340,7 +340,7 @@ func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportO
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -170,7 +170,7 @@ func testV2RayWebsocketOutbound(t *testing.T, maxEarlyData uint32, earlyDataHead
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeVMess,
|
Type: C.TypeVMess,
|
||||||
Tag: "vmess-out",
|
Tag: "vmess-out",
|
||||||
|
|
|
@ -240,7 +240,7 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, globalPadding boo
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeVMess,
|
Type: C.TypeVMess,
|
||||||
VMessOptions: option.VMessOutboundOptions{
|
VMessOptions: option.VMessOutboundOptions{
|
||||||
|
@ -291,7 +291,7 @@ func testVMessSelf(t *testing.T, security string, alterId int, globalPadding boo
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeDirect,
|
Type: C.TypeDirect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,7 @@ func _TestWireGuard(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Outbounds: []option.Outbound{
|
LegacyOutbounds: []option.LegacyOutbound{
|
||||||
{
|
{
|
||||||
Type: C.TypeWireGuard,
|
Type: C.TypeWireGuard,
|
||||||
WireGuardOptions: option.WireGuardOutboundOptions{
|
WireGuardOptions: option.WireGuardOutboundOptions{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
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/service"
|
"github.com/sagernet/sing/service"
|
||||||
|
@ -21,10 +22,10 @@ var _ conn.Bind = (*ClientBind)(nil)
|
||||||
|
|
||||||
type ClientBind struct {
|
type ClientBind struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
logger logger.Logger
|
||||||
pauseManager pause.Manager
|
pauseManager pause.Manager
|
||||||
bindCtx context.Context
|
bindCtx context.Context
|
||||||
bindDone context.CancelFunc
|
bindDone context.CancelFunc
|
||||||
errorHandler E.Handler
|
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
reservedForEndpoint map[netip.AddrPort][3]uint8
|
reservedForEndpoint map[netip.AddrPort][3]uint8
|
||||||
connAccess sync.Mutex
|
connAccess sync.Mutex
|
||||||
|
@ -35,11 +36,11 @@ type ClientBind struct {
|
||||||
reserved [3]uint8
|
reserved [3]uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientBind(ctx context.Context, errorHandler E.Handler, dialer N.Dialer, isConnect bool, connectAddr netip.AddrPort, reserved [3]uint8) *ClientBind {
|
func NewClientBind(ctx context.Context, logger logger.Logger, dialer N.Dialer, isConnect bool, connectAddr netip.AddrPort, reserved [3]uint8) *ClientBind {
|
||||||
return &ClientBind{
|
return &ClientBind{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
|
logger: logger,
|
||||||
pauseManager: service.FromContext[pause.Manager](ctx),
|
pauseManager: service.FromContext[pause.Manager](ctx),
|
||||||
errorHandler: errorHandler,
|
|
||||||
dialer: dialer,
|
dialer: dialer,
|
||||||
reservedForEndpoint: make(map[netip.AddrPort][3]uint8),
|
reservedForEndpoint: make(map[netip.AddrPort][3]uint8),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
|
@ -115,7 +116,7 @@ func (c *ClientBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
c.errorHandler.NewError(context.Background(), E.Cause(err, "connect to server"))
|
c.logger.Error(E.Cause(err, "connect to server"))
|
||||||
err = nil
|
err = nil
|
||||||
c.pauseManager.WaitActive()
|
c.pauseManager.WaitActive()
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
@ -127,7 +128,7 @@ func (c *ClientBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint)
|
||||||
select {
|
select {
|
||||||
case <-c.done:
|
case <-c.done:
|
||||||
default:
|
default:
|
||||||
c.errorHandler.NewError(context.Background(), E.Cause(err, "read packet"))
|
c.logger.Error(context.Background(), E.Cause(err, "read packet"))
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue