Add WithDialer option for custom TCP dialer injection#67
Conversation
Allow callers to inject a custom dialer function via WithDialer() that flows through to the tlsdialer used by each front. This enables kindling to set a single dialer that automatically applies to all fronted connections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce a single WithDialer option at the kindling level that automatically flows to all transports (fronted, dnstt, amp, smart). Key changes: - Add exported DialContextFunc type and WithDialer option - Add Close() to Kindling interface for resource cleanup - Rewrite WithDomainFronting to accept fronted.Option params - Rewrite WithDNSTunnel to accept dnstt.Option params - Rewrite WithAMPCache to accept amp.Config + amp.Option params - Update smart dialer to use injected dialer via FuncStreamDialer - Add streamConnAdapter and closerFunc helper types - Update tests for new API signatures The With* functions now construct transport instances internally and prepend the dialer option, so callers no longer need to create transport instances themselves. Requires getlantern/fronted#67 and getlantern/dnstt#12. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds support for injecting a custom TCP dialing function into the fronted client so callers can control how underlying network connections are established (e.g., for custom transports, proxies, or instrumentation), while preserving default behavior when not provided.
Changes:
- Introduces
WithDialer(func(ctx context.Context, network, addr string) (net.Conn, error))option and stores it onfronted. - Threads the dial function through
loadFronts→newFront→front.dial()and adapts it totlsdialer.Dialer.DoDialusingcontext.WithTimeout. - Updates
TestLoadFrontsto match the newloadFrontssignature.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| fronted.go | Adds dialFunc to fronted, a WithDialer option, and threads dialer injection through onNewFronts/loadFronts. |
| front.go | Stores dialer on front and uses it in front.dial() by adapting to tlsdialer.Dialer.DoDial. |
| fronted_test.go | Updates loadFronts callsite for the new parameter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // WithDialer sets a custom dialer function for the fronted instance. This allows callers to | ||
| // inject their own dialer for making TCP connections to fronting domains. | ||
| func WithDialer(dial func(ctx context.Context, network, addr string) (net.Conn, error)) Option { | ||
| return func(f *fronted) { | ||
| f.dialFunc = dial | ||
| } | ||
| } |
There was a problem hiding this comment.
New public option WithDialer adds behavior that isn’t covered by tests yet. Please add a unit test that injects a dialer via WithDialer, triggers a dial (e.g., by calling fr.dial(...) or f.doDial(...) with a dialer that records invocation and returns a sentinel error), and asserts the injected dialer is called and its error is propagated.
fronted.go
Outdated
| // fronted identifies working IP address/domain pairings for domain fronting and is | ||
| // an implementation of http.RoundTripper for the convenience of callers. | ||
| type fronted struct { | ||
| dialFunc func(ctx context.Context, network, addr string) (net.Conn, error) |
There was a problem hiding this comment.
The dialer function type is repeated in several places (fronted.dialFunc, WithDialer, loadFronts, front.dialFunc, newFront). Consider introducing a named type (e.g., type DialFunc func(context.Context, string, string) (net.Conn, error)) to reduce duplication and make future signature changes safer.
| // fronted identifies working IP address/domain pairings for domain fronting and is | |
| // an implementation of http.RoundTripper for the convenience of callers. | |
| type fronted struct { | |
| dialFunc func(ctx context.Context, network, addr string) (net.Conn, error) | |
| // DialFunc is the function type used for dialing network connections. | |
| type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) | |
| // fronted identifies working IP address/domain pairings for domain fronting and is | |
| // an implementation of http.RoundTripper for the convenience of callers. | |
| type fronted struct { | |
| dialFunc DialFunc |
fronted.go
Outdated
| } | ||
|
|
||
| // WithDialer sets a custom dialer function for the fronted instance. This allows callers to | ||
| // inject their own dialer for making TCP connections to fronting domains. |
There was a problem hiding this comment.
The WithDialer docstring says it’s for “making TCP connections to fronting domains”, but the dialer is ultimately invoked with the addr passed to tlsdialer.Dialer.Dial("tcp", addr), which (in front.dial) is built from fr.IpAddress (plus default port). Consider clarifying in the comment that the injected dialer will typically receive an IP:port target, while SNI/ServerName is handled separately via TLS config.
| // inject their own dialer for making TCP connections to fronting domains. | |
| // inject their own dialer for making the underlying TCP connections. The dialer will typically | |
| // be invoked with an IP:port destination (derived from the configured fronting infrastructure), | |
| // while the fronting domain name (SNI/ServerName) is configured separately via the TLS settings. |
Introduce a single WithDialer option at the kindling level that automatically flows to all transports (fronted, dnstt, amp, smart). Key changes: - Add exported DialContextFunc type and WithDialer option - Add Close() to Kindling interface for resource cleanup - Rewrite WithDomainFronting to accept fronted.Option params - Rewrite WithDNSTunnel to accept dnstt.Option params - Rewrite WithAMPCache to accept amp.Config + amp.Option params - Update smart dialer to use injected dialer via FuncStreamDialer - Add streamConnAdapter and closerFunc helper types - Update tests for new API signatures The With* functions now construct transport instances internally and prepend the dialer option, so callers no longer need to create transport instances themselves. Requires getlantern/fronted#67 and getlantern/dnstt#12. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Introduce named DialFunc type for the dialer function signature - Improve WithDialer docstring with more context about how the dialer is used - Add tests: TestWithDialer, TestWithDialerDefault, TestWithDialerFlowsToFronts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
WithDialer(func(ctx context.Context, network, addr string) (net.Conn, error))option tofrontedloadFronts→newFront→front.dial(), adapting it totlsdialer.Dialer.DoDialviacontext.WithTimeout(&net.Dialer{}).DialContextwhen no custom dialer is provided (preserving existing behavior)Test plan
go build ./...compiles cleanlygo vet ./...passesgo test ./...)WithDialer🤖 Generated with Claude Code