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"
2023-12-20 19:55:14 +08:00
"time"
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-18 18:55:34 +08:00
"github.com/sagernet/sing/common/json/badoption"
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 InboundOptionsRegistry interface {
CreateOptions ( outboundType string ) ( any , bool )
}
2022-06-30 21:27:56 +08:00
type _Inbound 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 Inbound _Inbound
2024-11-02 00:39:02 +08:00
func ( h * Inbound ) MarshalJSONContext ( ctx context . Context ) ([] byte , error ) {
return badjson . MarshallObjectsContext ( ctx , ( * _Inbound )( h ), h . Options )
2023-12-11 18:36:06 +08:00
}
2024-11-02 00:39:02 +08:00
func ( h * Inbound ) UnmarshalJSONContext ( ctx context . Context , content [] byte ) error {
2024-11-21 18:10:41 +08:00
err := json . UnmarshalContext ( ctx , content , ( * _Inbound )( h ))
2022-06-30 21:27:56 +08:00
if err != nil {
return err
}
2024-11-02 00:39:02 +08:00
registry := service . FromContext [ InboundOptionsRegistry ]( ctx )
if registry == nil {
2025-03-29 17:24:34 +08:00
return E . New ( "missing inbound fields registry in context" )
2022-06-30 21:27:56 +08:00
}
2024-11-02 00:39:02 +08:00
options , loaded := registry . CreateOptions ( h . Type )
if ! loaded {
return E . New ( "unknown inbound type: " , h . Type )
}
err = badjson . UnmarshallExcludedContext ( ctx , content , ( * _Inbound )( 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
}
2026-03-21 17:09:34 +08:00
if listenWrapper , isListen := options .( ListenOptionsWrapper ); isListen {
//nolint:staticcheck
if listenWrapper . TakeListenOptions (). InboundOptions != ( InboundOptions {}) {
return E . New ( "legacy inbound fields are deprecated in sing-box 1.11.0 and removed in sing-box 1.13.0, checkout migration: https://sing-box.sagernet.org/migration/#migrate-legacy-inbound-fields-to-rule-actions" )
}
}
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
}
2024-10-21 23:38:34 +08:00
// Deprecated: Use rule action instead
2022-07-10 08:18:52 +08:00
type InboundOptions struct {
2024-11-18 18:55:34 +08:00
SniffEnabled bool `json:"sniff,omitempty"`
SniffOverrideDestination bool `json:"sniff_override_destination,omitempty"`
SniffTimeout badoption . Duration `json:"sniff_timeout,omitempty"`
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"`
2022-06-30 21:27:56 +08:00
}
2022-07-10 08:18:52 +08:00
type ListenOptions struct {
2024-11-18 18:55:34 +08:00
Listen * badoption . Addr `json:"listen,omitempty"`
ListenPort uint16 `json:"listen_port,omitempty"`
2025-05-05 08:50:22 +08:00
BindInterface string `json:"bind_interface,omitempty"`
RoutingMark FwMark `json:"routing_mark,omitempty"`
ReuseAddr bool `json:"reuse_addr,omitempty"`
NetNs string `json:"netns,omitempty"`
2025-12-06 11:23:01 +08:00
DisableTCPKeepAlive bool `json:"disable_tcp_keep_alive,omitempty"`
2024-11-18 18:55:34 +08:00
TCPKeepAlive badoption . Duration `json:"tcp_keep_alive,omitempty"`
TCPKeepAliveInterval badoption . Duration `json:"tcp_keep_alive_interval,omitempty"`
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
UDPFragment * bool `json:"udp_fragment,omitempty"`
UDPFragmentDefault bool `json:"-"`
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
2026-02-28 17:55:56 +08:00
Detour string `json:"detour,omitempty"`
2024-11-02 00:39:02 +08:00
// Deprecated: removed
ProxyProtocol bool `json:"proxy_protocol,omitempty"`
// Deprecated: removed
ProxyProtocolAcceptNoHeader bool `json:"proxy_protocol_accept_no_header,omitempty"`
2022-07-10 08:18:52 +08:00
InboundOptions
}
2023-12-20 19:55:14 +08:00
2024-11-18 18:55:34 +08:00
type UDPTimeoutCompat badoption . Duration
2023-12-20 19:55:14 +08:00
2023-12-26 10:51:39 +08:00
func ( c UDPTimeoutCompat ) MarshalJSON () ([] byte , error ) {
return json . Marshal (( time . Duration )( c ). String ())
}
func ( c * UDPTimeoutCompat ) UnmarshalJSON ( data [] byte ) error {
2023-12-20 19:55:14 +08:00
var valueNumber int64
err := json . Unmarshal ( data , & valueNumber )
if err == nil {
2023-12-26 10:51:39 +08:00
* c = UDPTimeoutCompat ( time . Second * time . Duration ( valueNumber ))
2023-12-20 19:55:14 +08:00
return nil
}
2024-11-18 18:55:34 +08:00
return json . Unmarshal ( data , ( * badoption . Duration )( c ))
2023-12-20 19:55:14 +08:00
}
2023-12-11 18:36:06 +08:00
type ListenOptionsWrapper interface {
TakeListenOptions () ListenOptions
ReplaceListenOptions ( options ListenOptions )
}
func ( o * ListenOptions ) TakeListenOptions () ListenOptions {
return * o
}
func ( o * ListenOptions ) ReplaceListenOptions ( options ListenOptions ) {
* o = options
}