Skip to content

atunnel: restrict the actor egress listener to IPv4 - #1042

Closed
Yuan Gao (ygao-g) wants to merge 1 commit into
agent-substrate:mainfrom
ygao-g:atunnel-ipv6-listen
Closed

atunnel: restrict the actor egress listener to IPv4#1042
Yuan Gao (ygao-g) wants to merge 1 commit into
agent-substrate:mainfrom
ygao-g:atunnel-ipv6-listen

Conversation

@ygao-g

@ygao-g Yuan Gao (ygao-g) commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #943

It's a good idea to open an issue first for discussion.

  • Tests pass
  • Appropriate changes to documentation are included in the PR

The actor egress listener was opened with net.Listen("tcp", "0.0.0.0:15001").
Go treats every unspecified address as a wildcard, so that binds ::
dual-stack: the listener has been accepting IPv6 connections all along, and
TCPOriginalDestination cannot resolve them because it reads only the IPv4
SOL_IP/SO_ORIGINAL_DST. Such a connection is accepted and then fails.
Egress now opens through atunnel.ListenEgressIPv4, where the network string
decides the family rather than an address that never did; the family is in the
name so the constraint is visible at the call site while the IPv6 work is in
flight.

This does not hold IPv6-only clusters back: the actor leg is IPv4 link-local by
construction (ateomnet.ActorVethIP, IPv4-family nftables), so nothing that
works today changes. Widening egress in earnest needs actor networking to gain
IPv6 (#945) and an IP6T_SO_ORIGINAL_DST lookup (#686). The ingress flag
default is spelled :443 to record that it is deliberately dual-stack, which is
a comment on existing behavior rather than a change to it.

🤖 Generated with Claude Code

@ygao-g
Yuan Gao (ygao-g) force-pushed the atunnel-ipv6-listen branch 2 times, most recently from 74cdf67 to af1a861 Compare August 18, 2026 20:15
@ygao-g Yuan Gao (ygao-g) changed the title atecontroller,ateom: Support IPv6 for atunnel ingress atunnel: restrict the actor egress listener to IPv4 Aug 18, 2026
The transparent egress listener was opened with net.Listen("tcp",
"0.0.0.0:15001"). Go treats an unspecified address as a wildcard, so
that binds "::" dual-stack and accepts IPv6 connections, but the
original-destination lookup reads only the IPv4 SOL_IP/SO_ORIGINAL_DST.
An IPv6 actor connection was therefore accepted and then failed with no
destination to dial. Open it with "tcp4" through a named helper,
ListenEgressIPv4, so the constraint is visible at the call site and the
connection is refused rather than half-served.

This is a stopgap for the IPv4-only actor network, not the fix: the
IPv6 original-destination lookup is agent-substrate#686 and dual-stack actor
networking is agent-substrate#945. Ingress keeps its family-agnostic wildcard and is
unaffected.
@ygao-g

Copy link
Copy Markdown
Collaborator Author

Superseded. The egress pin here was overtaken by #753 and #979, which make
actor egress work over IPv6 rather than keeping the listener off it. The
other half of this PR, the ateom ingress listen defaults, ships on its own
in #1080.

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.

atunnel: egress listener accepts IPv6 connections it cannot route

1 participant