mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-25 01:51:29 +00:00
Migrate bad options to library
This commit is contained in:
parent
3ff9693ac6
commit
03e422df1a
|
@ -3,6 +3,7 @@ package dialer
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
@ -102,7 +103,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||||
udpAddr4 string
|
udpAddr4 string
|
||||||
)
|
)
|
||||||
if options.Inet4BindAddress != nil {
|
if options.Inet4BindAddress != nil {
|
||||||
bindAddr := options.Inet4BindAddress.Build()
|
bindAddr := options.Inet4BindAddress.Build(netip.IPv4Unspecified())
|
||||||
dialer4.LocalAddr = &net.TCPAddr{IP: bindAddr.AsSlice()}
|
dialer4.LocalAddr = &net.TCPAddr{IP: bindAddr.AsSlice()}
|
||||||
udpDialer4.LocalAddr = &net.UDPAddr{IP: bindAddr.AsSlice()}
|
udpDialer4.LocalAddr = &net.UDPAddr{IP: bindAddr.AsSlice()}
|
||||||
udpAddr4 = M.SocksaddrFrom(bindAddr, 0).String()
|
udpAddr4 = M.SocksaddrFrom(bindAddr, 0).String()
|
||||||
|
@ -113,7 +114,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||||
udpAddr6 string
|
udpAddr6 string
|
||||||
)
|
)
|
||||||
if options.Inet6BindAddress != nil {
|
if options.Inet6BindAddress != nil {
|
||||||
bindAddr := options.Inet6BindAddress.Build()
|
bindAddr := options.Inet6BindAddress.Build(netip.IPv6Unspecified())
|
||||||
dialer6.LocalAddr = &net.TCPAddr{IP: bindAddr.AsSlice()}
|
dialer6.LocalAddr = &net.TCPAddr{IP: bindAddr.AsSlice()}
|
||||||
udpDialer6.LocalAddr = &net.UDPAddr{IP: bindAddr.AsSlice()}
|
udpDialer6.LocalAddr = &net.UDPAddr{IP: bindAddr.AsSlice()}
|
||||||
udpAddr6 = M.SocksaddrFrom(bindAddr, 0).String()
|
udpAddr6 = M.SocksaddrFrom(bindAddr, 0).String()
|
||||||
|
|
|
@ -3,6 +3,7 @@ package listener
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
@ -92,7 +93,7 @@ func (l *Listener) Start() error {
|
||||||
if l.setSystemProxy {
|
if l.setSystemProxy {
|
||||||
listenPort := M.SocksaddrFromNet(l.tcpListener.Addr()).Port
|
listenPort := M.SocksaddrFromNet(l.tcpListener.Addr()).Port
|
||||||
var listenAddrString string
|
var listenAddrString string
|
||||||
listenAddr := l.listenOptions.Listen.Build()
|
listenAddr := l.listenOptions.Listen.Build(netip.IPv4Unspecified())
|
||||||
if listenAddr.IsUnspecified() {
|
if listenAddr.IsUnspecified() {
|
||||||
listenAddrString = "127.0.0.1"
|
listenAddrString = "127.0.0.1"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package listener
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
@ -16,7 +17,7 @@ import (
|
||||||
|
|
||||||
func (l *Listener) ListenTCP() (net.Listener, error) {
|
func (l *Listener) ListenTCP() (net.Listener, error) {
|
||||||
var err error
|
var err error
|
||||||
bindAddr := M.SocksaddrFrom(l.listenOptions.Listen.Build(), l.listenOptions.ListenPort)
|
bindAddr := M.SocksaddrFrom(l.listenOptions.Listen.Build(netip.AddrFrom4([4]byte{127, 0, 0, 1})), l.listenOptions.ListenPort)
|
||||||
var tcpListener net.Listener
|
var tcpListener net.Listener
|
||||||
var listenConfig net.ListenConfig
|
var listenConfig net.ListenConfig
|
||||||
if l.listenOptions.TCPKeepAlive >= 0 {
|
if l.listenOptions.TCPKeepAlive >= 0 {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package listener
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
@ -12,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *Listener) ListenUDP() (net.PacketConn, error) {
|
func (l *Listener) ListenUDP() (net.PacketConn, error) {
|
||||||
bindAddr := M.SocksaddrFrom(l.listenOptions.Listen.Build(), l.listenOptions.ListenPort)
|
bindAddr := M.SocksaddrFrom(l.listenOptions.Listen.Build(netip.AddrFrom4([4]byte{127, 0, 0, 1})), l.listenOptions.ListenPort)
|
||||||
var lc net.ListenConfig
|
var lc net.ListenConfig
|
||||||
var udpFragment bool
|
var udpFragment bool
|
||||||
if l.listenOptions.UDPFragment != nil {
|
if l.listenOptions.UDPFragment != nil {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package deprecated
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import "net/netip"
|
import (
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
|
)
|
||||||
|
|
||||||
type DNSOptions struct {
|
type DNSOptions struct {
|
||||||
Servers []DNSServerOptions `json:"servers,omitempty"`
|
Servers []DNSServerOptions `json:"servers,omitempty"`
|
||||||
|
@ -16,10 +20,10 @@ type DNSServerOptions struct {
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
AddressResolver string `json:"address_resolver,omitempty"`
|
AddressResolver string `json:"address_resolver,omitempty"`
|
||||||
AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
|
AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
|
||||||
AddressFallbackDelay Duration `json:"address_fallback_delay,omitempty"`
|
AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
|
||||||
Strategy DomainStrategy `json:"strategy,omitempty"`
|
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||||
Detour string `json:"detour,omitempty"`
|
Detour string `json:"detour,omitempty"`
|
||||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSClientOptions struct {
|
type DNSClientOptions struct {
|
||||||
|
@ -27,7 +31,7 @@ type DNSClientOptions struct {
|
||||||
DisableCache bool `json:"disable_cache,omitempty"`
|
DisableCache bool `json:"disable_cache,omitempty"`
|
||||||
DisableExpire bool `json:"disable_expire,omitempty"`
|
DisableExpire bool `json:"disable_expire,omitempty"`
|
||||||
IndependentCache bool `json:"independent_cache,omitempty"`
|
IndependentCache bool `json:"independent_cache,omitempty"`
|
||||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSFakeIPOptions struct {
|
type DNSFakeIPOptions struct {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import "github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
type ExperimentalOptions struct {
|
type ExperimentalOptions struct {
|
||||||
CacheFile *CacheFileOptions `json:"cache_file,omitempty"`
|
CacheFile *CacheFileOptions `json:"cache_file,omitempty"`
|
||||||
ClashAPI *ClashAPIOptions `json:"clash_api,omitempty"`
|
ClashAPI *ClashAPIOptions `json:"clash_api,omitempty"`
|
||||||
|
@ -13,7 +15,7 @@ type CacheFileOptions struct {
|
||||||
CacheID string `json:"cache_id,omitempty"`
|
CacheID string `json:"cache_id,omitempty"`
|
||||||
StoreFakeIP bool `json:"store_fakeip,omitempty"`
|
StoreFakeIP bool `json:"store_fakeip,omitempty"`
|
||||||
StoreRDRC bool `json:"store_rdrc,omitempty"`
|
StoreRDRC bool `json:"store_rdrc,omitempty"`
|
||||||
RDRCTimeout Duration `json:"rdrc_timeout,omitempty"`
|
RDRCTimeout badoption.Duration `json:"rdrc_timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClashAPIOptions struct {
|
type ClashAPIOptions struct {
|
||||||
|
@ -24,7 +26,7 @@ type ClashAPIOptions struct {
|
||||||
Secret string `json:"secret,omitempty"`
|
Secret string `json:"secret,omitempty"`
|
||||||
DefaultMode string `json:"default_mode,omitempty"`
|
DefaultMode string `json:"default_mode,omitempty"`
|
||||||
ModeList []string `json:"-"`
|
ModeList []string `json:"-"`
|
||||||
AccessControlAllowOrigin Listable[string] `json:"access_control_allow_origin,omitempty"`
|
AccessControlAllowOrigin badoption.Listable[string] `json:"access_control_allow_origin,omitempty"`
|
||||||
AccessControlAllowPrivateNetwork bool `json:"access_control_allow_private_network,omitempty"`
|
AccessControlAllowPrivateNetwork bool `json:"access_control_allow_private_network,omitempty"`
|
||||||
|
|
||||||
// Deprecated: migrated to global cache file
|
// Deprecated: migrated to global cache file
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import "github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
type SelectorOutboundOptions struct {
|
type SelectorOutboundOptions struct {
|
||||||
Outbounds []string `json:"outbounds"`
|
Outbounds []string `json:"outbounds"`
|
||||||
Default string `json:"default,omitempty"`
|
Default string `json:"default,omitempty"`
|
||||||
|
@ -9,8 +11,8 @@ type SelectorOutboundOptions struct {
|
||||||
type URLTestOutboundOptions struct {
|
type URLTestOutboundOptions struct {
|
||||||
Outbounds []string `json:"outbounds"`
|
Outbounds []string `json:"outbounds"`
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
Interval Duration `json:"interval,omitempty"`
|
Interval badoption.Duration `json:"interval,omitempty"`
|
||||||
Tolerance uint16 `json:"tolerance,omitempty"`
|
Tolerance uint16 `json:"tolerance,omitempty"`
|
||||||
IdleTimeout Duration `json:"idle_timeout,omitempty"`
|
IdleTimeout badoption.Duration `json:"idle_timeout,omitempty"`
|
||||||
InterruptExistConnections bool `json:"interrupt_exist_connections,omitempty"`
|
InterruptExistConnections bool `json:"interrupt_exist_connections,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -51,17 +52,17 @@ func (h *Inbound) UnmarshalJSONContext(ctx context.Context, content []byte) erro
|
||||||
type InboundOptions struct {
|
type InboundOptions struct {
|
||||||
SniffEnabled bool `json:"sniff,omitempty"`
|
SniffEnabled bool `json:"sniff,omitempty"`
|
||||||
SniffOverrideDestination bool `json:"sniff_override_destination,omitempty"`
|
SniffOverrideDestination bool `json:"sniff_override_destination,omitempty"`
|
||||||
SniffTimeout Duration `json:"sniff_timeout,omitempty"`
|
SniffTimeout badoption.Duration `json:"sniff_timeout,omitempty"`
|
||||||
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
||||||
UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"`
|
UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"`
|
||||||
Detour string `json:"detour,omitempty"`
|
Detour string `json:"detour,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenOptions struct {
|
type ListenOptions struct {
|
||||||
Listen *ListenAddress `json:"listen,omitempty"`
|
Listen *badoption.Addr `json:"listen,omitempty"`
|
||||||
ListenPort uint16 `json:"listen_port,omitempty"`
|
ListenPort uint16 `json:"listen_port,omitempty"`
|
||||||
TCPKeepAlive Duration `json:"tcp_keep_alive,omitempty"`
|
TCPKeepAlive badoption.Duration `json:"tcp_keep_alive,omitempty"`
|
||||||
TCPKeepAliveInterval Duration `json:"tcp_keep_alive_interval,omitempty"`
|
TCPKeepAliveInterval badoption.Duration `json:"tcp_keep_alive_interval,omitempty"`
|
||||||
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
||||||
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
||||||
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
||||||
|
@ -75,7 +76,7 @@ type ListenOptions struct {
|
||||||
InboundOptions
|
InboundOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
type UDPTimeoutCompat Duration
|
type UDPTimeoutCompat badoption.Duration
|
||||||
|
|
||||||
func (c UDPTimeoutCompat) MarshalJSON() ([]byte, error) {
|
func (c UDPTimeoutCompat) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal((time.Duration)(c).String())
|
return json.Marshal((time.Duration)(c).String())
|
||||||
|
@ -88,7 +89,7 @@ func (c *UDPTimeoutCompat) UnmarshalJSON(data []byte) error {
|
||||||
*c = UDPTimeoutCompat(time.Second * time.Duration(valueNumber))
|
*c = UDPTimeoutCompat(time.Second * time.Duration(valueNumber))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return json.Unmarshal(data, (*Duration)(c))
|
return json.Unmarshal(data, (*badoption.Duration)(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenOptionsWrapper interface {
|
type ListenOptionsWrapper interface {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import "github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
type NTPOptions struct {
|
type NTPOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
Interval Duration `json:"interval,omitempty"`
|
Interval badoption.Duration `json:"interval,omitempty"`
|
||||||
WriteToSystem bool `json:"write_to_system,omitempty"`
|
WriteToSystem bool `json:"write_to_system,omitempty"`
|
||||||
ServerOptions
|
ServerOptions
|
||||||
DialerOptions
|
DialerOptions
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
@ -66,18 +67,18 @@ type DialerOptionsWrapper interface {
|
||||||
type DialerOptions struct {
|
type DialerOptions struct {
|
||||||
Detour string `json:"detour,omitempty"`
|
Detour string `json:"detour,omitempty"`
|
||||||
BindInterface string `json:"bind_interface,omitempty"`
|
BindInterface string `json:"bind_interface,omitempty"`
|
||||||
Inet4BindAddress *ListenAddress `json:"inet4_bind_address,omitempty"`
|
Inet4BindAddress *badoption.Addr `json:"inet4_bind_address,omitempty"`
|
||||||
Inet6BindAddress *ListenAddress `json:"inet6_bind_address,omitempty"`
|
Inet6BindAddress *badoption.Addr `json:"inet6_bind_address,omitempty"`
|
||||||
ProtectPath string `json:"protect_path,omitempty"`
|
ProtectPath string `json:"protect_path,omitempty"`
|
||||||
RoutingMark uint32 `json:"routing_mark,omitempty"`
|
RoutingMark uint32 `json:"routing_mark,omitempty"`
|
||||||
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
||||||
ConnectTimeout Duration `json:"connect_timeout,omitempty"`
|
ConnectTimeout badoption.Duration `json:"connect_timeout,omitempty"`
|
||||||
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
||||||
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
||||||
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
||||||
UDPFragmentDefault bool `json:"-"`
|
UDPFragmentDefault bool `json:"-"`
|
||||||
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
||||||
FallbackDelay Duration `json:"fallback_delay,omitempty"`
|
FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"`
|
||||||
IsWireGuardListener bool `json:"-"`
|
IsWireGuardListener bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package option
|
||||||
import (
|
import (
|
||||||
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/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OnDemandOptions struct {
|
type OnDemandOptions struct {
|
||||||
|
@ -12,10 +13,10 @@ type OnDemandOptions struct {
|
||||||
|
|
||||||
type OnDemandRule struct {
|
type OnDemandRule struct {
|
||||||
Action *OnDemandRuleAction `json:"action,omitempty"`
|
Action *OnDemandRuleAction `json:"action,omitempty"`
|
||||||
DNSSearchDomainMatch Listable[string] `json:"dns_search_domain_match,omitempty"`
|
DNSSearchDomainMatch badoption.Listable[string] `json:"dns_search_domain_match,omitempty"`
|
||||||
DNSServerAddressMatch Listable[string] `json:"dns_server_address_match,omitempty"`
|
DNSServerAddressMatch badoption.Listable[string] `json:"dns_server_address_match,omitempty"`
|
||||||
InterfaceTypeMatch *OnDemandRuleInterfaceType `json:"interface_type_match,omitempty"`
|
InterfaceTypeMatch *OnDemandRuleInterfaceType `json:"interface_type_match,omitempty"`
|
||||||
SSIDMatch Listable[string] `json:"ssid_match,omitempty"`
|
SSIDMatch badoption.Listable[string] `json:"ssid_match,omitempty"`
|
||||||
ProbeURL string `json:"probe_url,omitempty"`
|
ProbeURL string `json:"probe_url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _Rule struct {
|
type _Rule struct {
|
||||||
|
@ -66,37 +67,37 @@ func (r Rule) IsValid() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RawDefaultRule struct {
|
type RawDefaultRule struct {
|
||||||
Inbound Listable[string] `json:"inbound,omitempty"`
|
Inbound badoption.Listable[string] `json:"inbound,omitempty"`
|
||||||
IPVersion int `json:"ip_version,omitempty"`
|
IPVersion int `json:"ip_version,omitempty"`
|
||||||
Network Listable[string] `json:"network,omitempty"`
|
Network badoption.Listable[string] `json:"network,omitempty"`
|
||||||
AuthUser Listable[string] `json:"auth_user,omitempty"`
|
AuthUser badoption.Listable[string] `json:"auth_user,omitempty"`
|
||||||
Protocol Listable[string] `json:"protocol,omitempty"`
|
Protocol badoption.Listable[string] `json:"protocol,omitempty"`
|
||||||
Client Listable[string] `json:"client,omitempty"`
|
Client badoption.Listable[string] `json:"client,omitempty"`
|
||||||
Domain Listable[string] `json:"domain,omitempty"`
|
Domain badoption.Listable[string] `json:"domain,omitempty"`
|
||||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
DomainSuffix badoption.Listable[string] `json:"domain_suffix,omitempty"`
|
||||||
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
|
DomainKeyword badoption.Listable[string] `json:"domain_keyword,omitempty"`
|
||||||
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
|
DomainRegex badoption.Listable[string] `json:"domain_regex,omitempty"`
|
||||||
Geosite Listable[string] `json:"geosite,omitempty"`
|
Geosite badoption.Listable[string] `json:"geosite,omitempty"`
|
||||||
SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
|
SourceGeoIP badoption.Listable[string] `json:"source_geoip,omitempty"`
|
||||||
GeoIP Listable[string] `json:"geoip,omitempty"`
|
GeoIP badoption.Listable[string] `json:"geoip,omitempty"`
|
||||||
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
|
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||||
SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"`
|
SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"`
|
||||||
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
|
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty"`
|
||||||
IPIsPrivate bool `json:"ip_is_private,omitempty"`
|
IPIsPrivate bool `json:"ip_is_private,omitempty"`
|
||||||
SourcePort Listable[uint16] `json:"source_port,omitempty"`
|
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
||||||
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
|
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
||||||
Port Listable[uint16] `json:"port,omitempty"`
|
Port badoption.Listable[uint16] `json:"port,omitempty"`
|
||||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
PortRange badoption.Listable[string] `json:"port_range,omitempty"`
|
||||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
ProcessName badoption.Listable[string] `json:"process_name,omitempty"`
|
||||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
ProcessPath badoption.Listable[string] `json:"process_path,omitempty"`
|
||||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
ProcessPathRegex badoption.Listable[string] `json:"process_path_regex,omitempty"`
|
||||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
PackageName badoption.Listable[string] `json:"package_name,omitempty"`
|
||||||
User Listable[string] `json:"user,omitempty"`
|
User badoption.Listable[string] `json:"user,omitempty"`
|
||||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
||||||
ClashMode string `json:"clash_mode,omitempty"`
|
ClashMode string `json:"clash_mode,omitempty"`
|
||||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
||||||
RuleSet Listable[string] `json:"rule_set,omitempty"`
|
RuleSet badoption.Listable[string] `json:"rule_set,omitempty"`
|
||||||
RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"`
|
RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"`
|
||||||
Invert bool `json:"invert,omitempty"`
|
Invert bool `json:"invert,omitempty"`
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package option
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
@ -11,6 +12,7 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _RuleAction struct {
|
type _RuleAction struct {
|
||||||
|
@ -177,7 +179,7 @@ type _DNSRouteActionOptions struct {
|
||||||
// Deprecated: Use DNSRouteOptionsActionOptions instead.
|
// Deprecated: Use DNSRouteOptionsActionOptions instead.
|
||||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||||
// Deprecated: Use DNSRouteOptionsActionOptions instead.
|
// Deprecated: Use DNSRouteOptionsActionOptions instead.
|
||||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSRouteActionOptions _DNSRouteActionOptions
|
type DNSRouteActionOptions _DNSRouteActionOptions
|
||||||
|
@ -199,7 +201,7 @@ func (r *DNSRouteActionOptions) UnmarshalJSONContext(ctx context.Context, data [
|
||||||
type _DNSRouteOptionsActionOptions struct {
|
type _DNSRouteOptionsActionOptions struct {
|
||||||
DisableCache bool `json:"disable_cache,omitempty"`
|
DisableCache bool `json:"disable_cache,omitempty"`
|
||||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DNSRouteOptionsActionOptions _DNSRouteOptionsActionOptions
|
type DNSRouteOptionsActionOptions _DNSRouteOptionsActionOptions
|
||||||
|
@ -225,10 +227,10 @@ func (d DirectActionOptions) Descriptions() []string {
|
||||||
descriptions = append(descriptions, "bind_interface="+d.BindInterface)
|
descriptions = append(descriptions, "bind_interface="+d.BindInterface)
|
||||||
}
|
}
|
||||||
if d.Inet4BindAddress != nil {
|
if d.Inet4BindAddress != nil {
|
||||||
descriptions = append(descriptions, "inet4_bind_address="+d.Inet4BindAddress.Build().String())
|
descriptions = append(descriptions, "inet4_bind_address="+d.Inet4BindAddress.Build(netip.IPv4Unspecified()).String())
|
||||||
}
|
}
|
||||||
if d.Inet6BindAddress != nil {
|
if d.Inet6BindAddress != nil {
|
||||||
descriptions = append(descriptions, "inet6_bind_address="+d.Inet6BindAddress.Build().String())
|
descriptions = append(descriptions, "inet6_bind_address="+d.Inet6BindAddress.Build(netip.IPv6Unspecified()).String())
|
||||||
}
|
}
|
||||||
if d.RoutingMark != 0 {
|
if d.RoutingMark != 0 {
|
||||||
descriptions = append(descriptions, "routing_mark="+fmt.Sprintf("0x%x", d.RoutingMark))
|
descriptions = append(descriptions, "routing_mark="+fmt.Sprintf("0x%x", d.RoutingMark))
|
||||||
|
@ -294,8 +296,8 @@ func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RouteActionSniff struct {
|
type RouteActionSniff struct {
|
||||||
Sniffer Listable[string] `json:"sniffer,omitempty"`
|
Sniffer badoption.Listable[string] `json:"sniffer,omitempty"`
|
||||||
Timeout Duration `json:"timeout,omitempty"`
|
Timeout badoption.Duration `json:"timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RouteActionResolve struct {
|
type RouteActionResolve struct {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _DNSRule struct {
|
type _DNSRule struct {
|
||||||
|
@ -67,38 +68,38 @@ func (r DNSRule) IsValid() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RawDefaultDNSRule struct {
|
type RawDefaultDNSRule struct {
|
||||||
Inbound Listable[string] `json:"inbound,omitempty"`
|
Inbound badoption.Listable[string] `json:"inbound,omitempty"`
|
||||||
IPVersion int `json:"ip_version,omitempty"`
|
IPVersion int `json:"ip_version,omitempty"`
|
||||||
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
|
QueryType badoption.Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||||
Network Listable[string] `json:"network,omitempty"`
|
Network badoption.Listable[string] `json:"network,omitempty"`
|
||||||
AuthUser Listable[string] `json:"auth_user,omitempty"`
|
AuthUser badoption.Listable[string] `json:"auth_user,omitempty"`
|
||||||
Protocol Listable[string] `json:"protocol,omitempty"`
|
Protocol badoption.Listable[string] `json:"protocol,omitempty"`
|
||||||
Domain Listable[string] `json:"domain,omitempty"`
|
Domain badoption.Listable[string] `json:"domain,omitempty"`
|
||||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
DomainSuffix badoption.Listable[string] `json:"domain_suffix,omitempty"`
|
||||||
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
|
DomainKeyword badoption.Listable[string] `json:"domain_keyword,omitempty"`
|
||||||
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
|
DomainRegex badoption.Listable[string] `json:"domain_regex,omitempty"`
|
||||||
Geosite Listable[string] `json:"geosite,omitempty"`
|
Geosite badoption.Listable[string] `json:"geosite,omitempty"`
|
||||||
SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
|
SourceGeoIP badoption.Listable[string] `json:"source_geoip,omitempty"`
|
||||||
GeoIP Listable[string] `json:"geoip,omitempty"`
|
GeoIP badoption.Listable[string] `json:"geoip,omitempty"`
|
||||||
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
|
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty"`
|
||||||
IPIsPrivate bool `json:"ip_is_private,omitempty"`
|
IPIsPrivate bool `json:"ip_is_private,omitempty"`
|
||||||
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
|
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||||
SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"`
|
SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"`
|
||||||
SourcePort Listable[uint16] `json:"source_port,omitempty"`
|
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
||||||
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
|
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
||||||
Port Listable[uint16] `json:"port,omitempty"`
|
Port badoption.Listable[uint16] `json:"port,omitempty"`
|
||||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
PortRange badoption.Listable[string] `json:"port_range,omitempty"`
|
||||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
ProcessName badoption.Listable[string] `json:"process_name,omitempty"`
|
||||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
ProcessPath badoption.Listable[string] `json:"process_path,omitempty"`
|
||||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
ProcessPathRegex badoption.Listable[string] `json:"process_path_regex,omitempty"`
|
||||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
PackageName badoption.Listable[string] `json:"package_name,omitempty"`
|
||||||
User Listable[string] `json:"user,omitempty"`
|
User badoption.Listable[string] `json:"user,omitempty"`
|
||||||
UserID Listable[int32] `json:"user_id,omitempty"`
|
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
||||||
Outbound Listable[string] `json:"outbound,omitempty"`
|
Outbound badoption.Listable[string] `json:"outbound,omitempty"`
|
||||||
ClashMode string `json:"clash_mode,omitempty"`
|
ClashMode string `json:"clash_mode,omitempty"`
|
||||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
||||||
RuleSet Listable[string] `json:"rule_set,omitempty"`
|
RuleSet badoption.Listable[string] `json:"rule_set,omitempty"`
|
||||||
RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"`
|
RuleSetIPCIDRMatchSource bool `json:"rule_set_ip_cidr_match_source,omitempty"`
|
||||||
RuleSetIPCIDRAcceptEmpty bool `json:"rule_set_ip_cidr_accept_empty,omitempty"`
|
RuleSetIPCIDRAcceptEmpty bool `json:"rule_set_ip_cidr_accept_empty,omitempty"`
|
||||||
Invert bool `json:"invert,omitempty"`
|
Invert bool `json:"invert,omitempty"`
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
)
|
)
|
||||||
|
@ -86,7 +87,7 @@ type LocalRuleSet struct {
|
||||||
type RemoteRuleSet struct {
|
type RemoteRuleSet struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
DownloadDetour string `json:"download_detour,omitempty"`
|
DownloadDetour string `json:"download_detour,omitempty"`
|
||||||
UpdateInterval Duration `json:"update_interval,omitempty"`
|
UpdateInterval badoption.Duration `json:"update_interval,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type _HeadlessRule struct {
|
type _HeadlessRule struct {
|
||||||
|
@ -145,31 +146,31 @@ func (r HeadlessRule) IsValid() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultHeadlessRule struct {
|
type DefaultHeadlessRule struct {
|
||||||
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
|
QueryType badoption.Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||||
Network Listable[string] `json:"network,omitempty"`
|
Network badoption.Listable[string] `json:"network,omitempty"`
|
||||||
Domain Listable[string] `json:"domain,omitempty"`
|
Domain badoption.Listable[string] `json:"domain,omitempty"`
|
||||||
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
|
DomainSuffix badoption.Listable[string] `json:"domain_suffix,omitempty"`
|
||||||
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
|
DomainKeyword badoption.Listable[string] `json:"domain_keyword,omitempty"`
|
||||||
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
|
DomainRegex badoption.Listable[string] `json:"domain_regex,omitempty"`
|
||||||
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
|
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||||
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
|
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty"`
|
||||||
SourcePort Listable[uint16] `json:"source_port,omitempty"`
|
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
||||||
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
|
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
||||||
Port Listable[uint16] `json:"port,omitempty"`
|
Port badoption.Listable[uint16] `json:"port,omitempty"`
|
||||||
PortRange Listable[string] `json:"port_range,omitempty"`
|
PortRange badoption.Listable[string] `json:"port_range,omitempty"`
|
||||||
ProcessName Listable[string] `json:"process_name,omitempty"`
|
ProcessName badoption.Listable[string] `json:"process_name,omitempty"`
|
||||||
ProcessPath Listable[string] `json:"process_path,omitempty"`
|
ProcessPath badoption.Listable[string] `json:"process_path,omitempty"`
|
||||||
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
|
ProcessPathRegex badoption.Listable[string] `json:"process_path_regex,omitempty"`
|
||||||
PackageName Listable[string] `json:"package_name,omitempty"`
|
PackageName badoption.Listable[string] `json:"package_name,omitempty"`
|
||||||
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
|
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||||
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
|
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
||||||
Invert bool `json:"invert,omitempty"`
|
Invert bool `json:"invert,omitempty"`
|
||||||
|
|
||||||
DomainMatcher *domain.Matcher `json:"-"`
|
DomainMatcher *domain.Matcher `json:"-"`
|
||||||
SourceIPSet *netipx.IPSet `json:"-"`
|
SourceIPSet *netipx.IPSet `json:"-"`
|
||||||
IPSet *netipx.IPSet `json:"-"`
|
IPSet *netipx.IPSet `json:"-"`
|
||||||
|
|
||||||
AdGuardDomain Listable[string] `json:"-"`
|
AdGuardDomain badoption.Listable[string] `json:"-"`
|
||||||
AdGuardDomainMatcher *domain.AdGuardMatcher `json:"-"`
|
AdGuardDomainMatcher *domain.AdGuardMatcher `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import "github.com/sagernet/sing/common/auth"
|
import (
|
||||||
|
"github.com/sagernet/sing/common/auth"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
|
)
|
||||||
|
|
||||||
type SocksInboundOptions struct {
|
type SocksInboundOptions struct {
|
||||||
ListenOptions
|
ListenOptions
|
||||||
|
@ -31,5 +34,5 @@ type HTTPOutboundOptions struct {
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
OutboundTLSOptionsContainer
|
OutboundTLSOptionsContainer
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Headers HTTPHeader `json:"headers,omitempty"`
|
Headers badoption.HTTPHeader `json:"headers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import "github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
type SSHOutboundOptions struct {
|
type SSHOutboundOptions struct {
|
||||||
DialerOptions
|
DialerOptions
|
||||||
ServerOptions
|
ServerOptions
|
||||||
User string `json:"user,omitempty"`
|
User string `json:"user,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
PrivateKey Listable[string] `json:"private_key,omitempty"`
|
PrivateKey badoption.Listable[string] `json:"private_key,omitempty"`
|
||||||
PrivateKeyPath string `json:"private_key_path,omitempty"`
|
PrivateKeyPath string `json:"private_key_path,omitempty"`
|
||||||
PrivateKeyPassphrase string `json:"private_key_passphrase,omitempty"`
|
PrivateKeyPassphrase string `json:"private_key_passphrase,omitempty"`
|
||||||
HostKey Listable[string] `json:"host_key,omitempty"`
|
HostKey badoption.Listable[string] `json:"host_key,omitempty"`
|
||||||
HostKeyAlgorithms Listable[string] `json:"host_key_algorithms,omitempty"`
|
HostKeyAlgorithms badoption.Listable[string] `json:"host_key_algorithms,omitempty"`
|
||||||
ClientVersion string `json:"client_version,omitempty"`
|
ClientVersion string `json:"client_version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,226 +0,0 @@
|
||||||
package option
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
const durationDay = 24 * time.Hour
|
|
||||||
|
|
||||||
var unitMap = map[string]uint64{
|
|
||||||
"ns": uint64(time.Nanosecond),
|
|
||||||
"us": uint64(time.Microsecond),
|
|
||||||
"µs": uint64(time.Microsecond), // U+00B5 = micro symbol
|
|
||||||
"μs": uint64(time.Microsecond), // U+03BC = Greek letter mu
|
|
||||||
"ms": uint64(time.Millisecond),
|
|
||||||
"s": uint64(time.Second),
|
|
||||||
"m": uint64(time.Minute),
|
|
||||||
"h": uint64(time.Hour),
|
|
||||||
"d": uint64(durationDay),
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseDuration parses a duration string.
|
|
||||||
// A duration string is a possibly signed sequence of
|
|
||||||
// decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
// such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
func ParseDuration(s string) (Duration, error) {
|
|
||||||
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
|
|
||||||
orig := s
|
|
||||||
var d uint64
|
|
||||||
neg := false
|
|
||||||
|
|
||||||
// Consume [-+]?
|
|
||||||
if s != "" {
|
|
||||||
c := s[0]
|
|
||||||
if c == '-' || c == '+' {
|
|
||||||
neg = c == '-'
|
|
||||||
s = s[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Special case: if all that is left is "0", this is zero.
|
|
||||||
if s == "0" {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
if s == "" {
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
for s != "" {
|
|
||||||
var (
|
|
||||||
v, f uint64 // integers before, after decimal point
|
|
||||||
scale float64 = 1 // value = v + f/scale
|
|
||||||
)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// The next character must be [0-9.]
|
|
||||||
if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
// Consume [0-9]*
|
|
||||||
pl := len(s)
|
|
||||||
v, s, err = leadingInt(s)
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
pre := pl != len(s) // whether we consumed anything before a period
|
|
||||||
|
|
||||||
// Consume (\.[0-9]*)?
|
|
||||||
post := false
|
|
||||||
if s != "" && s[0] == '.' {
|
|
||||||
s = s[1:]
|
|
||||||
pl := len(s)
|
|
||||||
f, scale, s = leadingFraction(s)
|
|
||||||
post = pl != len(s)
|
|
||||||
}
|
|
||||||
if !pre && !post {
|
|
||||||
// no digits (e.g. ".s" or "-.s")
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume unit.
|
|
||||||
i := 0
|
|
||||||
for ; i < len(s); i++ {
|
|
||||||
c := s[i]
|
|
||||||
if c == '.' || '0' <= c && c <= '9' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
return 0, errors.New("time: missing unit in duration " + quote(orig))
|
|
||||||
}
|
|
||||||
u := s[:i]
|
|
||||||
s = s[i:]
|
|
||||||
unit, ok := unitMap[u]
|
|
||||||
if !ok {
|
|
||||||
return 0, errors.New("time: unknown unit " + quote(u) + " in duration " + quote(orig))
|
|
||||||
}
|
|
||||||
if v > 1<<63/unit {
|
|
||||||
// overflow
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
v *= unit
|
|
||||||
if f > 0 {
|
|
||||||
// float64 is needed to be nanosecond accurate for fractions of hours.
|
|
||||||
// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
|
|
||||||
v += uint64(float64(f) * (float64(unit) / scale))
|
|
||||||
if v > 1<<63 {
|
|
||||||
// overflow
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d += v
|
|
||||||
if d > 1<<63 {
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if neg {
|
|
||||||
return -Duration(d), nil
|
|
||||||
}
|
|
||||||
if d > 1<<63-1 {
|
|
||||||
return 0, errors.New("time: invalid duration " + quote(orig))
|
|
||||||
}
|
|
||||||
return Duration(d), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errLeadingInt = errors.New("time: bad [0-9]*") // never printed
|
|
||||||
|
|
||||||
// leadingInt consumes the leading [0-9]* from s.
|
|
||||||
func leadingInt[bytes []byte | string](s bytes) (x uint64, rem bytes, err error) {
|
|
||||||
i := 0
|
|
||||||
for ; i < len(s); i++ {
|
|
||||||
c := s[i]
|
|
||||||
if c < '0' || c > '9' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if x > 1<<63/10 {
|
|
||||||
// overflow
|
|
||||||
return 0, rem, errLeadingInt
|
|
||||||
}
|
|
||||||
x = x*10 + uint64(c) - '0'
|
|
||||||
if x > 1<<63 {
|
|
||||||
// overflow
|
|
||||||
return 0, rem, errLeadingInt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x, s[i:], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// leadingFraction consumes the leading [0-9]* from s.
|
|
||||||
// It is used only for fractions, so does not return an error on overflow,
|
|
||||||
// it just stops accumulating precision.
|
|
||||||
func leadingFraction(s string) (x uint64, scale float64, rem string) {
|
|
||||||
i := 0
|
|
||||||
scale = 1
|
|
||||||
overflow := false
|
|
||||||
for ; i < len(s); i++ {
|
|
||||||
c := s[i]
|
|
||||||
if c < '0' || c > '9' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if overflow {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if x > (1<<63-1)/10 {
|
|
||||||
// It's possible for overflow to give a positive number, so take care.
|
|
||||||
overflow = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
y := x*10 + uint64(c) - '0'
|
|
||||||
if y > 1<<63 {
|
|
||||||
overflow = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
x = y
|
|
||||||
scale *= 10
|
|
||||||
}
|
|
||||||
return x, scale, s[i:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are borrowed from unicode/utf8 and strconv and replicate behavior in
|
|
||||||
// that package, since we can't take a dependency on either.
|
|
||||||
const (
|
|
||||||
lowerhex = "0123456789abcdef"
|
|
||||||
runeSelf = 0x80
|
|
||||||
runeError = '\uFFFD'
|
|
||||||
)
|
|
||||||
|
|
||||||
func quote(s string) string {
|
|
||||||
buf := make([]byte, 1, len(s)+2) // slice will be at least len(s) + quotes
|
|
||||||
buf[0] = '"'
|
|
||||||
for i, c := range s {
|
|
||||||
if c >= runeSelf || c < ' ' {
|
|
||||||
// This means you are asking us to parse a time.Duration or
|
|
||||||
// time.Location with unprintable or non-ASCII characters in it.
|
|
||||||
// We don't expect to hit this case very often. We could try to
|
|
||||||
// reproduce strconv.Quote's behavior with full fidelity but
|
|
||||||
// given how rarely we expect to hit these edge cases, speed and
|
|
||||||
// conciseness are better.
|
|
||||||
var width int
|
|
||||||
if c == runeError {
|
|
||||||
width = 1
|
|
||||||
if i+2 < len(s) && s[i:i+3] == string(runeError) {
|
|
||||||
width = 3
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
width = len(string(c))
|
|
||||||
}
|
|
||||||
for j := 0; j < width; j++ {
|
|
||||||
buf = append(buf, `\x`...)
|
|
||||||
buf = append(buf, lowerhex[s[i+j]>>4])
|
|
||||||
buf = append(buf, lowerhex[s[i+j]&0xF])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if c == '"' || c == '\\' {
|
|
||||||
buf = append(buf, '\\')
|
|
||||||
}
|
|
||||||
buf = append(buf, string(c)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf = append(buf, '"')
|
|
||||||
return string(buf)
|
|
||||||
}
|
|
|
@ -1,16 +1,18 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import "github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
type InboundTLSOptions struct {
|
type InboundTLSOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
ServerName string `json:"server_name,omitempty"`
|
ServerName string `json:"server_name,omitempty"`
|
||||||
Insecure bool `json:"insecure,omitempty"`
|
Insecure bool `json:"insecure,omitempty"`
|
||||||
ALPN Listable[string] `json:"alpn,omitempty"`
|
ALPN badoption.Listable[string] `json:"alpn,omitempty"`
|
||||||
MinVersion string `json:"min_version,omitempty"`
|
MinVersion string `json:"min_version,omitempty"`
|
||||||
MaxVersion string `json:"max_version,omitempty"`
|
MaxVersion string `json:"max_version,omitempty"`
|
||||||
CipherSuites Listable[string] `json:"cipher_suites,omitempty"`
|
CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"`
|
||||||
Certificate Listable[string] `json:"certificate,omitempty"`
|
Certificate badoption.Listable[string] `json:"certificate,omitempty"`
|
||||||
CertificatePath string `json:"certificate_path,omitempty"`
|
CertificatePath string `json:"certificate_path,omitempty"`
|
||||||
Key Listable[string] `json:"key,omitempty"`
|
Key badoption.Listable[string] `json:"key,omitempty"`
|
||||||
KeyPath string `json:"key_path,omitempty"`
|
KeyPath string `json:"key_path,omitempty"`
|
||||||
ACME *InboundACMEOptions `json:"acme,omitempty"`
|
ACME *InboundACMEOptions `json:"acme,omitempty"`
|
||||||
ECH *InboundECHOptions `json:"ech,omitempty"`
|
ECH *InboundECHOptions `json:"ech,omitempty"`
|
||||||
|
@ -39,11 +41,11 @@ type OutboundTLSOptions struct {
|
||||||
DisableSNI bool `json:"disable_sni,omitempty"`
|
DisableSNI bool `json:"disable_sni,omitempty"`
|
||||||
ServerName string `json:"server_name,omitempty"`
|
ServerName string `json:"server_name,omitempty"`
|
||||||
Insecure bool `json:"insecure,omitempty"`
|
Insecure bool `json:"insecure,omitempty"`
|
||||||
ALPN Listable[string] `json:"alpn,omitempty"`
|
ALPN badoption.Listable[string] `json:"alpn,omitempty"`
|
||||||
MinVersion string `json:"min_version,omitempty"`
|
MinVersion string `json:"min_version,omitempty"`
|
||||||
MaxVersion string `json:"max_version,omitempty"`
|
MaxVersion string `json:"max_version,omitempty"`
|
||||||
CipherSuites Listable[string] `json:"cipher_suites,omitempty"`
|
CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"`
|
||||||
Certificate Listable[string] `json:"certificate,omitempty"`
|
Certificate badoption.Listable[string] `json:"certificate,omitempty"`
|
||||||
CertificatePath string `json:"certificate_path,omitempty"`
|
CertificatePath string `json:"certificate_path,omitempty"`
|
||||||
ECH *OutboundECHOptions `json:"ech,omitempty"`
|
ECH *OutboundECHOptions `json:"ech,omitempty"`
|
||||||
UTLS *OutboundUTLSOptions `json:"utls,omitempty"`
|
UTLS *OutboundUTLSOptions `json:"utls,omitempty"`
|
||||||
|
@ -71,8 +73,8 @@ type InboundRealityOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
Handshake InboundRealityHandshakeOptions `json:"handshake,omitempty"`
|
Handshake InboundRealityHandshakeOptions `json:"handshake,omitempty"`
|
||||||
PrivateKey string `json:"private_key,omitempty"`
|
PrivateKey string `json:"private_key,omitempty"`
|
||||||
ShortID Listable[string] `json:"short_id,omitempty"`
|
ShortID badoption.Listable[string] `json:"short_id,omitempty"`
|
||||||
MaxTimeDifference Duration `json:"max_time_difference,omitempty"`
|
MaxTimeDifference badoption.Duration `json:"max_time_difference,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type InboundRealityHandshakeOptions struct {
|
type InboundRealityHandshakeOptions struct {
|
||||||
|
@ -84,7 +86,7 @@ type InboundECHOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"`
|
PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"`
|
||||||
DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"`
|
DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"`
|
||||||
Key Listable[string] `json:"key,omitempty"`
|
Key badoption.Listable[string] `json:"key,omitempty"`
|
||||||
KeyPath string `json:"key_path,omitempty"`
|
KeyPath string `json:"key_path,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +94,7 @@ type OutboundECHOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"`
|
PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"`
|
||||||
DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"`
|
DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"`
|
||||||
Config Listable[string] `json:"config,omitempty"`
|
Config badoption.Listable[string] `json:"config,omitempty"`
|
||||||
ConfigPath string `json:"config_path,omitempty"`
|
ConfigPath string `json:"config_path,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InboundACMEOptions struct {
|
type InboundACMEOptions struct {
|
||||||
Domain Listable[string] `json:"domain,omitempty"`
|
Domain badoption.Listable[string] `json:"domain,omitempty"`
|
||||||
DataDirectory string `json:"data_directory,omitempty"`
|
DataDirectory string `json:"data_directory,omitempty"`
|
||||||
DefaultServerName string `json:"default_server_name,omitempty"`
|
DefaultServerName string `json:"default_server_name,omitempty"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import "github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
type TUICInboundOptions struct {
|
type TUICInboundOptions struct {
|
||||||
ListenOptions
|
ListenOptions
|
||||||
Users []TUICUser `json:"users,omitempty"`
|
Users []TUICUser `json:"users,omitempty"`
|
||||||
CongestionControl string `json:"congestion_control,omitempty"`
|
CongestionControl string `json:"congestion_control,omitempty"`
|
||||||
AuthTimeout Duration `json:"auth_timeout,omitempty"`
|
AuthTimeout badoption.Duration `json:"auth_timeout,omitempty"`
|
||||||
ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"`
|
ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"`
|
||||||
Heartbeat Duration `json:"heartbeat,omitempty"`
|
Heartbeat badoption.Duration `json:"heartbeat,omitempty"`
|
||||||
InboundTLSOptionsContainer
|
InboundTLSOptionsContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +27,7 @@ type TUICOutboundOptions struct {
|
||||||
UDPRelayMode string `json:"udp_relay_mode,omitempty"`
|
UDPRelayMode string `json:"udp_relay_mode,omitempty"`
|
||||||
UDPOverStream bool `json:"udp_over_stream,omitempty"`
|
UDPOverStream bool `json:"udp_over_stream,omitempty"`
|
||||||
ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"`
|
ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"`
|
||||||
Heartbeat Duration `json:"heartbeat,omitempty"`
|
Heartbeat badoption.Duration `json:"heartbeat,omitempty"`
|
||||||
Network NetworkList `json:"network,omitempty"`
|
Network NetworkList `json:"network,omitempty"`
|
||||||
OutboundTLSOptionsContainer
|
OutboundTLSOptionsContainer
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,14 @@ 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/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TunInboundOptions struct {
|
type TunInboundOptions struct {
|
||||||
InterfaceName string `json:"interface_name,omitempty"`
|
InterfaceName string `json:"interface_name,omitempty"`
|
||||||
MTU uint32 `json:"mtu,omitempty"`
|
MTU uint32 `json:"mtu,omitempty"`
|
||||||
GSO bool `json:"gso,omitempty"`
|
GSO bool `json:"gso,omitempty"`
|
||||||
Address Listable[netip.Prefix] `json:"address,omitempty"`
|
Address badoption.Listable[netip.Prefix] `json:"address,omitempty"`
|
||||||
AutoRoute bool `json:"auto_route,omitempty"`
|
AutoRoute bool `json:"auto_route,omitempty"`
|
||||||
IPRoute2TableIndex int `json:"iproute2_table_index,omitempty"`
|
IPRoute2TableIndex int `json:"iproute2_table_index,omitempty"`
|
||||||
IPRoute2RuleIndex int `json:"iproute2_rule_index,omitempty"`
|
IPRoute2RuleIndex int `json:"iproute2_rule_index,omitempty"`
|
||||||
|
@ -21,19 +22,19 @@ type TunInboundOptions struct {
|
||||||
AutoRedirectInputMark FwMark `json:"auto_redirect_input_mark,omitempty"`
|
AutoRedirectInputMark FwMark `json:"auto_redirect_input_mark,omitempty"`
|
||||||
AutoRedirectOutputMark FwMark `json:"auto_redirect_output_mark,omitempty"`
|
AutoRedirectOutputMark FwMark `json:"auto_redirect_output_mark,omitempty"`
|
||||||
StrictRoute bool `json:"strict_route,omitempty"`
|
StrictRoute bool `json:"strict_route,omitempty"`
|
||||||
RouteAddress Listable[netip.Prefix] `json:"route_address,omitempty"`
|
RouteAddress badoption.Listable[netip.Prefix] `json:"route_address,omitempty"`
|
||||||
RouteAddressSet Listable[string] `json:"route_address_set,omitempty"`
|
RouteAddressSet badoption.Listable[string] `json:"route_address_set,omitempty"`
|
||||||
RouteExcludeAddress Listable[netip.Prefix] `json:"route_exclude_address,omitempty"`
|
RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"route_exclude_address,omitempty"`
|
||||||
RouteExcludeAddressSet Listable[string] `json:"route_exclude_address_set,omitempty"`
|
RouteExcludeAddressSet badoption.Listable[string] `json:"route_exclude_address_set,omitempty"`
|
||||||
IncludeInterface Listable[string] `json:"include_interface,omitempty"`
|
IncludeInterface badoption.Listable[string] `json:"include_interface,omitempty"`
|
||||||
ExcludeInterface Listable[string] `json:"exclude_interface,omitempty"`
|
ExcludeInterface badoption.Listable[string] `json:"exclude_interface,omitempty"`
|
||||||
IncludeUID Listable[uint32] `json:"include_uid,omitempty"`
|
IncludeUID badoption.Listable[uint32] `json:"include_uid,omitempty"`
|
||||||
IncludeUIDRange Listable[string] `json:"include_uid_range,omitempty"`
|
IncludeUIDRange badoption.Listable[string] `json:"include_uid_range,omitempty"`
|
||||||
ExcludeUID Listable[uint32] `json:"exclude_uid,omitempty"`
|
ExcludeUID badoption.Listable[uint32] `json:"exclude_uid,omitempty"`
|
||||||
ExcludeUIDRange Listable[string] `json:"exclude_uid_range,omitempty"`
|
ExcludeUIDRange badoption.Listable[string] `json:"exclude_uid_range,omitempty"`
|
||||||
IncludeAndroidUser Listable[int] `json:"include_android_user,omitempty"`
|
IncludeAndroidUser badoption.Listable[int] `json:"include_android_user,omitempty"`
|
||||||
IncludePackage Listable[string] `json:"include_package,omitempty"`
|
IncludePackage badoption.Listable[string] `json:"include_package,omitempty"`
|
||||||
ExcludePackage Listable[string] `json:"exclude_package,omitempty"`
|
ExcludePackage badoption.Listable[string] `json:"exclude_package,omitempty"`
|
||||||
EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"`
|
EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"`
|
||||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
||||||
Stack string `json:"stack,omitempty"`
|
Stack string `json:"stack,omitempty"`
|
||||||
|
@ -41,17 +42,17 @@ type TunInboundOptions struct {
|
||||||
InboundOptions
|
InboundOptions
|
||||||
|
|
||||||
// Deprecated: merged to Address
|
// Deprecated: merged to Address
|
||||||
Inet4Address Listable[netip.Prefix] `json:"inet4_address,omitempty"`
|
Inet4Address badoption.Listable[netip.Prefix] `json:"inet4_address,omitempty"`
|
||||||
// Deprecated: merged to Address
|
// Deprecated: merged to Address
|
||||||
Inet6Address Listable[netip.Prefix] `json:"inet6_address,omitempty"`
|
Inet6Address badoption.Listable[netip.Prefix] `json:"inet6_address,omitempty"`
|
||||||
// Deprecated: merged to RouteAddress
|
// Deprecated: merged to RouteAddress
|
||||||
Inet4RouteAddress Listable[netip.Prefix] `json:"inet4_route_address,omitempty"`
|
Inet4RouteAddress badoption.Listable[netip.Prefix] `json:"inet4_route_address,omitempty"`
|
||||||
// Deprecated: merged to RouteAddress
|
// Deprecated: merged to RouteAddress
|
||||||
Inet6RouteAddress Listable[netip.Prefix] `json:"inet6_route_address,omitempty"`
|
Inet6RouteAddress badoption.Listable[netip.Prefix] `json:"inet6_route_address,omitempty"`
|
||||||
// Deprecated: merged to RouteExcludeAddress
|
// Deprecated: merged to RouteExcludeAddress
|
||||||
Inet4RouteExcludeAddress Listable[netip.Prefix] `json:"inet4_route_exclude_address,omitempty"`
|
Inet4RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"inet4_route_exclude_address,omitempty"`
|
||||||
// Deprecated: merged to RouteExcludeAddress
|
// Deprecated: merged to RouteExcludeAddress
|
||||||
Inet6RouteExcludeAddress Listable[netip.Prefix] `json:"inet6_route_exclude_address,omitempty"`
|
Inet6RouteExcludeAddress badoption.Listable[netip.Prefix] `json:"inet6_route_exclude_address,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FwMark uint32
|
type FwMark uint32
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import "github.com/sagernet/sing/common/json/badoption"
|
||||||
|
|
||||||
type TunPlatformOptions struct {
|
type TunPlatformOptions struct {
|
||||||
HTTPProxy *HTTPProxyOptions `json:"http_proxy,omitempty"`
|
HTTPProxy *HTTPProxyOptions `json:"http_proxy,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -7,6 +9,6 @@ type TunPlatformOptions struct {
|
||||||
type HTTPProxyOptions struct {
|
type HTTPProxyOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
ServerOptions
|
ServerOptions
|
||||||
BypassDomain Listable[string] `json:"bypass_domain,omitempty"`
|
BypassDomain badoption.Listable[string] `json:"bypass_domain,omitempty"`
|
||||||
MatchDomain Listable[string] `json:"match_domain,omitempty"`
|
MatchDomain badoption.Listable[string] `json:"match_domain,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
132
option/types.go
132
option/types.go
|
@ -1,10 +1,7 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"net/netip"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
@ -15,79 +12,6 @@ import (
|
||||||
mDNS "github.com/miekg/dns"
|
mDNS "github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListenAddress netip.Addr
|
|
||||||
|
|
||||||
func NewListenAddress(addr netip.Addr) *ListenAddress {
|
|
||||||
address := ListenAddress(addr)
|
|
||||||
return &address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a ListenAddress) MarshalJSON() ([]byte, error) {
|
|
||||||
addr := netip.Addr(a)
|
|
||||||
if !addr.IsValid() {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return json.Marshal(addr.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ListenAddress) UnmarshalJSON(content []byte) error {
|
|
||||||
var value string
|
|
||||||
err := json.Unmarshal(content, &value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
addr, err := netip.ParseAddr(value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*a = ListenAddress(addr)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ListenAddress) Build() netip.Addr {
|
|
||||||
if a == nil {
|
|
||||||
return netip.AddrFrom4([4]byte{127, 0, 0, 1})
|
|
||||||
}
|
|
||||||
return (netip.Addr)(*a)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AddrPrefix netip.Prefix
|
|
||||||
|
|
||||||
func (a AddrPrefix) MarshalJSON() ([]byte, error) {
|
|
||||||
prefix := netip.Prefix(a)
|
|
||||||
if prefix.Bits() == prefix.Addr().BitLen() {
|
|
||||||
return json.Marshal(prefix.Addr().String())
|
|
||||||
} else {
|
|
||||||
return json.Marshal(prefix.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AddrPrefix) UnmarshalJSON(content []byte) error {
|
|
||||||
var value string
|
|
||||||
err := json.Unmarshal(content, &value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
prefix, prefixErr := netip.ParsePrefix(value)
|
|
||||||
if prefixErr == nil {
|
|
||||||
*a = AddrPrefix(prefix)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
addr, addrErr := netip.ParseAddr(value)
|
|
||||||
if addrErr == nil {
|
|
||||||
*a = AddrPrefix(netip.PrefixFrom(addr, addr.BitLen()))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return prefixErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AddrPrefix) Build() netip.Prefix {
|
|
||||||
if a == nil {
|
|
||||||
return netip.Prefix{}
|
|
||||||
}
|
|
||||||
return netip.Prefix(*a)
|
|
||||||
}
|
|
||||||
|
|
||||||
type NetworkList string
|
type NetworkList string
|
||||||
|
|
||||||
func (v *NetworkList) UnmarshalJSON(content []byte) error {
|
func (v *NetworkList) UnmarshalJSON(content []byte) error {
|
||||||
|
@ -120,30 +44,6 @@ func (v NetworkList) Build() []string {
|
||||||
return strings.Split(string(v), "\n")
|
return strings.Split(string(v), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Listable[T any] []T
|
|
||||||
|
|
||||||
func (l Listable[T]) MarshalJSON() ([]byte, error) {
|
|
||||||
arrayList := []T(l)
|
|
||||||
if len(arrayList) == 1 {
|
|
||||||
return json.Marshal(arrayList[0])
|
|
||||||
}
|
|
||||||
return json.Marshal(arrayList)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Listable[T]) UnmarshalJSON(content []byte) error {
|
|
||||||
err := json.UnmarshalDisallowUnknownFields(content, (*[]T)(l))
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var singleItem T
|
|
||||||
newError := json.UnmarshalDisallowUnknownFields(content, &singleItem)
|
|
||||||
if newError != nil {
|
|
||||||
return E.Errors(err, newError)
|
|
||||||
}
|
|
||||||
*l = []T{singleItem}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type DomainStrategy dns.DomainStrategy
|
type DomainStrategy dns.DomainStrategy
|
||||||
|
|
||||||
func (s DomainStrategy) String() string {
|
func (s DomainStrategy) String() string {
|
||||||
|
@ -206,26 +106,6 @@ func (s *DomainStrategy) UnmarshalJSON(bytes []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Duration time.Duration
|
|
||||||
|
|
||||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
|
||||||
return json.Marshal((time.Duration)(d).String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Duration) UnmarshalJSON(bytes []byte) error {
|
|
||||||
var value string
|
|
||||||
err := json.Unmarshal(bytes, &value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
duration, err := ParseDuration(value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*d = Duration(duration)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type DNSQueryType uint16
|
type DNSQueryType uint16
|
||||||
|
|
||||||
func (t DNSQueryType) String() string {
|
func (t DNSQueryType) String() string {
|
||||||
|
@ -270,15 +150,3 @@ func DNSQueryTypeToString(queryType uint16) string {
|
||||||
}
|
}
|
||||||
return F.ToString(queryType)
|
return F.ToString(queryType)
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPHeader map[string]Listable[string]
|
|
||||||
|
|
||||||
func (h HTTPHeader) Build() http.Header {
|
|
||||||
header := make(http.Header)
|
|
||||||
for name, values := range h {
|
|
||||||
for _, value := range values {
|
|
||||||
header.Add(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return header
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
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"
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _V2RayTransportOptions struct {
|
type _V2RayTransportOptions struct {
|
||||||
|
@ -67,17 +68,17 @@ func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type V2RayHTTPOptions struct {
|
type V2RayHTTPOptions struct {
|
||||||
Host Listable[string] `json:"host,omitempty"`
|
Host badoption.Listable[string] `json:"host,omitempty"`
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Method string `json:"method,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
Headers HTTPHeader `json:"headers,omitempty"`
|
Headers badoption.HTTPHeader `json:"headers,omitempty"`
|
||||||
IdleTimeout Duration `json:"idle_timeout,omitempty"`
|
IdleTimeout badoption.Duration `json:"idle_timeout,omitempty"`
|
||||||
PingTimeout Duration `json:"ping_timeout,omitempty"`
|
PingTimeout badoption.Duration `json:"ping_timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type V2RayWebsocketOptions struct {
|
type V2RayWebsocketOptions struct {
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Headers HTTPHeader `json:"headers,omitempty"`
|
Headers badoption.HTTPHeader `json:"headers,omitempty"`
|
||||||
MaxEarlyData uint32 `json:"max_early_data,omitempty"`
|
MaxEarlyData uint32 `json:"max_early_data,omitempty"`
|
||||||
EarlyDataHeaderName string `json:"early_data_header_name,omitempty"`
|
EarlyDataHeaderName string `json:"early_data_header_name,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -86,8 +87,8 @@ type V2RayQUICOptions struct{}
|
||||||
|
|
||||||
type V2RayGRPCOptions struct {
|
type V2RayGRPCOptions struct {
|
||||||
ServiceName string `json:"service_name,omitempty"`
|
ServiceName string `json:"service_name,omitempty"`
|
||||||
IdleTimeout Duration `json:"idle_timeout,omitempty"`
|
IdleTimeout badoption.Duration `json:"idle_timeout,omitempty"`
|
||||||
PingTimeout Duration `json:"ping_timeout,omitempty"`
|
PingTimeout badoption.Duration `json:"ping_timeout,omitempty"`
|
||||||
PermitWithoutStream bool `json:"permit_without_stream,omitempty"`
|
PermitWithoutStream bool `json:"permit_without_stream,omitempty"`
|
||||||
ForceLite bool `json:"-"` // for test
|
ForceLite bool `json:"-"` // for test
|
||||||
}
|
}
|
||||||
|
@ -95,5 +96,5 @@ type V2RayGRPCOptions struct {
|
||||||
type V2RayHTTPUpgradeOptions struct {
|
type V2RayHTTPUpgradeOptions struct {
|
||||||
Host string `json:"host,omitempty"`
|
Host string `json:"host,omitempty"`
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Headers HTTPHeader `json:"headers,omitempty"`
|
Headers badoption.HTTPHeader `json:"headers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import "net/netip"
|
import (
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
|
)
|
||||||
|
|
||||||
type WireGuardOutboundOptions struct {
|
type WireGuardOutboundOptions struct {
|
||||||
DialerOptions
|
DialerOptions
|
||||||
SystemInterface bool `json:"system_interface,omitempty"`
|
SystemInterface bool `json:"system_interface,omitempty"`
|
||||||
GSO bool `json:"gso,omitempty"`
|
GSO bool `json:"gso,omitempty"`
|
||||||
InterfaceName string `json:"interface_name,omitempty"`
|
InterfaceName string `json:"interface_name,omitempty"`
|
||||||
LocalAddress Listable[netip.Prefix] `json:"local_address"`
|
LocalAddress badoption.Listable[netip.Prefix] `json:"local_address"`
|
||||||
PrivateKey string `json:"private_key"`
|
PrivateKey string `json:"private_key"`
|
||||||
Peers []WireGuardPeer `json:"peers,omitempty"`
|
Peers []WireGuardPeer `json:"peers,omitempty"`
|
||||||
ServerOptions
|
ServerOptions
|
||||||
|
@ -23,6 +27,6 @@ type WireGuardPeer struct {
|
||||||
ServerOptions
|
ServerOptions
|
||||||
PublicKey string `json:"public_key,omitempty"`
|
PublicKey string `json:"public_key,omitempty"`
|
||||||
PreSharedKey string `json:"pre_shared_key,omitempty"`
|
PreSharedKey string `json:"pre_shared_key,omitempty"`
|
||||||
AllowedIPs Listable[string] `json:"allowed_ips,omitempty"`
|
AllowedIPs badoption.Listable[string] `json:"allowed_ips,omitempty"`
|
||||||
Reserved []uint8 `json:"reserved,omitempty"`
|
Reserved []uint8 `json:"reserved,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,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/json/badoption"
|
||||||
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/ranges"
|
"github.com/sagernet/sing/common/ranges"
|
||||||
|
@ -257,7 +258,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||||
return inbound, nil
|
return inbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func uidToRange(uidList option.Listable[uint32]) []ranges.Range[uint32] {
|
func uidToRange(uidList badoption.Listable[uint32]) []ranges.Range[uint32] {
|
||||||
return common.Map(uidList, func(uid uint32) ranges.Range[uint32] {
|
return common.Map(uidList, func(uid uint32) ranges.Range[uint32] {
|
||||||
return ranges.NewSingle(uid)
|
return ranges.NewSingle(uid)
|
||||||
})
|
})
|
||||||
|
|
|
@ -239,9 +239,9 @@ func NewRouter(
|
||||||
}
|
}
|
||||||
var clientSubnet netip.Prefix
|
var clientSubnet netip.Prefix
|
||||||
if server.ClientSubnet != nil {
|
if server.ClientSubnet != nil {
|
||||||
clientSubnet = server.ClientSubnet.Build()
|
clientSubnet = netip.Prefix(common.PtrValueOrDefault(server.ClientSubnet))
|
||||||
} else if dnsOptions.ClientSubnet != nil {
|
} else if dnsOptions.ClientSubnet != nil {
|
||||||
clientSubnet = dnsOptions.ClientSubnet.Build()
|
clientSubnet = netip.Prefix(common.PtrValueOrDefault(dnsOptions.ClientSubnet))
|
||||||
}
|
}
|
||||||
if serverProtocol == "" {
|
if serverProtocol == "" {
|
||||||
serverProtocol = "transport"
|
serverProtocol = "transport"
|
||||||
|
|
|
@ -88,13 +88,13 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
|
||||||
Server: action.RouteOptions.Server,
|
Server: action.RouteOptions.Server,
|
||||||
DisableCache: action.RouteOptions.DisableCache,
|
DisableCache: action.RouteOptions.DisableCache,
|
||||||
RewriteTTL: action.RouteOptions.RewriteTTL,
|
RewriteTTL: action.RouteOptions.RewriteTTL,
|
||||||
ClientSubnet: action.RouteOptions.ClientSubnet.Build(),
|
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)),
|
||||||
}
|
}
|
||||||
case C.RuleActionTypeRouteOptions:
|
case C.RuleActionTypeRouteOptions:
|
||||||
return &RuleActionDNSRouteOptions{
|
return &RuleActionDNSRouteOptions{
|
||||||
DisableCache: action.RouteOptionsOptions.DisableCache,
|
DisableCache: action.RouteOptionsOptions.DisableCache,
|
||||||
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
|
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
|
||||||
ClientSubnet: action.RouteOptionsOptions.ClientSubnet.Build(),
|
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptionsOptions.ClientSubnet)),
|
||||||
}
|
}
|
||||||
case C.RuleActionTypeReject:
|
case C.RuleActionTypeReject:
|
||||||
return &RuleActionReject{
|
return &RuleActionReject{
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/sagernet/sing-box/transport/v2ray"
|
"github.com/sagernet/sing-box/transport/v2ray"
|
||||||
"github.com/sagernet/sing-vmess"
|
"github.com/sagernet/sing-vmess"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json/badoption"
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
@ -67,7 +68,7 @@ func newV2RayPlugin(ctx context.Context, pluginOpts Args, router adapter.Router,
|
||||||
transportOptions = option.V2RayTransportOptions{
|
transportOptions = option.V2RayTransportOptions{
|
||||||
Type: C.V2RayTransportTypeWebsocket,
|
Type: C.V2RayTransportTypeWebsocket,
|
||||||
WebsocketOptions: option.V2RayWebsocketOptions{
|
WebsocketOptions: option.V2RayWebsocketOptions{
|
||||||
Headers: map[string]option.Listable[string]{
|
Headers: map[string]badoption.Listable[string]{
|
||||||
"Host": []string{host},
|
"Host": []string{host},
|
||||||
},
|
},
|
||||||
Path: path,
|
Path: path,
|
||||||
|
|
Loading…
Reference in a new issue