2022-07-02 14:07:50 +08:00
|
|
|
package option
|
2022-06-30 21:27:56 +08:00
|
|
|
|
|
|
|
import (
|
2024-11-02 00:39:02 +08:00
|
|
|
"context"
|
|
|
|
|
2024-11-07 12:02:36 +08:00
|
|
|
C "github.com/sagernet/sing-box/constant"
|
|
|
|
"github.com/sagernet/sing-box/experimental/deprecated"
|
2022-06-30 21:27:56 +08:00
|
|
|
E "github.com/sagernet/sing/common/exceptions"
|
2023-12-01 20:15:11 +08:00
|
|
|
"github.com/sagernet/sing/common/json"
|
2024-11-02 00:39:02 +08:00
|
|
|
"github.com/sagernet/sing/common/json/badjson"
|
2024-11-07 21:44:04 +08:00
|
|
|
"github.com/sagernet/sing/common/json/badoption"
|
2022-07-02 14:07:50 +08:00
|
|
|
M "github.com/sagernet/sing/common/metadata"
|
2024-11-02 00:39:02 +08:00
|
|
|
"github.com/sagernet/sing/service"
|
2022-06-30 21:27:56 +08:00
|
|
|
)
|
|
|
|
|
2024-11-02 00:39:02 +08:00
|
|
|
type OutboundOptionsRegistry interface {
|
|
|
|
CreateOptions(outboundType string) (any, bool)
|
|
|
|
}
|
|
|
|
|
2022-06-30 21:27:56 +08:00
|
|
|
type _Outbound struct {
|
2024-11-02 00:39:02 +08:00
|
|
|
Type string `json:"type"`
|
|
|
|
Tag string `json:"tag,omitempty"`
|
|
|
|
Options any `json:"-"`
|
2022-06-30 21:27:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type Outbound _Outbound
|
|
|
|
|
2024-11-02 00:39:02 +08:00
|
|
|
func (h *Outbound) MarshalJSONContext(ctx context.Context) ([]byte, error) {
|
|
|
|
return badjson.MarshallObjectsContext(ctx, (*_Outbound)(h), h.Options)
|
2023-12-11 18:36:06 +08:00
|
|
|
}
|
|
|
|
|
2024-11-02 00:39:02 +08:00
|
|
|
func (h *Outbound) UnmarshalJSONContext(ctx context.Context, content []byte) error {
|
|
|
|
err := json.Unmarshal(content, (*_Outbound)(h))
|
2022-07-03 01:57:04 +08:00
|
|
|
if err != nil {
|
2022-06-30 21:27:56 +08:00
|
|
|
return err
|
|
|
|
}
|
2024-11-02 00:39:02 +08:00
|
|
|
registry := service.FromContext[OutboundOptionsRegistry](ctx)
|
|
|
|
if registry == nil {
|
|
|
|
return E.New("missing outbound options registry in context")
|
|
|
|
}
|
2024-11-07 12:02:36 +08:00
|
|
|
switch h.Type {
|
|
|
|
case C.TypeBlock, C.TypeDNS:
|
|
|
|
deprecated.Report(ctx, deprecated.OptionSpecialOutbounds)
|
|
|
|
}
|
2024-11-02 00:39:02 +08:00
|
|
|
options, loaded := registry.CreateOptions(h.Type)
|
|
|
|
if !loaded {
|
|
|
|
return E.New("unknown outbound type: ", h.Type)
|
2022-06-30 21:27:56 +08:00
|
|
|
}
|
2024-11-02 00:39:02 +08:00
|
|
|
err = badjson.UnmarshallExcludedContext(ctx, content, (*_Outbound)(h), options)
|
2022-07-03 11:28:15 +08:00
|
|
|
if err != nil {
|
2023-12-01 20:15:11 +08:00
|
|
|
return err
|
2022-07-03 11:28:15 +08:00
|
|
|
}
|
2024-11-07 12:02:36 +08:00
|
|
|
if listenWrapper, isListen := options.(ListenOptionsWrapper); isListen {
|
|
|
|
if listenWrapper.TakeListenOptions().InboundOptions != (InboundOptions{}) {
|
|
|
|
deprecated.Report(ctx, deprecated.OptionInboundOptions)
|
|
|
|
}
|
|
|
|
}
|
2024-11-02 00:39:02 +08:00
|
|
|
h.Options = options
|
2022-07-03 11:28:15 +08:00
|
|
|
return nil
|
2022-06-30 21:27:56 +08:00
|
|
|
}
|
|
|
|
|
2023-12-11 18:36:06 +08:00
|
|
|
type DialerOptionsWrapper interface {
|
|
|
|
TakeDialerOptions() DialerOptions
|
|
|
|
ReplaceDialerOptions(options DialerOptions)
|
|
|
|
}
|
|
|
|
|
2022-06-30 21:27:56 +08:00
|
|
|
type DialerOptions struct {
|
2024-11-12 19:37:10 +08:00
|
|
|
Detour string `json:"detour,omitempty"`
|
|
|
|
BindInterface string `json:"bind_interface,omitempty"`
|
|
|
|
Inet4BindAddress *badoption.Addr `json:"inet4_bind_address,omitempty"`
|
|
|
|
Inet6BindAddress *badoption.Addr `json:"inet6_bind_address,omitempty"`
|
|
|
|
ProtectPath string `json:"protect_path,omitempty"`
|
|
|
|
RoutingMark uint32 `json:"routing_mark,omitempty"`
|
|
|
|
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
|
|
|
ConnectTimeout badoption.Duration `json:"connect_timeout,omitempty"`
|
|
|
|
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
|
|
|
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
|
|
|
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
|
|
|
UDPFragmentDefault bool `json:"-"`
|
|
|
|
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
|
|
|
NetworkStrategy NetworkStrategy `json:"network_strategy,omitempty"`
|
|
|
|
FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"`
|
|
|
|
NetworkFallbackDelay badoption.Duration `json:"network_fallback_delay,omitempty"`
|
|
|
|
IsWireGuardListener bool `json:"-"`
|
2022-06-30 21:27:56 +08:00
|
|
|
}
|
|
|
|
|
2023-12-11 18:36:06 +08:00
|
|
|
func (o *DialerOptions) TakeDialerOptions() DialerOptions {
|
|
|
|
return *o
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *DialerOptions) ReplaceDialerOptions(options DialerOptions) {
|
|
|
|
*o = options
|
|
|
|
}
|
|
|
|
|
|
|
|
type ServerOptionsWrapper interface {
|
|
|
|
TakeServerOptions() ServerOptions
|
|
|
|
ReplaceServerOptions(options ServerOptions)
|
|
|
|
}
|
|
|
|
|
2022-07-02 14:07:50 +08:00
|
|
|
type ServerOptions struct {
|
2022-06-30 21:27:56 +08:00
|
|
|
Server string `json:"server"`
|
|
|
|
ServerPort uint16 `json:"server_port"`
|
2022-07-02 14:07:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o ServerOptions) Build() M.Socksaddr {
|
|
|
|
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
|
|
|
|
}
|
2023-12-11 18:36:06 +08:00
|
|
|
|
|
|
|
func (o *ServerOptions) TakeServerOptions() ServerOptions {
|
|
|
|
return *o
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *ServerOptions) ReplaceServerOptions(options ServerOptions) {
|
|
|
|
*o = options
|
|
|
|
}
|