conn,device: always perform PeerAwareEndpoint check

It was previously suppressed if roaming was disabled for the peer.
Tailscale always disables roaming as we explicitly configure
conn.Endpoint's for all peers.

This commit also modifies PeerAwareEndpoint usage such that wireguard-go
never uses/sets it as a Peer Endpoint value. In theory we (Tailscale)
always disable roaming, so we should always return early from
SetEndpointFromPacket(), but this acts as an extra footgun guard and
improves clarity around intended usage.

Updates tailscale/corp#27502
Updates tailscale/corp#29422
Updates tailscale/corp#30042

Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
Jordan Whited 2025-07-01 14:44:37 -07:00 committed by Jordan Whited
parent 65cd6eed7d
commit 24483d7a00
2 changed files with 12 additions and 7 deletions

View file

@ -87,17 +87,21 @@ type Endpoint interface {
} }
// PeerAwareEndpoint is an optional Endpoint specialization for // PeerAwareEndpoint is an optional Endpoint specialization for
// integrations that want to know about the outcome of cryptorouting // integrations that want to know about the outcome of Cryptokey Routing
// identification. // identification.
// //
// If they receive a packet from a source they had not pre-identified, // If they receive a packet from a source they had not pre-identified,
// to learn the identification WireGuard can derive from the session // to learn the identification WireGuard can derive from the session
// or handshake. // or handshake.
// //
// If GetPeerEndpoint returns nil, WireGuard will be unable to respond // wireguard-go never installs a [PeerAwareEndpoint] as the [Endpoint] for a
// to the peer until a new endpoint is written by a later packet. // [Peer].
type PeerAwareEndpoint interface { type PeerAwareEndpoint interface {
GetPeerEndpoint(peerPublicKey [32]byte) Endpoint // FromPeer is called at least once per successfully Cryptokey Routing ID'd
// [ReceiveFunc] packets batch for a given node key. wireguard-go will
// always call it for the latest/tail packet in the batch, only ever
// suppressing calls for older packets.
FromPeer(peerPublicKey [32]byte)
} }
var ( var (

View file

@ -282,13 +282,14 @@ func (peer *Peer) Stop() {
func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) { func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) {
peer.endpoint.Lock() peer.endpoint.Lock()
defer peer.endpoint.Unlock() defer peer.endpoint.Unlock()
if ep, ok := endpoint.(conn.PeerAwareEndpoint); ok {
ep.FromPeer(peer.handshake.remoteStatic)
return
}
if peer.endpoint.disableRoaming { if peer.endpoint.disableRoaming {
return return
} }
peer.endpoint.clearSrcOnTx = false peer.endpoint.clearSrcOnTx = false
if ep, ok := endpoint.(conn.PeerAwareEndpoint); ok {
endpoint = ep.GetPeerEndpoint(peer.handshake.remoteStatic)
}
peer.endpoint.val = endpoint peer.endpoint.val = endpoint
} }