Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ type Client struct {
socksWg sync.WaitGroup

DNSResolutionMapForDirectDialsEventual eventual.Value
useProxyless func() bool
Copy link
Preview

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useProxyless field is added to the Client struct but there's no nil check before using it in initDialers. If useProxyless is nil when passed to UseProxyless, this could cause a panic when the function is called.

Copilot uses AI. Check for mistakes.

}

// NewClient creates a new client that does things like starts the HTTP and
Expand All @@ -168,6 +169,7 @@ func NewClient(
eventWithLabel func(category, action, label string),
onDialError func(error, bool),
onSucceedingProxy func(),
useProxyless func() bool,
) (*Client, error) {
// A small LRU to detect redirect loop
rewriteLRU, err := lru.New(100)
Expand Down Expand Up @@ -204,6 +206,7 @@ func NewClient(
httpListener: eventual.NewValue(),
socksListener: eventual.NewValue(),
DNSResolutionMapForDirectDialsEventual: eventual.NewValue(),
useProxyless: useProxyless,
}

keepAliveIdleTimeout := chained.IdleTimeout - 5*time.Second
Expand Down Expand Up @@ -754,7 +757,7 @@ func (client *Client) initDialers(proxies map[string]*commonconfig.ProxyConfig)
OnNewDialer: func(dialer dialer.Dialer) {
client.dialer.set(dialer)
},
ProxyAll: client.proxyAll,
UseProxyless: client.useProxyless,
},
)
client.dialer.set(newDialer)
Expand Down
8 changes: 4 additions & 4 deletions dialer/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ type Options struct {

OnNewDialer func(Dialer)

// Specifies whether or not to proxy all traffic. In this case, that means bypasses the proxyless
// dialer and uses the proxy dialers to connect to the destination site.
ProxyAll func() bool
// Specifies whether or not to enable proxyless dialing for all traffic. Proxyless is
// off when proxy all is on.
UseProxyless func() bool
}

// Clone creates a deep copy of the Options object
Expand All @@ -65,7 +65,7 @@ func (o *Options) Clone() *Options {
BanditDir: o.BanditDir,
proxylessDialer: o.proxylessDialer,
OnNewDialer: o.OnNewDialer,
ProxyAll: o.ProxyAll,
UseProxyless: o.UseProxyless,
}
}

Expand Down
3 changes: 1 addition & 2 deletions dialer/parallel_dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ func newParallelPreferProxyless(proxyless proxyless, d Dialer, opts *Options) Di
}

func (d *parallelDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
if !common.SupportsProxyless() {
log.Debugf("Proxyless transport not supported, falling back to default dialer for %s", addr)
if !common.SupportsProxyless() || !d.opts.UseProxyless() {
// If the proxyless transport is not supported, we fall back to the default dialer.
Comment on lines +26 to 27
Copy link
Preview

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition logic appears incorrect. The function should fall back to default dialer when proxyless is NOT supported OR when proxyless is NOT enabled. However, the function name UseProxyless suggests it returns true when proxyless should be used, making the negation !d.opts.UseProxyless() potentially confusing. Consider verifying the intended behavior: should this be !d.opts.UseProxyless() (fall back when proxyless is disabled) or d.opts.UseProxyless() == false?

Suggested change
if !common.SupportsProxyless() || !d.opts.UseProxyless() {
// If the proxyless transport is not supported, we fall back to the default dialer.
if !common.SupportsProxyless() || d.opts.UseProxyless() == false {
// If proxyless transport is not supported or not enabled, fall back to the default dialer.

Copilot uses AI. Check for mistakes.

return d.dialer.DialContext(ctx, network, addr)
}
Expand Down
3 changes: 2 additions & 1 deletion flashlight.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type Flashlight struct {
errorHandler func(HandledErrorType, error)
mxProxyListeners sync.RWMutex
proxyListeners []func(map[string]*commonconfig.ProxyConfig, config.Source)
useProxyless func() bool
}

// clientCallbacks are callbacks the client is configured with
Expand Down Expand Up @@ -215,7 +216,6 @@ func New(
useDetour := func() bool {
return !_proxyAll() && f.featureEnabled(config.FeatureDetour) && !f.featureEnabled(config.FeatureProxyWhitelistedOnly)
}

proxyAll := func() bool {
useShortcutOrDetour := useShortcut() || useDetour()
return !useShortcutOrDetour && !f.featureEnabled(config.FeatureProxyWhitelistedOnly)
Expand Down Expand Up @@ -243,6 +243,7 @@ func New(
eventWithLabel,
f.callbacks.onDialError,
f.callbacks.onSucceedingProxy,
f.useProxyless,
)

if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ func WithOnProxies(onProxiesUpdate func([]dialer.ProxyDialer, config.Source)) Op
client.callbacks.onProxiesUpdate = onProxiesUpdate
}
}

// WithUseProxyless sets the function to determine if proxyless dialing should be used.
func WithUseProxyless(useProxyless func() bool) Option {
return func(client *Flashlight) {
client.useProxyless = useProxyless
}
}
Loading