浏览代码

refactor: Outbound domain resolver

世界 9 月之前
父节点
当前提交
2cb5ff521a

+ 1 - 1
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")
 		}
 		}

+ 24 - 2
common/dialer/dialer.go

@@ -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)
 	}
 	}
@@ -35,13 +36,25 @@ func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
 		}
 		}
 		dialer = NewDetour(outboundManager, options.Detour)
 		dialer = NewDetour(outboundManager, options.Detour)
 	}
 	}
-	if options.Detour == "" {
+	if remoteIsDomain && options.Detour == "" && options.DomainResolver == "" {
+		deprecated.Report(ctx, deprecated.OptionMissingDomainResolverInDialOptions)
+	}
+	if (options.Detour == "" && remoteIsDomain) || options.DomainResolver != "" {
 		router := service.FromContext[adapter.DNSRouter](ctx)
 		router := service.FromContext[adapter.DNSRouter](ctx)
 		if router != nil {
 		if router != nil {
+			var resolveTransport adapter.DNSTransport
+			if options.DomainResolver != "" {
+				transport, loaded := service.FromContext[adapter.DNSTransportManager](ctx).Transport(options.DomainResolver)
+				if !loaded {
+					return nil, E.New("DNS server not found: " + options.DomainResolver)
+				}
+				resolveTransport = transport
+			}
 			dialer = NewResolveDialer(
 			dialer = NewResolveDialer(
 				router,
 				router,
 				dialer,
 				dialer,
 				options.Detour == "" && !options.TCPFastOpen,
 				options.Detour == "" && !options.TCPFastOpen,
+				resolveTransport,
 				C.DomainStrategy(options.DomainStrategy),
 				C.DomainStrategy(options.DomainStrategy),
 				time.Duration(options.FallbackDelay))
 				time.Duration(options.FallbackDelay))
 		}
 		}
@@ -60,10 +73,19 @@ func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInter
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+	var resolveTransport adapter.DNSTransport
+	if options.DomainResolver != "" {
+		transport, loaded := service.FromContext[adapter.DNSTransportManager](ctx).Transport(options.DomainResolver)
+		if !loaded {
+			return nil, E.New("DNS server not found: " + options.DomainResolver)
+		}
+		resolveTransport = transport
+	}
 	return NewResolveParallelInterfaceDialer(
 	return NewResolveParallelInterfaceDialer(
 		service.FromContext[adapter.DNSRouter](ctx),
 		service.FromContext[adapter.DNSRouter](ctx),
 		dialer,
 		dialer,
 		true,
 		true,
+		resolveTransport,
 		C.DomainStrategy(options.DomainStrategy),
 		C.DomainStrategy(options.DomainStrategy),
 		time.Duration(options.FallbackDelay),
 		time.Duration(options.FallbackDelay),
 	), nil
 	), nil

+ 9 - 8
common/dialer/resolve.go

@@ -22,15 +22,17 @@ type resolveDialer struct {
 	dialer        N.Dialer
 	dialer        N.Dialer
 	parallel      bool
 	parallel      bool
 	router        adapter.DNSRouter
 	router        adapter.DNSRouter
+	transport     adapter.DNSTransport
 	strategy      C.DomainStrategy
 	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(router adapter.DNSRouter, dialer N.Dialer, parallel bool, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) N.Dialer {
 	return &resolveDialer{
 	return &resolveDialer{
 		dialer,
 		dialer,
 		parallel,
 		parallel,
 		router,
 		router,
+		transport,
 		strategy,
 		strategy,
 		fallbackDelay,
 		fallbackDelay,
 	}
 	}
@@ -41,12 +43,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(router adapter.DNSRouter, dialer ParallelInterfaceDialer, parallel bool, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer {
 	return &resolveParallelNetworkDialer{
 	return &resolveParallelNetworkDialer{
 		resolveDialer{
 		resolveDialer{
 			dialer,
 			dialer,
 			parallel,
 			parallel,
 			router,
 			router,
+			transport,
 			strategy,
 			strategy,
 			fallbackDelay,
 			fallbackDelay,
 		},
 		},
@@ -59,7 +62,7 @@ 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, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -75,7 +78,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, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -91,9 +94,7 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context
 		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, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -112,7 +113,7 @@ 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, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 1 - 1
common/tls/reality_server.go

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

+ 11 - 3
dns/transport_dialer.go

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

+ 18 - 0
experimental/deprecated/constants.go

@@ -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 OptionMissingDomainResolverInDialOptions = Note{
+	Name:              "missing-domain-resolver-in-dial-options",
+	Description:       "missing domain resolver in dial options",
+	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,
+	OptionMissingDomainResolverInDialOptions,
 }
 }

+ 5 - 0
option/outbound.go

@@ -77,6 +77,7 @@ 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:"-"`
+	DomainResolver      string                            `json:"domain_resolver,omitempty"`
 	DomainStrategy      DomainStrategy                    `json:"domain_strategy,omitempty"`
 	DomainStrategy      DomainStrategy                    `json:"domain_strategy,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"`
@@ -107,6 +108,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
 }
 }

+ 1 - 1
protocol/http/outbound.go

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

+ 1 - 1
protocol/hysteria/outbound.go

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

+ 1 - 1
protocol/hysteria2/outbound.go

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

+ 1 - 1
protocol/shadowsocks/outbound.go

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

+ 2 - 2
protocol/shadowtls/inbound.go

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

+ 1 - 1
protocol/shadowtls/outbound.go

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

+ 1 - 1
protocol/socks/outbound.go

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

+ 1 - 1
protocol/ssh/outbound.go

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

+ 1 - 1
protocol/tor/outbound.go

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

+ 1 - 1
protocol/trojan/outbound.go

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

+ 1 - 1
protocol/tuic/outbound.go

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

+ 1 - 1
protocol/vless/outbound.go

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

+ 1 - 1
protocol/vmess/outbound.go

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

+ 1 - 1
protocol/wireguard/endpoint.go

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

+ 1 - 1
protocol/wireguard/outbound.go

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

+ 1 - 1
route/rule/rule_action.go

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

+ 1 - 1
route/rule/rule_dns.go

@@ -205,7 +205,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)
 	}
 	}

+ 6 - 3
route/rule/rule_item_outbound.go

@@ -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 != "" {
-		return true
+	if r.matchAny {
+		return metadata.Outbound != ""
 	}
 	}
 	return r.outboundMap[metadata.Outbound]
 	return r.outboundMap[metadata.Outbound]
 }
 }