Skip to content

▚▚ fix(relay): key IPv6 proxy mappings the way packets look them up - #124

Merged
oschwartz10612 merged 1 commit into
fosrl:mainfrom
breken-ai:fix/relay-ipv6-mapping-keys
Sep 28, 2026
Merged

oschwartz10612 merged 1 commit into
fosrl:mainfrom
breken-ai:fix/relay-ipv6-mapping-keys

Conversation

@breken-ai

Copy link
Copy Markdown
Contributor

Community Contribution License Agreement

By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.

AI Disclosure

Please disclose how AI was used in this pull request. The use of AI does not preclude this from being merged but is an important factor in how we review your request.

This pull request was written by an AI coding agent (Anthropic Claude, running in Claude Code) operating the breken-ai account. The agent found the bug by reading the code, wrote the fix and the regression test, and ran the checks listed under "How to test?". The red/green runs below are real output from those runs.

Description

The relay can't forward packets for a client that connects over IPv6. handleWireGuardPacket looks the mapping up by remoteAddr.String(), which for IPv6 is [2001:db8::1]:51820. The two paths that add mappings at runtime build the key with fmt.Sprintf("%s:%d", ...), which gives 2001:db8::1:51820:

  • notifyServer, after a hole punch (/gerbil/update-hole-punch response)
  • UpdateProxyMapping, from /update-destinations

So the lookup misses and every WireGuard packet from that client is dropped with No proxy mapping found for [2001:db8::1]:51820. Mappings loaded at startup from /gerbil/get-all-relays do work, because Pangolin keys them with formatEndpoint ([ip]:port). That means an IPv6 client that connects after gerbil starts isn't relayed until gerbil restarts.

getCachedAddr has the same problem with IPv6 destinations: net.ResolveUDPAddr("udp", "2001:db8::5:51820") fails with too many colons in address.

Fix

  • relay/relay.go: build these three keys with net.JoinHostPort(ip, strconv.Itoa(port)), which brackets IPv6 and matches UDPAddr.String(). IPv4 keys come out the same as before.

Not changed

  • The initial mapping load, session tracking and containsIP.

How to test?

  • go test ./relay/: new TestRelayForwardsIPv6Peer starts the relay on [::1]:0, registers a mapping for an IPv6 client with UpdateProxyMapping (the /update-destinations path), sends a handshake initiation from that client, and checks that it reaches an IPv6 destination.
    • Red (on main): the relay logs No proxy mapping found for [::1]:59684 and the test fails with destination did not receive the forwarded initiation: read udp6 [::1]:50044: i/o timeout.
    • Green: passes with this change.
  • go test ./..., go vet ./relay/, gofmt -l relay/ and go build ./... are clean.

▚▚ Shipped by breken — self-healing software. This one's on us. breken.ai

@oschwartz10612

Copy link
Copy Markdown
Member

Thanks

@oschwartz10612
oschwartz10612 merged commit 5ec1298 into fosrl:main Sep 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants