wgengine{,/magicsock}: add DERP hooks for filtering+sending packets

Add two small APIs to support out-of-tree projects to exchange custom
signaling messages over DERP without requiring disco protocol
extensions:

- OnDERPRecv callback on magicsock.Options / wgengine.Config: called for
  every non-disco DERP packet before the peer map lookup, allowing callers
  to intercept packets from unknown peers that would otherwise be dropped.

- SendDERPPacketTo method on magicsock.Conn: sends arbitrary bytes to a
  node key via a DERP region, creating the connection if needed. Thin
  wrapper around the existing internal sendAddr.

Also allow netstack.Start to accept a nil LocalBackend for use cases
that wire up TCP/UDP handlers directly without a full LocalBackend.

Updates tailscale/corp#24454

Change-Id: I99a523ef281625b8c0024a963f5f5bf5d8792c17
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2026-03-11 13:29:06 +00:00
committed by Brad Fitzpatrick
parent 4c7c1091ba
commit 073a9a8c9e
4 changed files with 51 additions and 11 deletions
+8
View File
@@ -272,6 +272,13 @@ type Config struct {
// leave it zero, in which case a new disco key is generated per
// Tailscale start and kept only in memory.
ForceDiscoKey key.DiscoPrivate
// OnDERPRecv, if non-nil, is called for every non-disco packet
// received from DERP before the peer map lookup. If it returns
// true, the packet is considered handled and is not passed to
// WireGuard. The pkt slice is borrowed and must be copied if
// the callee needs to retain it.
OnDERPRecv func(regionID int, src key.NodePublic, pkt []byte) (handled bool)
}
// NewFakeUserspaceEngine returns a new userspace engine for testing.
@@ -441,6 +448,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
ControlKnobs: conf.ControlKnobs,
PeerByKeyFunc: e.PeerByKey,
ForceDiscoKey: conf.ForceDiscoKey,
OnDERPRecv: conf.OnDERPRecv,
}
if buildfeatures.HasLazyWG {
magicsockOpts.NoteRecvActivity = e.noteRecvActivity