conn,device: enable cryptorouting via PeerAwareEndpoint

Introduce an optional extension point for Endpoint that enables a path
for WireGuard to inform an integration about the peer public key that is
associated with an Endpoint.

The API is expected to return either the same or a new Endpoint in
response to this function. A future version of this patch could
potentially remove the returned Endpoint, but would require larger
integrator changes downstream.

This adds a small per-packet cost that could later be removed with a
larger refactor of the wireguard-go interface and Tailscale magicsock
code, as well as introducing a generic bound for Endpoint in a device &
bind instance.

Updates tailscale/corp#20732
This commit is contained in:
James Tucker 2024-06-07 16:57:40 -07:00 committed by Brad Fitzpatrick
parent cfa45674af
commit 2f5d148bcf
3 changed files with 18 additions and 1 deletions

View file

@ -84,6 +84,20 @@ type Endpoint interface {
SrcIP() netip.Addr SrcIP() netip.Addr
} }
// PeerAwareEndpoint is an optional Endpoint specialization for
// integrations that want to know about the outcome of cryptorouting
// identification.
//
// If they receive a packet from a source they had not pre-identified,
// to learn the identification WireGuard can derive from the session
// or handshake.
//
// If GetPeerEndpoint returns nil, WireGuard will be unable to respond
// to the peer until a new endpoint is written by a later packet.
type PeerAwareEndpoint interface {
GetPeerEndpoint(peerPublicKey [32]byte) Endpoint
}
var ( var (
ErrBindAlreadyOpen = errors.New("bind is already open") ErrBindAlreadyOpen = errors.New("bind is already open")
ErrWrongEndpointType = errors.New("endpoint type does not correspond with bind type") ErrWrongEndpointType = errors.New("endpoint type does not correspond with bind type")

View file

@ -124,7 +124,7 @@ type Handshake struct {
localEphemeral NoisePrivateKey // ephemeral secret key localEphemeral NoisePrivateKey // ephemeral secret key
localIndex uint32 // used to clear hash-table localIndex uint32 // used to clear hash-table
remoteIndex uint32 // index for sending remoteIndex uint32 // index for sending
remoteStatic NoisePublicKey // long term key remoteStatic NoisePublicKey // long term key, never changes, can be accessed without mutex
remoteEphemeral NoisePublicKey // ephemeral public key remoteEphemeral NoisePublicKey // ephemeral public key
precomputedStaticStatic [NoisePublicKeySize]byte // precomputed shared secret precomputedStaticStatic [NoisePublicKeySize]byte // precomputed shared secret
lastTimestamp tai64n.Timestamp lastTimestamp tai64n.Timestamp

View file

@ -283,6 +283,9 @@ func (peer *Peer) SetEndpointFromPacket(endpoint conn.Endpoint) {
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
} }