Skip to content

refactor(client): migrate PacketProxy to network/packetrelay#2777

Merged
fortuna merged 13 commits into
masterfrom
fortuna/packetrelay
Jun 23, 2026
Merged

refactor(client): migrate PacketProxy to network/packetrelay#2777
fortuna merged 13 commits into
masterfrom
fortuna/packetrelay

Conversation

@fortuna

@fortuna fortuna commented May 28, 2026

Copy link
Copy Markdown
Collaborator

Replaces the callback-based PacketProxy API with the flow-based PacketRelay API introduced in SDK v0.0.23, eliminating boilerplate goroutines and adopting the SDK's built-in DNS intercept and timeout decorators.

  • Delete client/go/outline/dnsintercept package (replaced by SDK)
  • Replace network.PacketProxy with packetrelay.PacketRelay throughout
  • Replace lwip2transport.ConfigureDevice with ConfigureDeviceWithRelay
  • Use sdk network/dnsintercept.InterceptDNSPacketRelay for UDP DNS routing
  • Use sdk network/packetrelay.TimeoutPacketRelay (30s base, 5s DNS)
  • Inline TCP DNS redirect into outline_dns_intercept.go

Depends on OutlineFoundation/outline-sdk#625

…v0.0.23)

Replaces the callback-based PacketProxy API with the flow-based PacketRelay
API introduced in SDK v0.0.23, eliminating boilerplate goroutines and
adopting the SDK's built-in DNS intercept and timeout decorators.

