Skip to content

Add tsnet.Server.Underlay for DERP and magicsock sockets - #11

Open
chasylexus wants to merge 1 commit into
SagerNet:devfrom
chasylexus:tsnet-underlay
Open

chasylexus wants to merge 1 commit into
SagerNet:devfrom
chasylexus:tsnet-underlay

Conversation

@chasylexus

Copy link
Copy Markdown

tsnet.Server.Dialer only reaches the control plane. DERP dials go through netns.NewDialerAlwaysDirect, and magicsock binds its UDP sockets through netns.Listener or the process-global netns.ListenPacketFunc. A tsnet user therefore cannot move all of a server's own traffic onto one transport, and two servers in one process cannot use different transports.

This adds netmon.Underlay, carried per Monitor next to Dialer, and uses it in derphttp.Client.dialContext (DERP connections, including the netcheck HTTPS latency client) and magicsock.Conn.listenPacket (peer, disco and STUN traffic). Rebind keeps passing the current port through it, and the per-server value takes precedence over the process-global ListenPacketFunc. netcheck skips the ICMP probes when an Underlay is set, since ICMP cannot go through it. Control plane connections keep using Dialer. With Underlay nil, every path behaves as before.

Fallback or selection between transports is left to the caller; the hook only replaces the socket source.

Tests:

  • go build ./...
  • go vet ./net/netmon/ ./derp/derphttp/ ./wgengine/magicsock/ ./net/netcheck/ ./tsnet/
  • go test -race ./wgengine/magicsock/ ./derp/derphttp/ -run 'Underlay|DialNode|ListenPacket|Rebind'
  • GOOS=linux, GOOS=windows and GOOS=android builds of ./tsnet/, ./net/netcheck/ and ./wgengine/magicsock/

The new tests cover: sockets bound through the underlay, the current port surviving Rebind, two Conns with independent underlays, DERP dialNode using the underlay, and the nil case binding and dialing directly.

tsnet.Server.Dialer only reaches the control plane. DERP dials go
through netns.NewDialerAlwaysDirect and magicsock binds its UDP sockets
through netns.Listener or the process-global netns.ListenPacketFunc, so
a tsnet user cannot move all of a server's own traffic onto one
transport, and two servers in one process cannot use different
transports.

Add netmon.Underlay, carried per Monitor next to Dialer, and use it in
derphttp.Client.dialContext and magicsock.Conn.listenPacket. Rebind
keeps passing the current port through it, and the per-server value
takes precedence over the process-global ListenPacketFunc. netcheck
skips the ICMP probes when an Underlay is set, since ICMP cannot go
through it. When Underlay is nil every path behaves as before.
@nekohasekai
nekohasekai force-pushed the dev branch 2 times, most recently from d6b37e9 to 66c96c3 Compare September 16, 2026 04:17
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.

1 participant