From 0cac33ceafb2e1eae80f67311a3dc58cfde9bf6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 15 Apr 2026 20:50:21 +0800 Subject: [PATCH] Fix legacy rule-set download_detour blocked by empty direct check --- common/dialer/detour.go | 24 ++++++++++++------------ common/dialer/dialer.go | 20 ++++++++++---------- common/httpclient/client.go | 15 ++++++++------- option/http.go | 21 +++++++++++---------- route/rule/rule_set_remote.go | 11 ++++++----- 5 files changed, 47 insertions(+), 44 deletions(-) diff --git a/common/dialer/detour.go b/common/dialer/detour.go index dc1777022..b2fc3efa0 100644 --- a/common/dialer/detour.go +++ b/common/dialer/detour.go @@ -17,20 +17,20 @@ type DirectDialer interface { } type DetourDialer struct { - outboundManager adapter.OutboundManager - detour string - defaultOutbound bool - legacyDNSDialer bool - dialer N.Dialer - initOnce sync.Once - initErr error + outboundManager adapter.OutboundManager + detour string + defaultOutbound bool + disableEmptyDirectCheck bool + dialer N.Dialer + initOnce sync.Once + initErr error } -func NewDetour(outboundManager adapter.OutboundManager, detour string, legacyDNSDialer bool) N.Dialer { +func NewDetour(outboundManager adapter.OutboundManager, detour string, disableEmptyDirectCheck bool) N.Dialer { return &DetourDialer{ - outboundManager: outboundManager, - detour: detour, - legacyDNSDialer: legacyDNSDialer, + outboundManager: outboundManager, + detour: detour, + disableEmptyDirectCheck: disableEmptyDirectCheck, } } @@ -66,7 +66,7 @@ func (d *DetourDialer) init() { } else { dialer = d.outboundManager.Default() } - if !d.defaultOutbound && !d.legacyDNSDialer { + if !d.defaultOutbound && !d.disableEmptyDirectCheck { if directDialer, isDirect := dialer.(DirectDialer); isDirect { if directDialer.IsEmpty() { d.initErr = E.New("detour to an empty direct outbound makes no sense") diff --git a/common/dialer/dialer.go b/common/dialer/dialer.go index 08257a04a..f78aa9f3d 100644 --- a/common/dialer/dialer.go +++ b/common/dialer/dialer.go @@ -17,15 +17,15 @@ import ( ) type Options struct { - Context context.Context - Options option.DialerOptions - RemoteIsDomain bool - DirectResolver bool - ResolverOnDetour bool - NewDialer bool - LegacyDNSDialer bool - DirectOutbound bool - DefaultOutbound bool + Context context.Context + Options option.DialerOptions + RemoteIsDomain bool + DirectResolver bool + ResolverOnDetour bool + NewDialer bool + DisableEmptyDirectCheck bool + DirectOutbound bool + DefaultOutbound bool } // TODO: merge with NewWithOptions @@ -49,7 +49,7 @@ func NewWithOptions(options Options) (N.Dialer, error) { if outboundManager == nil { return nil, E.New("missing outbound manager") } - dialer = NewDetour(outboundManager, dialOptions.Detour, options.LegacyDNSDialer) + dialer = NewDetour(outboundManager, dialOptions.Detour, options.DisableEmptyDirectCheck) } else if options.DefaultOutbound { outboundManager := service.FromContext[adapter.OutboundManager](options.Context) if outboundManager == nil { diff --git a/common/httpclient/client.go b/common/httpclient/client.go index c8eb0fef8..a6fde9c02 100644 --- a/common/httpclient/client.go +++ b/common/httpclient/client.go @@ -16,13 +16,14 @@ import ( func NewTransport(ctx context.Context, logger logger.ContextLogger, tag string, options option.HTTPClientOptions) (*ManagedTransport, error) { rawDialer, err := dialer.NewWithOptions(dialer.Options{ - Context: ctx, - Options: options.DialerOptions, - RemoteIsDomain: true, - DirectResolver: options.DirectResolver, - ResolverOnDetour: options.ResolveOnDetour, - NewDialer: options.ResolveOnDetour, - DefaultOutbound: options.DefaultOutbound, + Context: ctx, + Options: options.DialerOptions, + RemoteIsDomain: true, + DirectResolver: options.DirectResolver, + ResolverOnDetour: options.ResolveOnDetour, + NewDialer: options.ResolveOnDetour, + DisableEmptyDirectCheck: options.DisableEmptyDirectCheck, + DefaultOutbound: options.DefaultOutbound, }) if err != nil { return nil, err diff --git a/option/http.go b/option/http.go index fc7e16df9..1a9727044 100644 --- a/option/http.go +++ b/option/http.go @@ -25,16 +25,17 @@ type QUICOptions struct { } type _HTTPClientOptions struct { - Tag string `json:"tag,omitempty"` - Engine string `json:"engine,omitempty"` - Version int `json:"version,omitempty"` - DisableVersionFallback bool `json:"disable_version_fallback,omitempty"` - Headers badoption.HTTPHeader `json:"headers,omitempty"` - HTTP2Options HTTP2Options `json:"-"` - HTTP3Options QUICOptions `json:"-"` - DefaultOutbound bool `json:"-"` - ResolveOnDetour bool `json:"-"` - DirectResolver bool `json:"-"` + Tag string `json:"tag,omitempty"` + Engine string `json:"engine,omitempty"` + Version int `json:"version,omitempty"` + DisableVersionFallback bool `json:"disable_version_fallback,omitempty"` + Headers badoption.HTTPHeader `json:"headers,omitempty"` + HTTP2Options HTTP2Options `json:"-"` + HTTP3Options QUICOptions `json:"-"` + DefaultOutbound bool `json:"-"` + DisableEmptyDirectCheck bool `json:"-"` + ResolveOnDetour bool `json:"-"` + DirectResolver bool `json:"-"` OutboundTLSOptionsContainer DialerOptions } diff --git a/route/rule/rule_set_remote.go b/route/rule/rule_set_remote.go index 24066d75a..90b699e7e 100644 --- a/route/rule/rule_set_remote.go +++ b/route/rule/rule_set_remote.go @@ -294,11 +294,12 @@ func (s *RemoteRuleSet) resolveTransport() (adapter.HTTPTransport, error) { } if s.options.RemoteOptions.DownloadDetour != "" { //nolint:staticcheck deprecated.Report(s.ctx, deprecated.OptionLegacyRuleSetDownloadDetour) - var httpClientOptions option.HTTPClientOptions - httpClientOptions.DialerOptions = option.DialerOptions{ - Detour: s.options.RemoteOptions.DownloadDetour, //nolint:staticcheck - } - return httpClientManager.ResolveTransport(s.ctx, s.logger, httpClientOptions) + return httpClientManager.ResolveTransport(s.ctx, s.logger, option.HTTPClientOptions{ + DialerOptions: option.DialerOptions{ + Detour: s.options.RemoteOptions.DownloadDetour, //nolint:staticcheck + }, + DisableEmptyDirectCheck: true, + }) } defaultTransport := httpClientManager.DefaultTransport() if defaultTransport == nil {