123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- package option
- import (
- "context"
- "fmt"
- "net/netip"
- "time"
- 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"
- "github.com/sagernet/sing/common/json/badoption"
- )
- type _RuleAction struct {
- Action string `json:"action,omitempty"`
- RouteOptions RouteActionOptions `json:"-"`
- RouteOptionsOptions RouteOptionsActionOptions `json:"-"`
- DirectOptions DirectActionOptions `json:"-"`
- RejectOptions RejectActionOptions `json:"-"`
- SniffOptions RouteActionSniff `json:"-"`
- ResolveOptions RouteActionResolve `json:"-"`
- }
- type RuleAction _RuleAction
- func (r RuleAction) MarshalJSON() ([]byte, error) {
- if r.Action == "" {
- return json.Marshal(struct{}{})
- }
- var v any
- switch r.Action {
- case C.RuleActionTypeRoute:
- r.Action = ""
- v = r.RouteOptions
- case C.RuleActionTypeRouteOptions:
- v = r.RouteOptionsOptions
- case C.RuleActionTypeDirect:
- v = r.DirectOptions
- case C.RuleActionTypeReject:
- v = r.RejectOptions
- case C.RuleActionTypeHijackDNS:
- v = nil
- case C.RuleActionTypeSniff:
- v = r.SniffOptions
- case C.RuleActionTypeResolve:
- v = r.ResolveOptions
- default:
- return nil, E.New("unknown rule action: " + r.Action)
- }
- if v == nil {
- return badjson.MarshallObjects((_RuleAction)(r))
- }
- return badjson.MarshallObjects((_RuleAction)(r), v)
- }
- func (r *RuleAction) UnmarshalJSON(data []byte) error {
- err := json.Unmarshal(data, (*_RuleAction)(r))
- if err != nil {
- return err
- }
- var v any
- switch r.Action {
- case "", C.RuleActionTypeRoute:
- r.Action = C.RuleActionTypeRoute
- v = &r.RouteOptions
- case C.RuleActionTypeRouteOptions:
- v = &r.RouteOptionsOptions
- case C.RuleActionTypeDirect:
- v = &r.DirectOptions
- case C.RuleActionTypeReject:
- v = &r.RejectOptions
- case C.RuleActionTypeHijackDNS:
- v = nil
- case C.RuleActionTypeSniff:
- v = &r.SniffOptions
- case C.RuleActionTypeResolve:
- v = &r.ResolveOptions
- default:
- return E.New("unknown rule action: " + r.Action)
- }
- if v == nil {
- // check unknown fields
- return json.UnmarshalDisallowUnknownFields(data, &_RuleAction{})
- }
- return badjson.UnmarshallExcluded(data, (*_RuleAction)(r), v)
- }
- type _DNSRuleAction struct {
- Action string `json:"action,omitempty"`
- RouteOptions DNSRouteActionOptions `json:"-"`
- RouteOptionsOptions DNSRouteOptionsActionOptions `json:"-"`
- RejectOptions RejectActionOptions `json:"-"`
- PredefinedOptions DNSRouteActionPredefined `json:"-"`
- }
- type DNSRuleAction _DNSRuleAction
- func (r DNSRuleAction) MarshalJSON() ([]byte, error) {
- if r.Action == "" {
- return json.Marshal(struct{}{})
- }
- var v any
- switch r.Action {
- case C.RuleActionTypeRoute:
- r.Action = ""
- v = r.RouteOptions
- case C.RuleActionTypeRouteOptions:
- v = r.RouteOptionsOptions
- case C.RuleActionTypeReject:
- v = r.RejectOptions
- case C.RuleActionTypePredefined:
- v = r.PredefinedOptions
- default:
- return nil, E.New("unknown DNS rule action: " + r.Action)
- }
- return badjson.MarshallObjects((_DNSRuleAction)(r), v)
- }
- func (r *DNSRuleAction) UnmarshalJSONContext(ctx context.Context, data []byte) error {
- err := json.Unmarshal(data, (*_DNSRuleAction)(r))
- if err != nil {
- return err
- }
- var v any
- switch r.Action {
- case "", C.RuleActionTypeRoute:
- r.Action = C.RuleActionTypeRoute
- v = &r.RouteOptions
- case C.RuleActionTypeRouteOptions:
- v = &r.RouteOptionsOptions
- case C.RuleActionTypeReject:
- v = &r.RejectOptions
- case C.RuleActionTypePredefined:
- v = &r.PredefinedOptions
- default:
- return E.New("unknown DNS rule action: " + r.Action)
- }
- return badjson.UnmarshallExcludedContext(ctx, data, (*_DNSRuleAction)(r), v)
- }
- type RouteActionOptions struct {
- Outbound string `json:"outbound,omitempty"`
- RawRouteOptionsActionOptions
- }
- type RawRouteOptionsActionOptions struct {
- OverrideAddress string `json:"override_address,omitempty"`
- OverridePort uint16 `json:"override_port,omitempty"`
- NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
- FallbackDelay uint32 `json:"fallback_delay,omitempty"`
- UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"`
- UDPConnect bool `json:"udp_connect,omitempty"`
- UDPTimeout badoption.Duration `json:"udp_timeout,omitempty"`
- TLSFragment bool `json:"tls_fragment,omitempty"`
- TLSFragmentFallbackDelay badoption.Duration `json:"tls_fragment_fallback_delay,omitempty"`
- TLSRecordFragment bool `json:"tls_record_fragment,omitempty"`
- }
- type RouteOptionsActionOptions RawRouteOptionsActionOptions
- func (r *RouteOptionsActionOptions) UnmarshalJSON(data []byte) error {
- err := json.Unmarshal(data, (*RawRouteOptionsActionOptions)(r))
- if err != nil {
- return err
- }
- if *r == (RouteOptionsActionOptions{}) {
- return E.New("empty route option action")
- }
- if r.TLSFragment && r.TLSRecordFragment {
- return E.New("`tls_fragment` and `tls_record_fragment` are mutually exclusive")
- }
- return nil
- }
- type DNSRouteActionOptions struct {
- Server string `json:"server,omitempty"`
- Strategy DomainStrategy `json:"strategy,omitempty"`
- DisableCache bool `json:"disable_cache,omitempty"`
- RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
- ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
- }
- type _DNSRouteOptionsActionOptions struct {
- Strategy DomainStrategy `json:"strategy,omitempty"`
- DisableCache bool `json:"disable_cache,omitempty"`
- RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
- ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
- }
- type DNSRouteOptionsActionOptions _DNSRouteOptionsActionOptions
- func (r *DNSRouteOptionsActionOptions) UnmarshalJSON(data []byte) error {
- err := json.Unmarshal(data, (*_DNSRouteOptionsActionOptions)(r))
- if err != nil {
- return err
- }
- if *r == (DNSRouteOptionsActionOptions{}) {
- return E.New("empty DNS route option action")
- }
- return nil
- }
- type _DirectActionOptions DialerOptions
- type DirectActionOptions _DirectActionOptions
- func (d DirectActionOptions) Descriptions() []string {
- var descriptions []string
- if d.BindInterface != "" {
- descriptions = append(descriptions, "bind_interface="+d.BindInterface)
- }
- if d.Inet4BindAddress != nil {
- descriptions = append(descriptions, "inet4_bind_address="+d.Inet4BindAddress.Build(netip.IPv4Unspecified()).String())
- }
- if d.Inet6BindAddress != nil {
- descriptions = append(descriptions, "inet6_bind_address="+d.Inet6BindAddress.Build(netip.IPv6Unspecified()).String())
- }
- if d.RoutingMark != 0 {
- descriptions = append(descriptions, "routing_mark="+fmt.Sprintf("0x%x", d.RoutingMark))
- }
- if d.ReuseAddr {
- descriptions = append(descriptions, "reuse_addr")
- }
- if d.ConnectTimeout != 0 {
- descriptions = append(descriptions, "connect_timeout="+time.Duration(d.ConnectTimeout).String())
- }
- if d.TCPFastOpen {
- descriptions = append(descriptions, "tcp_fast_open")
- }
- if d.TCPMultiPath {
- descriptions = append(descriptions, "tcp_multi_path")
- }
- if d.UDPFragment != nil {
- descriptions = append(descriptions, "udp_fragment="+fmt.Sprint(*d.UDPFragment))
- }
- if d.DomainStrategy != DomainStrategy(C.DomainStrategyAsIS) {
- descriptions = append(descriptions, "domain_strategy="+d.DomainStrategy.String())
- }
- if d.FallbackDelay != 0 {
- descriptions = append(descriptions, "fallback_delay="+time.Duration(d.FallbackDelay).String())
- }
- return descriptions
- }
- func (d *DirectActionOptions) UnmarshalJSON(data []byte) error {
- err := json.Unmarshal(data, (*_DirectActionOptions)(d))
- if err != nil {
- return err
- }
- if d.Detour != "" {
- return E.New("detour is not available in the current context")
- }
- return nil
- }
- type _RejectActionOptions struct {
- Method string `json:"method,omitempty"`
- NoDrop bool `json:"no_drop,omitempty"`
- }
- type RejectActionOptions _RejectActionOptions
- func (r RejectActionOptions) MarshalJSON() ([]byte, error) {
- switch r.Method {
- case C.RuleActionRejectMethodDefault:
- r.Method = ""
- }
- return json.Marshal((_RejectActionOptions)(r))
- }
- func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error {
- err := json.Unmarshal(bytes, (*_RejectActionOptions)(r))
- if err != nil {
- return err
- }
- switch r.Method {
- case "", C.RuleActionRejectMethodDefault:
- r.Method = C.RuleActionRejectMethodDefault
- case C.RuleActionRejectMethodDrop:
- case C.RuleActionRejectMethodReply:
- default:
- return E.New("unknown reject method: " + r.Method)
- }
- if r.Method == C.RuleActionRejectMethodDrop && r.NoDrop {
- return E.New("no_drop is not available in current context")
- }
- return nil
- }
- type RouteActionSniff struct {
- Sniffer badoption.Listable[string] `json:"sniffer,omitempty"`
- Timeout badoption.Duration `json:"timeout,omitempty"`
- }
- type RouteActionResolve struct {
- Server string `json:"server,omitempty"`
- Strategy DomainStrategy `json:"strategy,omitempty"`
- DisableCache bool `json:"disable_cache,omitempty"`
- RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
- ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
- }
- type DNSRouteActionPredefined struct {
- Rcode *DNSRCode `json:"rcode,omitempty"`
- Answer badoption.Listable[DNSRecordOptions] `json:"answer,omitempty"`
- Ns badoption.Listable[DNSRecordOptions] `json:"ns,omitempty"`
- Extra badoption.Listable[DNSRecordOptions] `json:"extra,omitempty"`
- }
|