From 63ef6f972f2a1dd00f2bc5fe7df5a838780cbf2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 12 Jan 2025 12:45:27 +0800 Subject: [PATCH] refactor: Outbound domain resolver --- box.go | 2 +- common/dialer/dialer.go | 26 ++++++++++++++++++++++++-- common/dialer/resolve.go | 17 +++++++++-------- common/tls/reality_server.go | 2 +- dns/transport_dialer.go | 14 +++++++++++--- experimental/deprecated/constants.go | 18 ++++++++++++++++++ option/outbound.go | 5 +++++ protocol/http/outbound.go | 2 +- protocol/hysteria/outbound.go | 2 +- protocol/hysteria2/outbound.go | 2 +- protocol/shadowsocks/outbound.go | 2 +- protocol/shadowtls/inbound.go | 4 ++-- protocol/shadowtls/outbound.go | 2 +- protocol/socks/outbound.go | 2 +- protocol/ssh/outbound.go | 2 +- protocol/tor/outbound.go | 2 +- protocol/trojan/outbound.go | 2 +- protocol/tuic/outbound.go | 2 +- protocol/vless/outbound.go | 2 +- protocol/vmess/outbound.go | 2 +- protocol/wireguard/endpoint.go | 2 +- protocol/wireguard/outbound.go | 2 +- route/rule/rule_action.go | 2 +- route/rule/rule_dns.go | 2 +- route/rule/rule_item_outbound.go | 9 ++++++--- 25 files changed, 93 insertions(+), 36 deletions(-) diff --git a/box.go b/box.go index bd15c66a..1f8564f2 100644 --- a/box.go +++ b/box.go @@ -309,7 +309,7 @@ func New(options Options) (*Box, error) { } } if ntpOptions.Enabled { - ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions) + ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions, ntpOptions.ServerIsDomain()) if err != nil { return nil, E.Cause(err, "create NTP service") } diff --git a/common/dialer/dialer.go b/common/dialer/dialer.go index f63e3864..4b06f948 100644 --- a/common/dialer/dialer.go +++ b/common/dialer/dialer.go @@ -8,6 +8,7 @@ import ( "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/deprecated" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -15,7 +16,7 @@ import ( "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 { return NewDefault(ctx, options) } @@ -35,13 +36,25 @@ func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) { } 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) 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( router, dialer, options.Detour == "" && !options.TCPFastOpen, + resolveTransport, C.DomainStrategy(options.DomainStrategy), time.Duration(options.FallbackDelay)) } @@ -60,10 +73,19 @@ func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInter if err != nil { 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( service.FromContext[adapter.DNSRouter](ctx), dialer, true, + resolveTransport, C.DomainStrategy(options.DomainStrategy), time.Duration(options.FallbackDelay), ), nil diff --git a/common/dialer/resolve.go b/common/dialer/resolve.go index 3d667a6c..ebabc980 100644 --- a/common/dialer/resolve.go +++ b/common/dialer/resolve.go @@ -22,15 +22,17 @@ type resolveDialer struct { dialer N.Dialer parallel bool router adapter.DNSRouter + transport adapter.DNSTransport strategy C.DomainStrategy 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{ dialer, parallel, router, + transport, strategy, fallbackDelay, } @@ -41,12 +43,13 @@ type resolveParallelNetworkDialer struct { 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{ resolveDialer{ dialer, parallel, router, + transport, strategy, fallbackDelay, }, @@ -59,7 +62,7 @@ func (d *resolveDialer) DialContext(ctx context.Context, network string, destina return d.dialer.DialContext(ctx, network, destination) } 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 { return nil, err } @@ -75,7 +78,7 @@ func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd return d.dialer.ListenPacket(ctx, destination) } 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 { return nil, err } @@ -91,9 +94,7 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context return d.dialer.DialContext(ctx, network, destination) } 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 { return nil, err } @@ -112,7 +113,7 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C return d.dialer.ListenPacket(ctx, destination) } 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 { return nil, err } diff --git a/common/tls/reality_server.go b/common/tls/reality_server.go index cf429815..912d13dd 100644 --- a/common/tls/reality_server.go +++ b/common/tls/reality_server.go @@ -101,7 +101,7 @@ func NewRealityServer(ctx context.Context, logger log.Logger, options option.Inb 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 { return nil, err } diff --git a/dns/transport_dialer.go b/dns/transport_dialer.go index 14e1188d..d9298b7f 100644 --- a/dns/transport_dialer.go +++ b/dns/transport_dialer.go @@ -19,12 +19,20 @@ func NewLocalDialer(ctx context.Context, options option.LocalDNSServerOptions) ( if options.LegacyDefaultDialer { return dialer.NewDefaultOutbound(ctx), nil } 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) { - 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 { 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) } 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 transportDialer, nil diff --git a/experimental/deprecated/constants.go b/experimental/deprecated/constants.go index bf648365..bb386d4f 100644 --- a/experimental/deprecated/constants.go +++ b/experimental/deprecated/constants.go @@ -161,6 +161,20 @@ var OptionLegacyDNSFakeIPOptions = Note{ 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{ OptionBadMatchSource, OptionGEOIP, @@ -172,4 +186,8 @@ var Options = []Note{ OptionWireGuardOutbound, OptionWireGuardGSO, OptionTUNGSO, + OptionLegacyDNSTransport, + OptionLegacyDNSFakeIPOptions, + OptionOutboundDNSRuleItem, + OptionMissingDomainResolverInDialOptions, } diff --git a/option/outbound.go b/option/outbound.go index 5cadd3e2..2f8697da 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -77,6 +77,7 @@ type DialerOptions struct { TCPMultiPath bool `json:"tcp_multi_path,omitempty"` UDPFragment *bool `json:"udp_fragment,omitempty"` UDPFragmentDefault bool `json:"-"` + DomainResolver string `json:"domain_resolver,omitempty"` DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` NetworkStrategy *NetworkStrategy `json:"network_strategy,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) } +func (o ServerOptions) ServerIsDomain() bool { + return M.IsDomainName(o.Server) +} + func (o *ServerOptions) TakeServerOptions() ServerOptions { return *o } diff --git a/protocol/http/outbound.go b/protocol/http/outbound.go index c58f3071..0570dde5 100644 --- a/protocol/http/outbound.go +++ b/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) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/hysteria/outbound.go b/protocol/hysteria/outbound.go index e1d8716c..7746df13 100644 --- a/protocol/hysteria/outbound.go +++ b/protocol/hysteria/outbound.go @@ -47,7 +47,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/hysteria2/outbound.go b/protocol/hysteria2/outbound.go index 74e87b37..c805f07e 100644 --- a/protocol/hysteria2/outbound.go +++ b/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) } } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/shadowsocks/outbound.go b/protocol/shadowsocks/outbound.go index 7e7277ef..875c9e69 100644 --- a/protocol/shadowsocks/outbound.go +++ b/protocol/shadowsocks/outbound.go @@ -44,7 +44,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/shadowtls/inbound.go b/protocol/shadowtls/inbound.go index 5ae5656f..1db191d8 100644 --- a/protocol/shadowtls/inbound.go +++ b/protocol/shadowtls/inbound.go @@ -47,7 +47,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo if options.Version > 1 { handshakeForServerName = make(map[string]shadowtls.HandshakeConfig) 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 { 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 { return nil, err } diff --git a/protocol/shadowtls/outbound.go b/protocol/shadowtls/outbound.go index 2b480729..0731b033 100644 --- a/protocol/shadowtls/outbound.go +++ b/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) } } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/socks/outbound.go b/protocol/socks/outbound.go index 323149e2..851412ff 100644 --- a/protocol/socks/outbound.go +++ b/protocol/socks/outbound.go @@ -46,7 +46,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/ssh/outbound.go b/protocol/ssh/outbound.go index eb9970b5..304ea389 100644 --- a/protocol/ssh/outbound.go +++ b/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) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/tor/outbound.go b/protocol/tor/outbound.go index 58824b53..9a0e2d65 100644 --- a/protocol/tor/outbound.go +++ b/protocol/tor/outbound.go @@ -75,7 +75,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL } startConf.TorrcFile = torrcFile } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, false) if err != nil { return nil, err } diff --git a/protocol/trojan/outbound.go b/protocol/trojan/outbound.go index 82889bc1..37a6933c 100644 --- a/protocol/trojan/outbound.go +++ b/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) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/tuic/outbound.go b/protocol/tuic/outbound.go index 49b01f96..a31d4850 100644 --- a/protocol/tuic/outbound.go +++ b/protocol/tuic/outbound.go @@ -60,7 +60,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL case "quic": tuicUDPStream = true } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/vless/outbound.go b/protocol/vless/outbound.go index 1d832a65..e0208be9 100644 --- a/protocol/vless/outbound.go +++ b/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) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/vmess/outbound.go b/protocol/vmess/outbound.go index d41b30d9..be05990e 100644 --- a/protocol/vmess/outbound.go +++ b/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) { - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain()) if err != nil { return nil, err } diff --git a/protocol/wireguard/endpoint.go b/protocol/wireguard/endpoint.go index 300701a9..4f4d3ab3 100644 --- a/protocol/wireguard/endpoint.go +++ b/protocol/wireguard/endpoint.go @@ -53,7 +53,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL if options.Detour == "" { options.IsWireGuardListener = true } - outboundDialer, err := dialer.New(ctx, options.DialerOptions) + outboundDialer, err := dialer.New(ctx, options.DialerOptions, false) if err != nil { return nil, err } diff --git a/protocol/wireguard/outbound.go b/protocol/wireguard/outbound.go index 4aa49a8d..b6eea44f 100644 --- a/protocol/wireguard/outbound.go +++ b/protocol/wireguard/outbound.go @@ -56,7 +56,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL } else if options.GSO { 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 { return nil, err } diff --git a/route/rule/rule_action.go b/route/rule/rule_action.go index fbf8c66e..bdda273e 100644 --- a/route/rule/rule_action.go +++ b/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), }, nil 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 { return nil, err } diff --git a/route/rule/rule_dns.go b/route/rule/rule_dns.go index 1b4dcdc4..37712928 100644 --- a/route/rule/rule_dns.go +++ b/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) } if len(options.Outbound) > 0 { - item := NewOutboundRule(options.Outbound) + item := NewOutboundRule(ctx, options.Outbound) rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } diff --git a/route/rule/rule_item_outbound.go b/route/rule/rule_item_outbound.go index 3f37dee7..a13d0597 100644 --- a/route/rule/rule_item_outbound.go +++ b/route/rule/rule_item_outbound.go @@ -1,9 +1,11 @@ package rule import ( + "context" "strings" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/experimental/deprecated" F "github.com/sagernet/sing/common/format" ) @@ -15,7 +17,8 @@ type OutboundItem struct { 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)} for _, outbound := range outbounds { if outbound == "any" { @@ -28,8 +31,8 @@ func NewOutboundRule(outbounds []string) *OutboundItem { } 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] }