- Bump SDK to v0.0.23
- Delete client/go/outline/dnsintercept package (replaced by SDK)
- Replace network.PacketProxy with packetrelay.PacketRelay throughout
- Replace lwip2transport.ConfigureDevice with ConfigureDeviceWithRelay
- Use sdk network/dnsintercept.InterceptDNSPacketRelay for UDP DNS routing
- Use sdk network/packetrelay.TimeoutPacketRelay (30s base, 5s DNS)
- Inline TCP DNS redirect into outline_dns_intercept.go

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@fortuna fortuna changed the title refactor(client/go): migrate PacketProxy to network/packetrelay (SDK … refactor(client/go): migrate PacketProxy to network/packetrelay May 28, 2026
@fortuna

fortuna commented May 28, 2026

Copy link
Copy Markdown
Collaborator Author

@greptile review

@greptile-apps

greptile-apps Bot commented May 28, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces the callback-based PacketProxy API with the flow-based PacketRelay API introduced in SDK v0.0.23+, deleting the local dnsintercept package entirely and delegating DNS intercept, truncation, and timeout logic to the SDK.

  • DNS intercept refactored: TCP redirect is now an inlined closure; UDP uses SDK dnsintercept.NewInterceptDNSPacketRelay with two relay paths (5 s DNS timeout via dnsListener, immediate-truncate fallback via dnstruncate), wired through a DelegatePacketRelay that switches on UDP health checks.
  • API propagated top-to-bottom: Client.NewAssociation, EstablishVPN, ConnectRemoteDevice, and the PacketProxy struct all updated from network.PacketProxy to packetrelay.PacketRelay; lwip2transport.ConfigureDevice replaced with ConfigureDeviceWithRelay.
  • Incidental correctness fix: relay.go log-level branches were inverted in the old code (slog.Info on error, slog.Warn on success); this PR corrects the inversion.

Confidence Score: 5/5

Safe to merge; the refactor is a clean API migration with no functional regressions and one opportunistic correctness fix.

All changed call-sites consistently adopt the new PacketRelay API. The DNS interception logic — truncate-first, switch to forward on UDP health confirmation — is faithfully preserved. The shared baseListener between both relay paths is intentional and correct (PacketListenerRelay is stateless; each NewAssociation creates an independent socket). The dnsListener carries the required 5 s write-idle timeout, satisfying the SDK's documented MUST constraint for the dnsRelay parameter. The only comment is on the incidental log-level inversion fix in relay.go.

No files require special attention.

Important Files Changed

Filename Overview
client/go/outline/configregistry/outline_dns_intercept.go Migrates DNS interception from old callback-based API to SDK's flow-based PacketRelay. TCP redirect is inlined as a closure; UDP uses NewInterceptDNSPacketRelay with a truncate relay (TC=1) as the safe initial state, switching to a forward relay once UDP health is confirmed. Both paths share a baseListener for non-DNS traffic; DNS path gets a dedicated 5 s write-idle timeout via dnsListener.
client/go/outline/tun2socks/relay.go Fixes a pre-existing log-level inversion: slog.Warn now fires on close error, slog.Info on success. Minor correctness fix bundled with the refactor.
client/go/outline/configregistry/types.go PacketProxy struct field changed from network.PacketProxy to packetrelay.PacketRelay; method set updated consistently throughout.
client/go/outline/vpn/device.go ConnectRemoteDevice now accepts packetrelay.PacketRelay instead of network.PacketProxy; uses ConfigureDeviceWithRelay for lwip2transport setup.
client/go/outline/vpn/vpn.go EstablishVPN signature updated to packetrelay.PacketRelay; panic message corrected from 'PacketListener' to 'PacketRelay'.
client/go/outline/client.go Client now implements PacketRelay.NewAssociation instead of PacketProxy.NewSession; delegates to embedded pp.NewAssociation.
client/go/outline/configregistry/config_proxyless.go Switches from NewPacketProxyFromPacketListener to NewPacketRelayFromPacketListener; passes the underlying PacketListener directly instead of the wrapper struct.
go.mod SDK bumped from v0.0.21-alpha.1 to v0.0.24-0.20260616223101-79c8a04b30e9 (pseudoversion for SDK PR #625); golang.org/x/net moved from direct to indirect dependency.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    OS["OS (UDP traffic)"] --> relayMain

    check["UDP connectivity check\n(onNetworkChanged)"] -->|"UDP healthy → SetRelay(relayForward)"| relayMain
    check -->|"UDP blocked → SetRelay(relayTrunc)"| relayMain

    relayMain{{"DelegatePacketRelay\n(relayMain)\nstarts with relayTrunc"}}

    relayMain -->|"UDP available"| relayForward["InterceptDNSPacketRelay\n(relayForward)"]
    relayMain -->|"UDP blocked"| relayTrunc["InterceptDNSPacketRelay\n(relayTrunc)"]

    relayForward -->|"DNS → linkLocalDNS"| dnsListener["PacketListenerRelay\n(dnsListener, 5s timeout)\n→ remoteDNS resolver"]
    relayForward -->|"non-DNS"| baseListener["PacketListenerRelay\n(baseListener)\n→ proxy transport"]

    relayTrunc -->|"DNS → linkLocalDNS"| dnsTruncRelay["dnstruncate.PacketRelay\n(returns TC=1 immediately)"]
    relayTrunc -->|"non-DNS"| baseListener

    OS2["OS (TCP traffic)"] --> sdForward["sdForward closure\n(TCP DNS: linkLocalDNS → remoteDNS)"]
    sdForward --> sdDial["sd.Dial (proxy transport)"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    OS["OS (UDP traffic)"] --> relayMain

    check["UDP connectivity check\n(onNetworkChanged)"] -->|"UDP healthy → SetRelay(relayForward)"| relayMain
    check -->|"UDP blocked → SetRelay(relayTrunc)"| relayMain

    relayMain{{"DelegatePacketRelay\n(relayMain)\nstarts with relayTrunc"}}

    relayMain -->|"UDP available"| relayForward["InterceptDNSPacketRelay\n(relayForward)"]
    relayMain -->|"UDP blocked"| relayTrunc["InterceptDNSPacketRelay\n(relayTrunc)"]

    relayForward -->|"DNS → linkLocalDNS"| dnsListener["PacketListenerRelay\n(dnsListener, 5s timeout)\n→ remoteDNS resolver"]
    relayForward -->|"non-DNS"| baseListener["PacketListenerRelay\n(baseListener)\n→ proxy transport"]

    relayTrunc -->|"DNS → linkLocalDNS"| dnsTruncRelay["dnstruncate.PacketRelay\n(returns TC=1 immediately)"]
    relayTrunc -->|"non-DNS"| baseListener

    OS2["OS (TCP traffic)"] --> sdForward["sdForward closure\n(TCP DNS: linkLocalDNS → remoteDNS)"]
    sdForward --> sdDial["sd.Dial (proxy transport)"]
Loading

Reviews (3): Last reviewed commit: "chore: update outline-sdk to dnsintercep..." | Re-trigger Greptile

Comment thread client/go/outline/configregistry/outline_dns_intercept.go
fortuna and others added 7 commits May 27, 2026 23:58
Give each TimeoutPacketRelay its own PacketListenerRelay so their
independent idle timeouts cannot close each other's underlying listener.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SetRelay only fails for nil relay; both relays are provably non-nil.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@fortuna fortuna requested review from jyyi1 and ohnorobo June 16, 2026 06:40
@fortuna fortuna marked this pull request as ready for review June 16, 2026 06:41
@fortuna fortuna requested a review from a team as a code owner June 16, 2026 06:41
@fortuna fortuna changed the title refactor(client/go): migrate PacketProxy to network/packetrelay refactor(client): migrate PacketProxy to network/packetrelay Jun 16, 2026

@jyyi1 jyyi1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, thanks!

Comment thread go.mod Outdated

@ohnorobo ohnorobo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

thanks, very nice simplification

@fortuna fortuna enabled auto-merge (squash) June 23, 2026 04:13
@fortuna fortuna merged commit 20cf602 into master Jun 23, 2026
25 checks passed
@fortuna fortuna deleted the fortuna/packetrelay branch June 23, 2026 04:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants