mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-01-31 05:06:58 +00:00
refactor: Outbound domain resolver
This commit is contained in:
parent
0909369edd
commit
19d1dd09b8
|
@ -28,12 +28,14 @@ type NetworkManager interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetworkOptions struct {
|
type NetworkOptions struct {
|
||||||
|
BindInterface string
|
||||||
|
RoutingMark uint32
|
||||||
|
DomainResolver string
|
||||||
|
DomainResolveOptions DNSQueryOptions
|
||||||
NetworkStrategy *C.NetworkStrategy
|
NetworkStrategy *C.NetworkStrategy
|
||||||
NetworkType []C.InterfaceType
|
NetworkType []C.InterfaceType
|
||||||
FallbackNetworkType []C.InterfaceType
|
FallbackNetworkType []C.InterfaceType
|
||||||
FallbackDelay time.Duration
|
FallbackDelay time.Duration
|
||||||
BindInterface string
|
|
||||||
RoutingMark uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type InterfaceUpdateListener interface {
|
type InterfaceUpdateListener interface {
|
||||||
|
|
2
box.go
2
box.go
|
@ -309,7 +309,7 @@ func New(options Options) (*Box, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ntpOptions.Enabled {
|
if ntpOptions.Enabled {
|
||||||
ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions)
|
ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions, ntpOptions.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "create NTP service")
|
return nil, E.Cause(err, "create NTP service")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
@ -15,7 +16,7 @@ import (
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
|
func New(ctx context.Context, options option.DialerOptions, remoteIsDomain bool) (N.Dialer, error) {
|
||||||
if options.IsWireGuardListener {
|
if options.IsWireGuardListener {
|
||||||
return NewDefault(ctx, options)
|
return NewDefault(ctx, options)
|
||||||
}
|
}
|
||||||
|
@ -23,50 +24,71 @@ func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if options.Detour == "" {
|
if options.Detour != "" {
|
||||||
dialer, err = NewDefault(ctx, options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
outboundManager := service.FromContext[adapter.OutboundManager](ctx)
|
outboundManager := service.FromContext[adapter.OutboundManager](ctx)
|
||||||
if outboundManager == nil {
|
if outboundManager == nil {
|
||||||
return nil, E.New("missing outbound manager")
|
return nil, E.New("missing outbound manager")
|
||||||
}
|
}
|
||||||
dialer = NewDetour(outboundManager, options.Detour)
|
dialer = NewDetour(outboundManager, options.Detour)
|
||||||
}
|
} else {
|
||||||
if options.Detour == "" {
|
dialer, err = NewDefault(ctx, options)
|
||||||
router := service.FromContext[adapter.DNSRouter](ctx)
|
|
||||||
if router != nil {
|
|
||||||
dialer = NewResolveDialer(
|
|
||||||
router,
|
|
||||||
dialer,
|
|
||||||
options.Detour == "" && !options.TCPFastOpen,
|
|
||||||
C.DomainStrategy(options.DomainStrategy),
|
|
||||||
time.Duration(options.FallbackDelay))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dialer, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInterfaceDialer, error) {
|
|
||||||
if options.Detour != "" {
|
|
||||||
return nil, E.New("`detour` is not supported in direct context")
|
|
||||||
}
|
|
||||||
if options.IsWireGuardListener {
|
|
||||||
return NewDefault(ctx, options)
|
|
||||||
}
|
|
||||||
dialer, err := NewDefault(ctx, options)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewResolveParallelInterfaceDialer(
|
}
|
||||||
service.FromContext[adapter.DNSRouter](ctx),
|
if remoteIsDomain && options.Detour == "" {
|
||||||
|
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
||||||
|
dnsTransport := service.FromContext[adapter.DNSTransportManager](ctx)
|
||||||
|
var defaultOptions adapter.NetworkOptions
|
||||||
|
if networkManager != nil {
|
||||||
|
defaultOptions = networkManager.DefaultOptions()
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
dnsQueryOptions adapter.DNSQueryOptions
|
||||||
|
resolveFallbackDelay time.Duration
|
||||||
|
)
|
||||||
|
if options.DomainResolver != nil && options.DomainResolver.Server != "" {
|
||||||
|
transport, loaded := dnsTransport.Transport(options.DomainResolver.Server)
|
||||||
|
if !loaded {
|
||||||
|
return nil, E.New("domain resolver not found: " + options.DomainResolver.Server)
|
||||||
|
}
|
||||||
|
var strategy C.DomainStrategy
|
||||||
|
if options.DomainResolver.Strategy != option.DomainStrategy(C.DomainStrategyAsIS) {
|
||||||
|
strategy = C.DomainStrategy(options.DomainResolver.Strategy)
|
||||||
|
} else if
|
||||||
|
//nolint:staticcheck
|
||||||
|
options.DomainStrategy != option.DomainStrategy(C.DomainStrategyAsIS) {
|
||||||
|
//nolint:staticcheck
|
||||||
|
strategy = C.DomainStrategy(options.DomainStrategy)
|
||||||
|
}
|
||||||
|
dnsQueryOptions = adapter.DNSQueryOptions{
|
||||||
|
Transport: transport,
|
||||||
|
Strategy: strategy,
|
||||||
|
DisableCache: options.DomainResolver.DisableCache,
|
||||||
|
RewriteTTL: options.DomainResolver.RewriteTTL,
|
||||||
|
ClientSubnet: options.DomainResolver.ClientSubnet.Build(netip.Prefix{}),
|
||||||
|
}
|
||||||
|
resolveFallbackDelay = time.Duration(options.FallbackDelay)
|
||||||
|
} else if defaultOptions.DomainResolver != "" {
|
||||||
|
dnsQueryOptions = defaultOptions.DomainResolveOptions
|
||||||
|
transport, loaded := dnsTransport.Transport(defaultOptions.DomainResolver)
|
||||||
|
if !loaded {
|
||||||
|
return nil, E.New("default domain resolver not found: " + defaultOptions.DomainResolver)
|
||||||
|
}
|
||||||
|
dnsQueryOptions.Transport = transport
|
||||||
|
resolveFallbackDelay = time.Duration(options.FallbackDelay)
|
||||||
|
} else {
|
||||||
|
deprecated.Report(ctx, deprecated.OptionMissingDomainResolver)
|
||||||
|
}
|
||||||
|
dialer = NewResolveDialer(
|
||||||
|
ctx,
|
||||||
dialer,
|
dialer,
|
||||||
true,
|
options.Detour == "" && !options.TCPFastOpen,
|
||||||
C.DomainStrategy(options.DomainStrategy),
|
dnsQueryOptions,
|
||||||
time.Duration(options.FallbackDelay),
|
resolveFallbackDelay,
|
||||||
), nil
|
)
|
||||||
|
}
|
||||||
|
return dialer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParallelInterfaceDialer interface {
|
type ParallelInterfaceDialer interface {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
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/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -18,20 +19,30 @@ var (
|
||||||
_ ParallelInterfaceDialer = (*resolveParallelNetworkDialer)(nil)
|
_ ParallelInterfaceDialer = (*resolveParallelNetworkDialer)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ResolveDialer interface {
|
||||||
|
N.Dialer
|
||||||
|
QueryOptions() adapter.DNSQueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParallelInterfaceResolveDialer interface {
|
||||||
|
ParallelInterfaceDialer
|
||||||
|
QueryOptions() adapter.DNSQueryOptions
|
||||||
|
}
|
||||||
|
|
||||||
type resolveDialer struct {
|
type resolveDialer struct {
|
||||||
|
router adapter.DNSRouter
|
||||||
dialer N.Dialer
|
dialer N.Dialer
|
||||||
parallel bool
|
parallel bool
|
||||||
router adapter.DNSRouter
|
queryOptions adapter.DNSQueryOptions
|
||||||
strategy C.DomainStrategy
|
|
||||||
fallbackDelay time.Duration
|
fallbackDelay time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResolveDialer(router adapter.DNSRouter, dialer N.Dialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) N.Dialer {
|
func NewResolveDialer(ctx context.Context, dialer N.Dialer, parallel bool, queryOptions adapter.DNSQueryOptions, fallbackDelay time.Duration) ResolveDialer {
|
||||||
return &resolveDialer{
|
return &resolveDialer{
|
||||||
|
service.FromContext[adapter.DNSRouter](ctx),
|
||||||
dialer,
|
dialer,
|
||||||
parallel,
|
parallel,
|
||||||
router,
|
queryOptions,
|
||||||
strategy,
|
|
||||||
fallbackDelay,
|
fallbackDelay,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,13 +52,13 @@ type resolveParallelNetworkDialer struct {
|
||||||
dialer ParallelInterfaceDialer
|
dialer ParallelInterfaceDialer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResolveParallelInterfaceDialer(router adapter.DNSRouter, dialer ParallelInterfaceDialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer {
|
func NewResolveParallelInterfaceDialer(ctx context.Context, dialer ParallelInterfaceDialer, parallel bool, queryOptions adapter.DNSQueryOptions, fallbackDelay time.Duration) ParallelInterfaceResolveDialer {
|
||||||
return &resolveParallelNetworkDialer{
|
return &resolveParallelNetworkDialer{
|
||||||
resolveDialer{
|
resolveDialer{
|
||||||
|
service.FromContext[adapter.DNSRouter](ctx),
|
||||||
dialer,
|
dialer,
|
||||||
parallel,
|
parallel,
|
||||||
router,
|
queryOptions,
|
||||||
strategy,
|
|
||||||
fallbackDelay,
|
fallbackDelay,
|
||||||
},
|
},
|
||||||
dialer,
|
dialer,
|
||||||
|
@ -59,12 +70,12 @@ func (d *resolveDialer) DialContext(ctx context.Context, network string, destina
|
||||||
return d.dialer.DialContext(ctx, network, destination)
|
return d.dialer.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy})
|
addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if d.parallel {
|
if d.parallel {
|
||||||
return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay)
|
return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.queryOptions.Strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay)
|
||||||
} else {
|
} else {
|
||||||
return N.DialSerial(ctx, d.dialer, network, destination, addresses)
|
return N.DialSerial(ctx, d.dialer, network, destination, addresses)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +86,7 @@ func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd
|
||||||
return d.dialer.ListenPacket(ctx, destination)
|
return d.dialer.ListenPacket(ctx, destination)
|
||||||
}
|
}
|
||||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy})
|
addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -86,14 +97,20 @@ func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd
|
||||||
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
|
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *resolveDialer) QueryOptions() adapter.DNSQueryOptions {
|
||||||
|
return d.queryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *resolveDialer) Upstream() any {
|
||||||
|
return d.dialer
|
||||||
|
}
|
||||||
|
|
||||||
func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
|
func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
|
||||||
if !destination.IsFqdn() {
|
if !destination.IsFqdn() {
|
||||||
return d.dialer.DialContext(ctx, network, destination)
|
return d.dialer.DialContext(ctx, network, destination)
|
||||||
}
|
}
|
||||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{
|
addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions)
|
||||||
Strategy: d.strategy,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -101,7 +118,7 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context
|
||||||
fallbackDelay = d.fallbackDelay
|
fallbackDelay = d.fallbackDelay
|
||||||
}
|
}
|
||||||
if d.parallel {
|
if d.parallel {
|
||||||
return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.queryOptions.Strategy == C.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||||
} else {
|
} else {
|
||||||
return DialSerialNetwork(ctx, d.dialer, network, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
return DialSerialNetwork(ctx, d.dialer, network, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||||
}
|
}
|
||||||
|
@ -112,10 +129,13 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C
|
||||||
return d.dialer.ListenPacket(ctx, destination)
|
return d.dialer.ListenPacket(ctx, destination)
|
||||||
}
|
}
|
||||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy})
|
addresses, err := d.router.Lookup(ctx, destination.Fqdn, d.queryOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if fallbackDelay == 0 {
|
||||||
|
fallbackDelay = d.fallbackDelay
|
||||||
|
}
|
||||||
conn, destinationAddress, err := ListenSerialNetworkPacket(ctx, d.dialer, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
conn, destinationAddress, err := ListenSerialNetworkPacket(ctx, d.dialer, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -123,6 +143,10 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C
|
||||||
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
|
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *resolveDialer) Upstream() any {
|
func (d *resolveParallelNetworkDialer) QueryOptions() adapter.DNSQueryOptions {
|
||||||
|
return d.queryOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *resolveParallelNetworkDialer) Upstream() any {
|
||||||
return d.dialer
|
return d.dialer
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ func NewRealityServer(ctx context.Context, logger log.Logger, options option.Inb
|
||||||
tlsConfig.ShortIds[shortID] = true
|
tlsConfig.ShortIds[shortID] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
handshakeDialer, err := dialer.New(ctx, options.Reality.Handshake.DialerOptions)
|
handshakeDialer, err := dialer.New(ctx, options.Reality.Handshake.DialerOptions, options.Reality.Handshake.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,20 @@ func NewLocalDialer(ctx context.Context, options option.LocalDNSServerOptions) (
|
||||||
if options.LegacyDefaultDialer {
|
if options.LegacyDefaultDialer {
|
||||||
return dialer.NewDefaultOutbound(ctx), nil
|
return dialer.NewDefaultOutbound(ctx), nil
|
||||||
} else {
|
} else {
|
||||||
return dialer.New(ctx, options.DialerOptions)
|
return dialer.New(ctx, options.DialerOptions, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions) (N.Dialer, error) {
|
func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions) (N.Dialer, error) {
|
||||||
transportDialer, err := NewLocalDialer(ctx, options.LocalDNSServerOptions)
|
var (
|
||||||
|
transportDialer N.Dialer
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if options.LegacyDefaultDialer {
|
||||||
|
transportDialer = dialer.NewDefaultOutbound(ctx)
|
||||||
|
} else {
|
||||||
|
transportDialer, err = dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -35,7 +43,7 @@ func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions)
|
||||||
return nil, E.New("address resolver not found: ", options.AddressResolver)
|
return nil, E.New("address resolver not found: ", options.AddressResolver)
|
||||||
}
|
}
|
||||||
transportDialer = NewTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.AddressStrategy), time.Duration(options.AddressFallbackDelay))
|
transportDialer = NewTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.AddressStrategy), time.Duration(options.AddressFallbackDelay))
|
||||||
} else if M.IsDomainName(options.Server) {
|
} else if options.ServerIsDomain() {
|
||||||
return nil, E.New("missing address resolver for server: ", options.Server)
|
return nil, E.New("missing address resolver for server: ", options.Server)
|
||||||
}
|
}
|
||||||
return transportDialer, nil
|
return transportDialer, nil
|
||||||
|
|
|
@ -161,6 +161,20 @@ var OptionLegacyDNSFakeIPOptions = Note{
|
||||||
ScheduledVersion: "1.14.0",
|
ScheduledVersion: "1.14.0",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var OptionOutboundDNSRuleItem = Note{
|
||||||
|
Name: "outbound-dns-rule-item",
|
||||||
|
Description: "outbound DNS rule item",
|
||||||
|
DeprecatedVersion: "1.12.0",
|
||||||
|
ScheduledVersion: "1.14.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
var OptionMissingDomainResolver = Note{
|
||||||
|
Name: "missing-domain-resolver",
|
||||||
|
Description: "missing `route.default_domain_resolver` or `domain_resolver` in dial fields",
|
||||||
|
DeprecatedVersion: "1.12.0",
|
||||||
|
ScheduledVersion: "1.14.0",
|
||||||
|
}
|
||||||
|
|
||||||
var Options = []Note{
|
var Options = []Note{
|
||||||
OptionBadMatchSource,
|
OptionBadMatchSource,
|
||||||
OptionGEOIP,
|
OptionGEOIP,
|
||||||
|
@ -172,4 +186,8 @@ var Options = []Note{
|
||||||
OptionWireGuardOutbound,
|
OptionWireGuardOutbound,
|
||||||
OptionWireGuardGSO,
|
OptionWireGuardGSO,
|
||||||
OptionTUNGSO,
|
OptionTUNGSO,
|
||||||
|
OptionLegacyDNSTransport,
|
||||||
|
OptionLegacyDNSFakeIPOptions,
|
||||||
|
OptionOutboundDNSRuleItem,
|
||||||
|
OptionMissingDomainResolver,
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,12 +77,46 @@ type DialerOptions struct {
|
||||||
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"`
|
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
|
||||||
NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
|
NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
|
||||||
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
||||||
FallbackNetworkType badoption.Listable[InterfaceType] `json:"fallback_network_type,omitempty"`
|
FallbackNetworkType badoption.Listable[InterfaceType] `json:"fallback_network_type,omitempty"`
|
||||||
FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"`
|
FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"`
|
||||||
IsWireGuardListener bool `json:"-"`
|
IsWireGuardListener bool `json:"-"`
|
||||||
|
|
||||||
|
// Deprecated: migrated to domain resolver
|
||||||
|
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type _DomainResolveOptions struct {
|
||||||
|
Server string `json:"server"`
|
||||||
|
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||||
|
DisableCache bool `json:"disable_cache,omitempty"`
|
||||||
|
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||||
|
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainResolveOptions _DomainResolveOptions
|
||||||
|
|
||||||
|
func (o DomainResolveOptions) MarshalJSON() ([]byte, error) {
|
||||||
|
if o.Strategy == DomainStrategy(C.DomainStrategyAsIS) &&
|
||||||
|
!o.DisableCache &&
|
||||||
|
o.RewriteTTL == nil &&
|
||||||
|
o.ClientSubnet == nil {
|
||||||
|
return json.Marshal(o.Server)
|
||||||
|
} else {
|
||||||
|
return json.Marshal((_DomainResolveOptions)(o))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DomainResolveOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
|
var stringValue string
|
||||||
|
err := json.Unmarshal(bytes, &stringValue)
|
||||||
|
if err == nil {
|
||||||
|
o.Server = stringValue
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return json.Unmarshal(bytes, (*_DomainResolveOptions)(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *DialerOptions) TakeDialerOptions() DialerOptions {
|
func (o *DialerOptions) TakeDialerOptions() DialerOptions {
|
||||||
|
@ -107,6 +141,10 @@ func (o ServerOptions) Build() M.Socksaddr {
|
||||||
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
|
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o ServerOptions) ServerIsDomain() bool {
|
||||||
|
return M.IsDomainName(o.Server)
|
||||||
|
}
|
||||||
|
|
||||||
func (o *ServerOptions) TakeServerOptions() ServerOptions {
|
func (o *ServerOptions) TakeServerOptions() ServerOptions {
|
||||||
return *o
|
return *o
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ type RouteOptions struct {
|
||||||
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
|
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
|
||||||
DefaultInterface string `json:"default_interface,omitempty"`
|
DefaultInterface string `json:"default_interface,omitempty"`
|
||||||
DefaultMark FwMark `json:"default_mark,omitempty"`
|
DefaultMark FwMark `json:"default_mark,omitempty"`
|
||||||
|
DomainResolver *DomainResolveOptions `json:"domain_resolver,omitempty"`
|
||||||
DefaultNetworkStrategy *NetworkStrategy `json:"default_network_strategy,omitempty"`
|
DefaultNetworkStrategy *NetworkStrategy `json:"default_network_strategy,omitempty"`
|
||||||
DefaultNetworkType badoption.Listable[InterfaceType] `json:"default_network_type,omitempty"`
|
DefaultNetworkType badoption.Listable[InterfaceType] `json:"default_network_type,omitempty"`
|
||||||
DefaultFallbackNetworkType badoption.Listable[InterfaceType] `json:"default_fallback_network_type,omitempty"`
|
DefaultFallbackNetworkType badoption.Listable[InterfaceType] `json:"default_fallback_network_type,omitempty"`
|
||||||
|
|
|
@ -42,16 +42,20 @@ type Outbound struct {
|
||||||
|
|
||||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
|
||||||
options.UDPFragmentDefault = true
|
options.UDPFragmentDefault = true
|
||||||
outboundDialer, err := dialer.NewDirect(ctx, options.DialerOptions)
|
if options.Detour != "" {
|
||||||
|
return nil, E.New("`detour` is not supported in direct context")
|
||||||
|
}
|
||||||
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outbound := &Outbound{
|
outbound := &Outbound{
|
||||||
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
|
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
//nolint:staticcheck
|
||||||
domainStrategy: C.DomainStrategy(options.DomainStrategy),
|
domainStrategy: C.DomainStrategy(options.DomainStrategy),
|
||||||
fallbackDelay: time.Duration(options.FallbackDelay),
|
fallbackDelay: time.Duration(options.FallbackDelay),
|
||||||
dialer: outboundDialer,
|
dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
|
||||||
// loopBack: newLoopBackDetector(router),
|
// loopBack: newLoopBackDetector(router),
|
||||||
}
|
}
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
|
|
|
@ -30,7 +30,7 @@ type Outbound struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (adapter.Outbound, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
return nil, E.New("unknown obfs type: ", options.Obfs.Type)
|
return nil, E.New("unknown obfs type: ", options.Obfs.Type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||||
if options.Version > 1 {
|
if options.Version > 1 {
|
||||||
handshakeForServerName = make(map[string]shadowtls.HandshakeConfig)
|
handshakeForServerName = make(map[string]shadowtls.HandshakeConfig)
|
||||||
for serverName, serverOptions := range options.HandshakeForServerName {
|
for serverName, serverOptions := range options.HandshakeForServerName {
|
||||||
handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions)
|
handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions, serverOptions.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handshakeDialer, err := dialer.New(ctx, options.Handshake.DialerOptions)
|
handshakeDialer, err := dialer.New(ctx, options.Handshake.DialerOptions, options.Handshake.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
tlsHandshakeFunc = shadowtls.DefaultTLSHandshakeFunc(options.Password, stdTLSConfig)
|
tlsHandshakeFunc = shadowtls.DefaultTLSHandshakeFunc(options.Password, stdTLSConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ type Outbound struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SSHOutboundOptions) (adapter.Outbound, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SSHOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
}
|
}
|
||||||
startConf.TorrcFile = torrcFile
|
startConf.TorrcFile = torrcFile
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ type Outbound struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanOutboundOptions) (adapter.Outbound, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
case "quic":
|
case "quic":
|
||||||
tuicUDPStream = true
|
tuicUDPStream = true
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ type Outbound struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (adapter.Outbound, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ type Outbound struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (adapter.Outbound, error) {
|
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (adapter.Outbound, error) {
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
if options.Detour == "" {
|
if options.Detour == "" {
|
||||||
options.IsWireGuardListener = true
|
options.IsWireGuardListener = true
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -81,9 +81,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
ListenPort: options.ListenPort,
|
ListenPort: options.ListenPort,
|
||||||
ResolvePeer: func(domain string) (netip.Addr, error) {
|
ResolvePeer: func(domain string) (netip.Addr, error) {
|
||||||
endpointAddresses, lookupErr := ep.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{
|
endpointAddresses, lookupErr := ep.dnsRouter.Lookup(ctx, domain, outboundDialer.(dialer.ResolveDialer).QueryOptions())
|
||||||
Strategy: C.DomainStrategy(options.DomainStrategy),
|
|
||||||
})
|
|
||||||
if lookupErr != nil {
|
if lookupErr != nil {
|
||||||
return netip.Addr{}, lookupErr
|
return netip.Addr{}, lookupErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
} else if options.GSO {
|
} else if options.GSO {
|
||||||
return nil, E.New("gso is conflict with detour")
|
return nil, E.New("gso is conflict with detour")
|
||||||
}
|
}
|
||||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||||
Address: options.LocalAddress,
|
Address: options.LocalAddress,
|
||||||
PrivateKey: options.PrivateKey,
|
PrivateKey: options.PrivateKey,
|
||||||
ResolvePeer: func(domain string) (netip.Addr, error) {
|
ResolvePeer: func(domain string) (netip.Addr, error) {
|
||||||
endpointAddresses, lookupErr := outbound.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{
|
endpointAddresses, lookupErr := outbound.dnsRouter.Lookup(ctx, domain, outboundDialer.(dialer.ResolveDialer).QueryOptions())
|
||||||
Strategy: C.DomainStrategy(options.DomainStrategy),
|
|
||||||
})
|
|
||||||
if lookupErr != nil {
|
if lookupErr != nil {
|
||||||
return netip.Addr{}, lookupErr
|
return netip.Addr{}, lookupErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -55,6 +56,7 @@ type NetworkManager struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOptions option.RouteOptions) (*NetworkManager, error) {
|
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOptions option.RouteOptions) (*NetworkManager, error) {
|
||||||
|
defaultDomainResolver := common.PtrValueOrDefault(routeOptions.DomainResolver)
|
||||||
nm := &NetworkManager{
|
nm := &NetworkManager{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
interfaceFinder: control.NewDefaultInterfaceFinder(),
|
interfaceFinder: control.NewDefaultInterfaceFinder(),
|
||||||
|
@ -62,6 +64,13 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOp
|
||||||
defaultOptions: adapter.NetworkOptions{
|
defaultOptions: adapter.NetworkOptions{
|
||||||
BindInterface: routeOptions.DefaultInterface,
|
BindInterface: routeOptions.DefaultInterface,
|
||||||
RoutingMark: uint32(routeOptions.DefaultMark),
|
RoutingMark: uint32(routeOptions.DefaultMark),
|
||||||
|
DomainResolver: defaultDomainResolver.Server,
|
||||||
|
DomainResolveOptions: adapter.DNSQueryOptions{
|
||||||
|
Strategy: C.DomainStrategy(defaultDomainResolver.Strategy),
|
||||||
|
DisableCache: defaultDomainResolver.DisableCache,
|
||||||
|
RewriteTTL: defaultDomainResolver.RewriteTTL,
|
||||||
|
ClientSubnet: defaultDomainResolver.ClientSubnet.Build(netip.Prefix{}),
|
||||||
|
},
|
||||||
NetworkStrategy: (*C.NetworkStrategy)(routeOptions.DefaultNetworkStrategy),
|
NetworkStrategy: (*C.NetworkStrategy)(routeOptions.DefaultNetworkStrategy),
|
||||||
NetworkType: common.Map(routeOptions.DefaultNetworkType, option.InterfaceType.Build),
|
NetworkType: common.Map(routeOptions.DefaultNetworkType, option.InterfaceType.Build),
|
||||||
FallbackNetworkType: common.Map(routeOptions.DefaultFallbackNetworkType, option.InterfaceType.Build),
|
FallbackNetworkType: common.Map(routeOptions.DefaultFallbackNetworkType, option.InterfaceType.Build),
|
||||||
|
|
|
@ -49,7 +49,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
|
||||||
UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout),
|
UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout),
|
||||||
}, nil
|
}, nil
|
||||||
case C.RuleActionTypeDirect:
|
case C.RuleActionTypeDirect:
|
||||||
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions))
|
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,7 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
|
||||||
rule.allItems = append(rule.allItems, item)
|
rule.allItems = append(rule.allItems, item)
|
||||||
}
|
}
|
||||||
if len(options.Outbound) > 0 {
|
if len(options.Outbound) > 0 {
|
||||||
item := NewOutboundRule(options.Outbound)
|
item := NewOutboundRule(ctx, options.Outbound)
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
rule.allItems = append(rule.allItems, item)
|
rule.allItems = append(rule.allItems, item)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package rule
|
package rule
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,7 +17,8 @@ type OutboundItem struct {
|
||||||
matchAny bool
|
matchAny bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOutboundRule(outbounds []string) *OutboundItem {
|
func NewOutboundRule(ctx context.Context, outbounds []string) *OutboundItem {
|
||||||
|
deprecated.Report(ctx, deprecated.OptionOutboundDNSRuleItem)
|
||||||
rule := &OutboundItem{outbounds: outbounds, outboundMap: make(map[string]bool)}
|
rule := &OutboundItem{outbounds: outbounds, outboundMap: make(map[string]bool)}
|
||||||
for _, outbound := range outbounds {
|
for _, outbound := range outbounds {
|
||||||
if outbound == "any" {
|
if outbound == "any" {
|
||||||
|
@ -28,8 +31,8 @@ func NewOutboundRule(outbounds []string) *OutboundItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OutboundItem) Match(metadata *adapter.InboundContext) bool {
|
func (r *OutboundItem) Match(metadata *adapter.InboundContext) bool {
|
||||||
if r.matchAny && metadata.Outbound != "" {
|
if r.matchAny {
|
||||||
return true
|
return metadata.Outbound != ""
|
||||||
}
|
}
|
||||||
return r.outboundMap[metadata.Outbound]
|
return r.outboundMap[metadata.Outbound]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue