Migrate bad options to library

This commit is contained in:
世界 2024-11-07 21:44:04 +08:00
parent 85f634d0cb
commit 1a230bda5d
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
58 changed files with 579 additions and 877 deletions

View file

@ -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()

View file

@ -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 {

View file

@ -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 {

View file

@ -2,6 +2,7 @@ package listener
import ( import (
"net" "net"
"net/netip"
"os" "os"
"time" "time"
@ -13,7 +14,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 {

View file

@ -2,6 +2,7 @@ package deprecated
import ( import (
"context" "context"
"github.com/sagernet/sing/service" "github.com/sagernet/sing/service"
) )

View file

@ -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"`
@ -12,22 +16,22 @@ type DNSOptions struct {
} }
type DNSServerOptions struct { type DNSServerOptions struct {
Tag string `json:"tag,omitempty"` Tag string `json:"tag,omitempty"`
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 {
Strategy DomainStrategy `json:"strategy,omitempty"` Strategy DomainStrategy `json:"strategy,omitempty"`
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 {

View file

@ -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"`
@ -8,24 +10,24 @@ type ExperimentalOptions struct {
} }
type CacheFileOptions struct { type CacheFileOptions struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
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 {
ExternalController string `json:"external_controller,omitempty"` ExternalController string `json:"external_controller,omitempty"`
ExternalUI string `json:"external_ui,omitempty"` ExternalUI string `json:"external_ui,omitempty"`
ExternalUIDownloadURL string `json:"external_ui_download_url,omitempty"` ExternalUIDownloadURL string `json:"external_ui_download_url,omitempty"`
ExternalUIDownloadDetour string `json:"external_ui_download_detour,omitempty"` ExternalUIDownloadDetour string `json:"external_ui_download_detour,omitempty"`
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
CacheFile string `json:"cache_file,omitempty"` CacheFile string `json:"cache_file,omitempty"`

View 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"`
@ -7,10 +9,10 @@ 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"`
} }

View file

@ -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"
) )
@ -49,24 +50,24 @@ func (h *Inbound) UnmarshalJSONContext(ctx context.Context, content []byte) erro
// Deprecated: Use rule action instead // Deprecated: Use rule action instead
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"`
UDPFragmentDefault bool `json:"-"` UDPFragmentDefault bool `json:"-"`
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"` UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
// Deprecated: removed // Deprecated: removed
ProxyProtocol bool `json:"proxy_protocol,omitempty"` ProxyProtocol bool `json:"proxy_protocol,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 {

View file

@ -1,9 +1,11 @@
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
} }

View file

@ -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"
) )
@ -64,21 +65,21 @@ 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:"-"`
} }
func (o *DialerOptions) TakeDialerOptions() DialerOptions { func (o *DialerOptions) TakeDialerOptions() DialerOptions {

View file

@ -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"`
} }

View file

@ -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,39 +67,39 @@ 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"`
// Deprecated: renamed to rule_set_ip_cidr_match_source // Deprecated: renamed to rule_set_ip_cidr_match_source
Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"`

View file

@ -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
@ -197,9 +199,9 @@ 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 {

View file

@ -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,41 +68,41 @@ 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"`
// Deprecated: renamed to rule_set_ip_cidr_match_source // Deprecated: renamed to rule_set_ip_cidr_match_source
Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"` Deprecated_RulesetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"`

View file

@ -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"
) )
@ -84,9 +85,9 @@ 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,32 +146,32 @@ 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:"-"`
} }
func (r DefaultHeadlessRule) IsValid() bool { func (r DefaultHeadlessRule) IsValid() bool {

View file

@ -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
@ -30,6 +33,6 @@ type HTTPOutboundOptions struct {
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
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"`
} }

View file

@ -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"`
} }

View file

@ -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)
}

View file

@ -1,20 +1,22 @@
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"`
Reality *InboundRealityOptions `json:"reality,omitempty"` Reality *InboundRealityOptions `json:"reality,omitempty"`
} }
type InboundTLSOptionsContainer struct { type InboundTLSOptionsContainer struct {
@ -35,19 +37,19 @@ func (o *InboundTLSOptionsContainer) ReplaceInboundTLSOptions(options *InboundTL
} }
type OutboundTLSOptions struct { type OutboundTLSOptions struct {
Enabled bool `json:"enabled,omitempty"` Enabled bool `json:"enabled,omitempty"`
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"`
Reality *OutboundRealityOptions `json:"reality,omitempty"` Reality *OutboundRealityOptions `json:"reality,omitempty"`
} }
type OutboundTLSOptionsContainer struct { type OutboundTLSOptionsContainer struct {
@ -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 {
@ -81,19 +83,19 @@ type InboundRealityHandshakeOptions struct {
} }
type InboundECHOptions struct { 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"`
} }
type OutboundECHOptions struct { 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"`
} }
type OutboundUTLSOptions struct { type OutboundUTLSOptions struct {

View file

@ -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"`

View file

@ -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
} }
@ -19,13 +21,13 @@ type TUICUser struct {
type TUICOutboundOptions struct { type TUICOutboundOptions struct {
DialerOptions DialerOptions
ServerOptions ServerOptions
UUID string `json:"uuid,omitempty"` UUID string `json:"uuid,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
CongestionControl string `json:"congestion_control,omitempty"` CongestionControl string `json:"congestion_control,omitempty"`
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
} }

View file

@ -7,51 +7,52 @@ 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"`
AutoRedirect bool `json:"auto_redirect,omitempty"` AutoRedirect bool `json:"auto_redirect,omitempty"`
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"`
Platform *TunPlatformOptions `json:"platform,omitempty"` Platform *TunPlatformOptions `json:"platform,omitempty"`
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

View file

@ -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"`
} }

View file

@ -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
}

View file

@ -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,33 +68,33 @@ 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"`
} }
type V2RayQUICOptions struct{} 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
} }
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"`
} }

View file

@ -1,15 +1,19 @@
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
PeerPublicKey string `json:"peer_public_key"` PeerPublicKey string `json:"peer_public_key"`
PreSharedKey string `json:"pre_shared_key,omitempty"` PreSharedKey string `json:"pre_shared_key,omitempty"`
@ -21,8 +25,8 @@ type WireGuardOutboundOptions struct {
type WireGuardPeer struct { 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"`
} }

View file

@ -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)
}) })

View file

@ -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"

View file

@ -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{

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
) )
@ -15,13 +17,13 @@ func TestBrutalShadowsocks(t *testing.T) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -30,7 +32,7 @@ func TestBrutalShadowsocks(t *testing.T) {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Method: method, Method: method,
@ -100,13 +102,13 @@ func TestBrutalTrojan(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -115,7 +117,7 @@ func TestBrutalTrojan(t *testing.T) {
Type: C.TypeTrojan, Type: C.TypeTrojan,
TrojanOptions: option.TrojanInboundOptions{ TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TrojanUser{{Password: password}}, Users: []option.TrojanUser{{Password: password}},
@ -197,13 +199,13 @@ func TestBrutalTrojan(t *testing.T) {
func TestBrutalVMess(t *testing.T) { func TestBrutalVMess(t *testing.T) {
user, _ := uuid.NewV4() user, _ := uuid.NewV4()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -212,7 +214,7 @@ func TestBrutalVMess(t *testing.T) {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{{UUID: user.String()}}, Users: []option.VMessUser{{UUID: user.String()}},
@ -279,13 +281,13 @@ func TestBrutalVMess(t *testing.T) {
func TestBrutalVLESS(t *testing.T) { func TestBrutalVLESS(t *testing.T) {
user, _ := uuid.NewV4() user, _ := uuid.NewV4()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -294,7 +296,7 @@ func TestBrutalVLESS(t *testing.T) {
Type: C.TypeVLESS, Type: C.TypeVLESS,
VLESSOptions: option.VLESSInboundOptions{ VLESSOptions: option.VLESSInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VLESSUser{{UUID: user.String()}}, Users: []option.VLESSUser{{UUID: user.String()}},

View file

@ -6,18 +6,20 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
// Since this is a feature one-off added by outsiders, I won't address these anymore. // Since this is a feature one-off added by outsiders, I won't address these anymore.
func _TestProxyProtocol(t *testing.T) { func _TestProxyProtocol(t *testing.T) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -26,7 +28,7 @@ func _TestProxyProtocol(t *testing.T) {
Type: C.TypeDirect, Type: C.TypeDirect,
DirectOptions: option.DirectInboundOptions{ DirectOptions: option.DirectInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
ProxyProtocol: true, ProxyProtocol: true,
}, },

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
) )
@ -14,13 +16,13 @@ import (
func TestTUICDomainUDP(t *testing.T) { func TestTUICDomainUDP(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -29,7 +31,7 @@ func TestTUICDomainUDP(t *testing.T) {
Type: C.TypeTUIC, Type: C.TypeTUIC,
TUICOptions: option.TUICInboundOptions{ TUICOptions: option.TUICInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
InboundOptions: option.InboundOptions{ InboundOptions: option.InboundOptions{
DomainStrategy: option.DomainStrategy(dns.DomainStrategyUseIPv6), DomainStrategy: option.DomainStrategy(dns.DomainStrategyUseIPv6),

View file

@ -8,6 +8,7 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
) )
@ -16,13 +17,13 @@ func TestECH(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false)) echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false))
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -31,7 +32,7 @@ func TestECH(t *testing.T) {
Type: C.TypeTrojan, Type: C.TypeTrojan,
TrojanOptions: option.TrojanInboundOptions{ TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TrojanUser{ Users: []option.TrojanUser{
@ -109,13 +110,13 @@ func TestECHQUIC(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false)) echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false))
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -124,7 +125,7 @@ func TestECHQUIC(t *testing.T) {
Type: C.TypeTUIC, Type: C.TypeTUIC,
TUICOptions: option.TUICInboundOptions{ TUICOptions: option.TUICInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TUICUser{{ Users: []option.TUICUser{{
@ -199,13 +200,13 @@ func TestECHHysteria2(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false)) echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org", false))
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -214,7 +215,7 @@ func TestECHHysteria2(t *testing.T) {
Type: C.TypeHysteria2, Type: C.TypeHysteria2,
Hysteria2Options: option.Hysteria2InboundOptions{ Hysteria2Options: option.Hysteria2InboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.Hysteria2User{{ Users: []option.Hysteria2User{{

View file

@ -12,10 +12,10 @@ require (
github.com/docker/docker v27.3.1+incompatible github.com/docker/docker v27.3.1+incompatible
github.com/docker/go-connections v0.5.0 github.com/docker/go-connections v0.5.0
github.com/gofrs/uuid/v5 v5.3.0 github.com/gofrs/uuid/v5 v5.3.0
github.com/sagernet/quic-go v0.48.0-beta.1 github.com/sagernet/quic-go v0.48.1-beta.1
github.com/sagernet/sing v0.5.0-rc.4.0.20241022031908-cd17884118cb github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241021154031-a59e0fbba3ce github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab
github.com/sagernet/sing-quic v0.3.0-rc.1 github.com/sagernet/sing-quic v0.3.0-rc.2
github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks v0.2.7
github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/sagernet/sing-shadowsocks2 v0.2.0
github.com/spyzhov/ajson v0.9.4 github.com/spyzhov/ajson v0.9.4
@ -25,13 +25,11 @@ require (
) )
require ( require (
berty.tech/go-libtor v1.0.385 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/andybalholm/brotli v1.0.6 // indirect github.com/andybalholm/brotli v1.0.6 // indirect
github.com/caddyserver/certmagic v0.20.0 // indirect github.com/caddyserver/certmagic v0.20.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect github.com/cloudflare/circl v1.3.7 // indirect
github.com/containerd/log v0.1.0 // indirect github.com/containerd/log v0.1.0 // indirect
github.com/cretz/bine v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.5.0 // indirect github.com/distribution/reference v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect
@ -42,8 +40,6 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/btree v1.1.3 // indirect github.com/google/btree v1.1.3 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
@ -65,7 +61,6 @@ require (
github.com/moby/term v0.5.0 // indirect github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/onsi/ginkgo/v2 v2.9.7 // indirect
github.com/ooni/go-libtor v1.1.8 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect
@ -81,13 +76,10 @@ require (
github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec // indirect github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f // indirect
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241021153919-9ae45181180d // indirect
github.com/sagernet/sing-vmess v0.1.12 // indirect github.com/sagernet/sing-vmess v0.1.12 // indirect
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
github.com/sagernet/utls v1.6.7 // indirect github.com/sagernet/utls v1.6.7 // indirect
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
github.com/vishvananda/netns v0.0.4 // indirect github.com/vishvananda/netns v0.0.4 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect github.com/zeebo/blake3 v0.2.3 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect

View file

@ -1,5 +1,3 @@
berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
@ -14,9 +12,6 @@ github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vc
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -43,10 +38,6 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk= github.com/gofrs/uuid/v5 v5.3.0 h1:m0mUMr+oVYUdxpMLgSYCZiXe7PuVPnI94+OMeVBNedk=
github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gofrs/uuid/v5 v5.3.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@ -107,8 +98,6 @@ github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
github.com/ooni/go-libtor v1.1.8 h1:Wo3V3DVTxl5vZdxtQakqYP+DAHx7pPtAFSl1bnAa08w=
github.com/ooni/go-libtor v1.1.8/go.mod h1:q1YyLwRD9GeMyeerVvwc0vJ2YgwDLTp2bdVcrh/JXyI=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
@ -135,45 +124,37 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
github.com/sagernet/quic-go v0.48.0-beta.1 h1:86hQZrmuoARI3BpDRkQaP0iAVpywA4YsRrzJPYuPKWg= github.com/sagernet/quic-go v0.48.1-beta.1 h1:ElPaV5yzlXIKZpqFMAcUGax6vddi3zt4AEpT94Z0vwo=
github.com/sagernet/quic-go v0.48.0-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/+or9YMLaG5VeTk4k= github.com/sagernet/quic-go v0.48.1-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/+or9YMLaG5VeTk4k=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.5.0-rc.4.0.20241022031908-cd17884118cb h1:3IhGq2UmcbQfAcuqyE8RYKFapqEEa3eItS/MrZr+5l8= github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f h1:A6+OeV5P1mok0eEEbLh4PidymZ6VZnTZ2uHwfapXgdU=
github.com/sagernet/sing v0.5.0-rc.4.0.20241022031908-cd17884118cb/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.5.1-0.20241107131656-6e1285b5d82f/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241021154031-a59e0fbba3ce h1:OfpxE5qnXMyU/9LtNgX4M7bGP11lJx4s+KZ3Sijb0HE= github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab h1:djP4EY/KM5T62xscormLflVi7eDlHv6p7md1FHMSArE=
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241021154031-a59e0fbba3ce/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M= github.com/sagernet/sing-dns v0.3.1-0.20241105104342-1914f319ddab/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec h1:6Fd/VsEsw9qIjaGi1IBTZSb4b4v5JYtNcoiBtGsQC48= github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec h1:6Fd/VsEsw9qIjaGi1IBTZSb4b4v5JYtNcoiBtGsQC48=
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec/go.mod h1:RSwqqHwbtTOX3vs6ms8vMtBGH/0ZNyLm/uwt6TlmR84= github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec/go.mod h1:RSwqqHwbtTOX3vs6ms8vMtBGH/0ZNyLm/uwt6TlmR84=
github.com/sagernet/sing-quic v0.3.0-rc.1 h1:SlzL1yfEAKJyRduub8vzOVtbyTLAX7RZEEBZxO5utts= github.com/sagernet/sing-quic v0.3.0-rc.2 h1:7vcC4bdS1GBJzHZhfmJiH0CfzQ4mYLUW51Z2RNHcGwc=
github.com/sagernet/sing-quic v0.3.0-rc.1/go.mod h1:uX+aUHA0fgIN6U3WViseDpSdTQriViZ7qz0Wbsf1mNQ= github.com/sagernet/sing-quic v0.3.0-rc.2/go.mod h1:3UOq51WVqzra7eCgod7t4hqnTaOiZzFUci9avMrtOqs=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f h1:gQwTgN/E4oHe3VlseD3/RhPs866cWcTsPG4dP6a8f8o=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/sing-tun v0.4.0-rc.5.0.20241107062822-5a91eb99c90f/go.mod h1:Ehs5mZ3T8tTgV3H1Tx4Va5ixvyKjTAUPJ3G11dq7B/g=
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241021153919-9ae45181180d h1:zWcIQM3eAKJGzy7zhqkO7zm7ZI890OdR4vSwx2mevS0=
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241021153919-9ae45181180d/go.mod h1:Xhv+Mz2nE7HZTwResni8EtTa7AMJz/S6uQLT5lV23M8=
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg= github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I= github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8= github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM= github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs=
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8/go.mod h1:K4J7/npM+VAMUeUmTa2JaA02JmyheP0GpRBOUvn3ecc=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spyzhov/ajson v0.9.4 h1:MVibcTCgO7DY4IlskdqIlCmDOsUOZ9P7oKj8ifdcf84= github.com/spyzhov/ajson v0.9.4 h1:MVibcTCgO7DY4IlskdqIlCmDOsUOZ9P7oKj8ifdcf84=
github.com/spyzhov/ajson v0.9.4/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8= github.com/spyzhov/ajson v0.9.4/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
@ -211,10 +192,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
@ -227,8 +206,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -237,23 +214,15 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=

View file

@ -6,17 +6,19 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestHTTPSelf(t *testing.T) { func TestHTTPSelf(t *testing.T) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -25,7 +27,7 @@ func TestHTTPSelf(t *testing.T) {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
}, },

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-quic/hysteria2" "github.com/sagernet/sing-quic/hysteria2"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestHysteria2Self(t *testing.T) { func TestHysteria2Self(t *testing.T) {
@ -28,13 +30,13 @@ func testHysteria2Self(t *testing.T, salamanderPassword string) {
} }
} }
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -43,7 +45,7 @@ func testHysteria2Self(t *testing.T, salamanderPassword string) {
Type: C.TypeHysteria2, Type: C.TypeHysteria2,
Hysteria2Options: option.Hysteria2InboundOptions{ Hysteria2Options: option.Hysteria2InboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
UpMbps: 100, UpMbps: 100,
@ -115,12 +117,12 @@ func testHysteria2Self(t *testing.T, salamanderPassword string) {
func TestHysteria2Inbound(t *testing.T) { func TestHysteria2Inbound(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeHysteria2, Type: C.TypeHysteria2,
Hysteria2Options: option.Hysteria2InboundOptions{ Hysteria2Options: option.Hysteria2InboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Obfs: &option.Hysteria2Obfs{ Obfs: &option.Hysteria2Obfs{
@ -167,12 +169,12 @@ func TestHysteria2Outbound(t *testing.T) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -6,18 +6,20 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestHysteriaSelf(t *testing.T) { func TestHysteriaSelf(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -26,7 +28,7 @@ func TestHysteriaSelf(t *testing.T) {
Type: C.TypeHysteria, Type: C.TypeHysteria,
HysteriaOptions: option.HysteriaInboundOptions{ HysteriaOptions: option.HysteriaInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
UpMbps: 100, UpMbps: 100,
@ -98,12 +100,12 @@ func TestHysteriaSelf(t *testing.T) {
func TestHysteriaInbound(t *testing.T) { func TestHysteriaInbound(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeHysteria, Type: C.TypeHysteria,
HysteriaOptions: option.HysteriaInboundOptions{ HysteriaOptions: option.HysteriaInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
UpMbps: 100, UpMbps: 100,
@ -149,12 +151,12 @@ func TestHysteriaOutbound(t *testing.T) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -7,19 +7,21 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestChainedInbound(t *testing.T) { func TestChainedInbound(t *testing.T) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -28,9 +30,11 @@ func TestChainedInbound(t *testing.T) {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
Detour: "detour", InboundOptions: option.InboundOptions{
Detour: "detour",
},
}, },
Method: method, Method: method,
Password: password, Password: password,
@ -41,7 +45,7 @@ func TestChainedInbound(t *testing.T) {
Tag: "detour", Tag: "detour",
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: otherPort, ListenPort: otherPort,
}, },
Method: method, Method: method,

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/spyzhov/ajson" "github.com/spyzhov/ajson"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -37,12 +39,12 @@ func TestMuxCoolServer(t *testing.T) {
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{
@ -81,12 +83,12 @@ func TestMuxCoolClient(t *testing.T) {
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -112,13 +114,13 @@ func TestMuxCoolClient(t *testing.T) {
func TestMuxCoolSelf(t *testing.T) { func TestMuxCoolSelf(t *testing.T) {
user := newUUID() user := newUUID()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -127,7 +129,7 @@ func TestMuxCoolSelf(t *testing.T) {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
) )
@ -55,13 +57,13 @@ func testShadowsocksMux(t *testing.T, options option.OutboundMultiplexOptions) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -70,7 +72,7 @@ func testShadowsocksMux(t *testing.T, options option.OutboundMultiplexOptions) {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Method: method, Method: method,
@ -125,13 +127,13 @@ func testShadowsocksMux(t *testing.T, options option.OutboundMultiplexOptions) {
func testVMessMux(t *testing.T, options option.OutboundMultiplexOptions) { func testVMessMux(t *testing.T, options option.OutboundMultiplexOptions) {
user, _ := uuid.NewV4() user, _ := uuid.NewV4()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -140,7 +142,7 @@ func testVMessMux(t *testing.T, options option.OutboundMultiplexOptions) {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{

View file

@ -6,19 +6,21 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth" "github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/json/badoption"
"github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/network"
) )
func TestNaiveInboundWithNginx(t *testing.T) { func TestNaiveInboundWithNginx(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeNaive, Type: C.TypeNaive,
NaiveOptions: option.NaiveInboundOptions{ NaiveOptions: option.NaiveInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: otherPort, ListenPort: otherPort,
}, },
Users: []auth.User{ Users: []auth.User{
@ -59,12 +61,12 @@ func TestNaiveInboundWithNginx(t *testing.T) {
func TestNaiveInbound(t *testing.T) { func TestNaiveInbound(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeNaive, Type: C.TypeNaive,
NaiveOptions: option.NaiveInboundOptions{ NaiveOptions: option.NaiveInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []auth.User{ Users: []auth.User{
@ -103,12 +105,12 @@ func TestNaiveInbound(t *testing.T) {
func TestNaiveHTTP3Inbound(t *testing.T) { func TestNaiveHTTP3Inbound(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeNaive, Type: C.TypeNaive,
NaiveOptions: option.NaiveInboundOptions{ NaiveOptions: option.NaiveInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []auth.User{ Users: []auth.User{

View file

@ -7,7 +7,9 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks2/shadowstream" "github.com/sagernet/sing-shadowsocks2/shadowstream"
"github.com/sagernet/sing/common"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestShadowsocksLegacy(t *testing.T) { func TestShadowsocksLegacy(t *testing.T) {
@ -24,12 +26,12 @@ func testShadowsocksLegacy(t *testing.T, method string) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -9,7 +9,9 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/sagernet/sing/common"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json/badoption"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -99,12 +101,12 @@ func testShadowsocksInboundWithShadowsocksRust(t *testing.T, method string, pass
Cmd: []string{"-s", F.ToString("127.0.0.1:", serverPort), "-b", F.ToString("0.0.0.0:", clientPort), "-m", method, "-k", password, "-U"}, Cmd: []string{"-s", F.ToString("127.0.0.1:", serverPort), "-b", F.ToString("0.0.0.0:", clientPort), "-m", method, "-k", password, "-U"},
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Method: method, Method: method,
@ -124,12 +126,12 @@ func testShadowsocksOutboundWithShadowsocksRust(t *testing.T, method string, pas
Cmd: []string{"-s", F.ToString("0.0.0.0:", serverPort), "-m", method, "-k", password, "-U"}, Cmd: []string{"-s", F.ToString("0.0.0.0:", serverPort), "-m", method, "-k", password, "-U"},
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -154,13 +156,13 @@ func testShadowsocksOutboundWithShadowsocksRust(t *testing.T, method string, pas
func testShadowsocksSelf(t *testing.T, method string, password string) { func testShadowsocksSelf(t *testing.T, method string, password string) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -169,7 +171,7 @@ func testShadowsocksSelf(t *testing.T, method string, password string) {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Method: method, Method: method,
@ -221,13 +223,13 @@ func TestShadowsocksUoT(t *testing.T) {
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -236,7 +238,7 @@ func TestShadowsocksUoT(t *testing.T) {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Method: method, Method: method,
@ -289,13 +291,13 @@ func TestShadowsocksUoT(t *testing.T) {
func testShadowsocks2022EIH(t *testing.T, method string, password string) { func testShadowsocks2022EIH(t *testing.T, method string, password string) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -304,7 +306,7 @@ func testShadowsocks2022EIH(t *testing.T, method string, password string) {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Method: method, Method: method,

View file

@ -10,7 +10,9 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022" "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/sagernet/sing/common"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json/badoption"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -37,12 +39,12 @@ func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool)
method := shadowaead_2022.List[0] method := shadowaead_2022.List[0]
ssPassword := mkBase64(t, 16) ssPassword := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -52,9 +54,12 @@ func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool)
Tag: "in", Tag: "in",
ShadowTLSOptions: option.ShadowTLSInboundOptions{ ShadowTLSOptions: option.ShadowTLSInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
Detour: "detour",
InboundOptions: option.InboundOptions{
Detour: "detour",
},
}, },
Handshake: option.ShadowTLSHandshakeOptions{ Handshake: option.ShadowTLSHandshakeOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
@ -72,7 +77,7 @@ func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool)
Tag: "detour", Tag: "detour",
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: otherPort, ListenPort: otherPort,
}, },
Method: method, Method: method,
@ -142,12 +147,12 @@ func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool)
func TestShadowTLSFallback(t *testing.T) { func TestShadowTLSFallback(t *testing.T) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeShadowTLS, Type: C.TypeShadowTLS,
ShadowTLSOptions: option.ShadowTLSInboundOptions{ ShadowTLSOptions: option.ShadowTLSInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Handshake: option.ShadowTLSHandshakeOptions{ Handshake: option.ShadowTLSHandshakeOptions{
@ -189,13 +194,13 @@ func TestShadowTLSInbound(t *testing.T) {
Cmd: []string{"--v3", "--threads", "1", "client", "--listen", "0.0.0.0:" + F.ToString(otherPort), "--server", "127.0.0.1:" + F.ToString(serverPort), "--sni", "google.com", "--password", password}, Cmd: []string{"--v3", "--threads", "1", "client", "--listen", "0.0.0.0:" + F.ToString(otherPort), "--server", "127.0.0.1:" + F.ToString(serverPort), "--sni", "google.com", "--password", password},
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "in", Tag: "in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -204,9 +209,11 @@ func TestShadowTLSInbound(t *testing.T) {
Type: C.TypeShadowTLS, Type: C.TypeShadowTLS,
ShadowTLSOptions: option.ShadowTLSInboundOptions{ ShadowTLSOptions: option.ShadowTLSInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
Detour: "detour", InboundOptions: option.InboundOptions{
Detour: "detour",
},
}, },
Handshake: option.ShadowTLSHandshakeOptions{ Handshake: option.ShadowTLSHandshakeOptions{
ServerOptions: option.ServerOptions{ ServerOptions: option.ServerOptions{
@ -225,7 +232,7 @@ func TestShadowTLSInbound(t *testing.T) {
Tag: "detour", Tag: "detour",
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
}, },
Method: method, Method: method,
Password: password, Password: password,
@ -283,12 +290,12 @@ func TestShadowTLSOutbound(t *testing.T) {
Env: []string{"RUST_LOG=trace"}, Env: []string{"RUST_LOG=trace"},
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -298,7 +305,7 @@ func TestShadowTLSOutbound(t *testing.T) {
Tag: "detour", Tag: "detour",
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: otherPort, ListenPort: otherPort,
}, },
Method: method, Method: method,

View file

@ -6,6 +6,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestShadowsocksObfs(t *testing.T) { func TestShadowsocksObfs(t *testing.T) {
@ -33,12 +35,12 @@ func testShadowsocksPlugin(t *testing.T, name string, opts string, args string)
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -7,19 +7,21 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-shadowsocks/shadowaead" "github.com/sagernet/sing-shadowsocks/shadowaead"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestTCPSlowOpen(t *testing.T) { func TestTCPSlowOpen(t *testing.T) {
method := shadowaead.List[0] method := shadowaead.List[0]
password := mkBase64(t, 16) password := mkBase64(t, 16)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -28,7 +30,7 @@ func TestTCPSlowOpen(t *testing.T) {
Type: C.TypeShadowsocks, Type: C.TypeShadowsocks,
ShadowsocksOptions: option.ShadowsocksInboundOptions{ ShadowsocksOptions: option.ShadowsocksInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
TCPFastOpen: true, TCPFastOpen: true,
}, },

View file

@ -6,18 +6,20 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestUTLS(t *testing.T) { func TestUTLS(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -26,7 +28,7 @@ func TestUTLS(t *testing.T) {
Type: C.TypeTrojan, Type: C.TypeTrojan,
TrojanOptions: option.TrojanInboundOptions{ TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TrojanUser{ Users: []option.TrojanUser{

View file

@ -6,6 +6,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func TestTrojanOutbound(t *testing.T) { func TestTrojanOutbound(t *testing.T) {
@ -20,12 +22,12 @@ func TestTrojanOutbound(t *testing.T) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -57,13 +59,13 @@ func TestTrojanOutbound(t *testing.T) {
func TestTrojanSelf(t *testing.T) { func TestTrojanSelf(t *testing.T) {
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -72,7 +74,7 @@ func TestTrojanSelf(t *testing.T) {
Type: C.TypeTrojan, Type: C.TypeTrojan,
TrojanOptions: option.TrojanInboundOptions{ TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TrojanUser{ Users: []option.TrojanUser{
@ -140,13 +142,13 @@ func TestTrojanSelf(t *testing.T) {
func TestTrojanPlainSelf(t *testing.T) { func TestTrojanPlainSelf(t *testing.T) {
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -155,7 +157,7 @@ func TestTrojanPlainSelf(t *testing.T) {
Type: C.TypeTrojan, Type: C.TypeTrojan,
TrojanOptions: option.TrojanInboundOptions{ TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TrojanUser{ Users: []option.TrojanUser{

View file

@ -6,6 +6,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
) )
@ -29,13 +31,13 @@ func testTUICSelf(t *testing.T, udpStream bool, zeroRTTHandshake bool) {
udpRelayMode = "quic" udpRelayMode = "quic"
} }
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -44,7 +46,7 @@ func testTUICSelf(t *testing.T, udpStream bool, zeroRTTHandshake bool) {
Type: C.TypeTUIC, Type: C.TypeTUIC,
TUICOptions: option.TUICInboundOptions{ TUICOptions: option.TUICInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TUICUser{{ Users: []option.TUICUser{{
@ -113,12 +115,12 @@ func testTUICSelf(t *testing.T, udpStream bool, zeroRTTHandshake bool) {
func TestTUICInbound(t *testing.T) { func TestTUICInbound(t *testing.T) {
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeTUIC, Type: C.TypeTUIC,
TUICOptions: option.TUICInboundOptions{ TUICOptions: option.TUICInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TUICUser{{ Users: []option.TUICUser{{
@ -160,12 +162,12 @@ func TestTUICOutbound(t *testing.T) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -8,19 +8,21 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/experimental/v2rayapi" "github.com/sagernet/sing-box/experimental/v2rayapi"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestV2RayAPI(t *testing.T) { func TestV2RayAPI(t *testing.T) {
i := startInstance(t, option.Options{ i := startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "in", Tag: "in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
"github.com/spyzhov/ajson" "github.com/spyzhov/ajson"
@ -27,12 +29,12 @@ func testV2RayGRPCInbound(t *testing.T, forceLite bool) {
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{
@ -126,13 +128,13 @@ func testV2RayGRPCOutbound(t *testing.T, forceLite bool) {
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -6,6 +6,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -44,13 +46,13 @@ func testVMessTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -59,7 +61,7 @@ func testVMessTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{
@ -133,13 +135,13 @@ func testTrojanTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -148,7 +150,7 @@ func testTrojanTransportSelf(t *testing.T, server *option.V2RayTransportOptions,
Type: C.TypeTrojan, Type: C.TypeTrojan,
TrojanOptions: option.TrojanInboundOptions{ TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.TrojanUser{ Users: []option.TrojanUser{
@ -224,13 +226,13 @@ func TestVMessQUICSelf(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -239,7 +241,7 @@ func TestVMessQUICSelf(t *testing.T) {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{
@ -312,13 +314,13 @@ func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportO
user, err := uuid.DefaultGenerator.NewV4() user, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err) require.NoError(t, err)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -327,7 +329,7 @@ func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportO
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
"github.com/spyzhov/ajson" "github.com/spyzhov/ajson"
@ -61,12 +63,12 @@ func testV2RayWebsocketInbound(t *testing.T, maxEarlyData uint32, earlyDataHeade
require.NoError(t, err) require.NoError(t, err)
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{
@ -158,13 +160,13 @@ func testV2RayWebsocketOutbound(t *testing.T, maxEarlyData uint32, earlyDataHead
}, },
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
"github.com/gofrs/uuid/v5" "github.com/gofrs/uuid/v5"
"github.com/spyzhov/ajson" "github.com/spyzhov/ajson"
@ -181,12 +183,12 @@ func testVMessInboundWithV2Ray(t *testing.T, security string, alterId int, authe
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{
@ -229,12 +231,12 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, globalPadding boo
}) })
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -263,13 +265,13 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, globalPadding boo
func testVMessSelf(t *testing.T, security string, alterId int, globalPadding bool, authenticatedLength bool, packetAddr bool) { func testVMessSelf(t *testing.T, security string, alterId int, globalPadding bool, authenticatedLength bool, packetAddr bool) {
user := newUUID() user := newUUID()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
Tag: "mixed-in", Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },
@ -278,7 +280,7 @@ func testVMessSelf(t *testing.T, security string, alterId int, globalPadding boo
Type: C.TypeVMess, Type: C.TypeVMess,
VMessOptions: option.VMessInboundOptions{ VMessOptions: option.VMessInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: serverPort, ListenPort: serverPort,
}, },
Users: []option.VMessUser{ Users: []option.VMessUser{

View file

@ -7,6 +7,8 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badoption"
) )
func _TestWireGuard(t *testing.T) { func _TestWireGuard(t *testing.T) {
@ -21,12 +23,12 @@ func _TestWireGuard(t *testing.T) {
}) })
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.LegacyInbound{ LegacyInbounds: []option.LegacyInbound{
{ {
Type: C.TypeMixed, Type: C.TypeMixed,
MixedOptions: option.HTTPMixedInboundOptions{ MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{ ListenOptions: option.ListenOptions{
Listen: option.NewListenAddress(netip.IPv4Unspecified()), Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
ListenPort: clientPort, ListenPort: clientPort,
}, },
}, },

View file

@ -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,