Skip to content

fix(gateway): translate ICMPv6 egress replies instead of dropping them - #419

Merged
privateip merged 1 commit into
feat/865-egress-phase-bfrom
fix/egress-icmpv6-return-handling
Aug 16, 2026
Merged

fix(gateway): translate ICMPv6 egress replies instead of dropping them#419
privateip merged 1 commit into
feat/865-egress-phase-bfrom
fix/egress-icmpv6-return-handling

Conversation

@privateip

Copy link
Copy Markdown
Contributor

Summary

The gateway's egress masquerade path claimed its public address and dropped anything that wasn't TCP or UDP, so ICMPv6 errors and echo replies from the internet never reached the tenant that sent the original packet. Path MTU discovery rides on one of those dropped message types, so large transfers silently stalled instead of adapting, and a tenant's own ping never worked. Both cases now translate back to the originating tenant instead of being dropped, and any other ICMPv6 type passes through to the normal network stack instead of being silently discarded.

Note

Base branch is feat/865-egress-phase-b (#381), not the default branch — the code this fixes doesn't exist on main yet, since the whole egress feature is still an open, unmerged stack. Merging here won't auto-close #404 until that stack lands on main.

Test plan

  • A stalled large transfer across a smaller-MTU path adapts instead of hanging
  • A tenant workload's ping to an external host succeeds end to end
  • Unrelated ICMPv6 traffic reaches the gateway node's own network stack instead of being dropped
  • Build, lint, and full test suite pass

Fixes #404

edgenat.c's handle_egress_return claimed masq_addr and dropped anything that wasn't TCP or UDP, so ICMPv6 Destination Unreachable, Packet Too Big (path MTU discovery), Time Exceeded, and Echo Reply never reached the tenant that originated the flow. PMTUD failures presented as stalled large transfers instead of an adapting connection, and the simplest reachability check a tenant can run (ping) never worked.

handle_egress_return now dispatches ICMPv6 into its own branch: the four RFC 4443 error types translate back to the tenant by parsing the embedded original datagram (a new parse_embedded_ports helper, since RFC 4443 only guarantees 8 bytes -- not enough for parse_l4's full TCP header bounds check) and reusing egress_conn_table's existing reverse key one layer deeper. Echo Request/Reply gets a full round trip, masquerading the Echo Identifier as a pseudo-port in both handle_egress_forward_icmp6 and handle_egress_return_icmp6_echo, the same technique Linux's own nf_conntrack ICMP tracker uses. Any other ICMPv6 type now XDP_PASSes instead of being claimed and dropped.

Two new drop reasons (DROP_REASON_MALFORMED_EGRESS_ICMP, DROP_REASON_NO_EGRESS_ICMP_CONN) replace the previous mislabeled use of DROP_REASON_MALFORMED_EGRESS_RETURN, which counted a well-formed ICMPv6 packet as a parse failure rather than the protocol-policy decision it actually was -- flagged in the #381 review comment this closes. dropreason.go mirrors both constants; edgemetrics's collector picks them up automatically since it already iterates DropReasonCount generically.

Adds edgenat_egress_icmp_test.go: seven root-required kernel tests covering all three translated error types, an unknown-flow drop, an unhandled-type passthrough, a forward-side non-echo-request rejection, and a full ping round trip proving the tenant's original identifier is restored, not just the address. Verified against the real eBPF verifier and passing, alongside the full existing suite (task test:unit, task test:unit-root, task lint, and task build all green).

Includes docs/plans/404-egress-return-icmpv6-handling.md, the implementation plan this change follows.

Fixes #404

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@privateip
privateip requested a review from a team as a code owner August 16, 2026 16:22
@privateip
privateip requested review from 0xmc, JoseSzycho, ecv, scotwells and slindseysr and removed request for a team August 16, 2026 16:22
@privateip
privateip merged commit 43027b1 into feat/865-egress-phase-b Aug 16, 2026
11 checks passed
@privateip
privateip deleted the fix/egress-icmpv6-return-handling branch August 16, 2026 16:55
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